1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.conscrypt.ct;
18
19import static org.conscrypt.TestUtils.openTestFile;
20import static org.conscrypt.TestUtils.readTestFile;
21
22import java.security.PublicKey;
23import java.util.Arrays;
24import junit.framework.TestCase;
25import org.conscrypt.InternalUtil;
26import org.conscrypt.OpenSSLX509Certificate;
27
28public class CTVerifierTest extends TestCase {
29    private OpenSSLX509Certificate ca;
30    private OpenSSLX509Certificate cert;
31    private OpenSSLX509Certificate certEmbedded;
32    private CTVerifier ctVerifier;
33
34    @Override
35    public void setUp() throws Exception {
36        super.setUp();
37        ca = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("ca-cert.pem"));
38        cert = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert.pem"));
39        certEmbedded = OpenSSLX509Certificate.fromX509PemInputStream(
40                openTestFile("cert-ct-embedded.pem"));
41
42        PublicKey key = InternalUtil.readPublicKeyPem(openTestFile("ct-server-key-public.pem"));
43
44        final CTLogInfo log = new CTLogInfo(key, "Test Log", "foo");
45        CTLogStore store = new CTLogStore() {
46            @Override
47            public CTLogInfo getKnownLog(byte[] logId) {
48                if (Arrays.equals(logId, log.getID())) {
49                    return log;
50                } else {
51                    return null;
52                }
53            }
54        };
55
56        ctVerifier = new CTVerifier(store);
57    }
58
59    public void test_verifySignedCertificateTimestamps_withOCSPResponse() throws Exception {
60        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
61
62        byte[] ocspResponse = readTestFile("ocsp-response.der");
63        CTVerificationResult result =
64            ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
65        assertEquals(1, result.getValidSCTs().size());
66        assertEquals(0, result.getInvalidSCTs().size());
67    }
68
69    public void test_verifySignedCertificateTimestamps_withTLSExtension() throws Exception {
70        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
71
72        byte[] tlsExtension = readTestFile("ct-signed-timestamp-list");
73        CTVerificationResult result =
74            ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
75        assertEquals(1, result.getValidSCTs().size());
76        assertEquals(0, result.getInvalidSCTs().size());
77    }
78
79    public void test_verifySignedCertificateTimestamps_withEmbeddedExtension() throws Exception {
80        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { certEmbedded, ca };
81
82        CTVerificationResult result =
83            ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
84        assertEquals(1, result.getValidSCTs().size());
85        assertEquals(0, result.getInvalidSCTs().size());
86    }
87
88    public void test_verifySignedCertificateTimestamps_withoutTimestamp() throws Exception {
89        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
90
91        CTVerificationResult result =
92            ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
93        assertEquals(0, result.getValidSCTs().size());
94        assertEquals(0, result.getInvalidSCTs().size());
95    }
96
97    public void test_verifySignedCertificateTimestamps_withInvalidSignature() throws Exception {
98        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
99
100        byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-invalid");
101
102        CTVerificationResult result =
103            ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
104        assertEquals(0, result.getValidSCTs().size());
105        assertEquals(1, result.getInvalidSCTs().size());
106        assertEquals(VerifiedSCT.Status.INVALID_SIGNATURE,
107                     result.getInvalidSCTs().get(0).status);
108    }
109
110    public void test_verifySignedCertificateTimestamps_withUnknownLog() throws Exception {
111        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
112
113        byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-unknown");
114
115        CTVerificationResult result =
116            ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
117        assertEquals(0, result.getValidSCTs().size());
118        assertEquals(1, result.getInvalidSCTs().size());
119        assertEquals(VerifiedSCT.Status.UNKNOWN_LOG,
120                     result.getInvalidSCTs().get(0).status);
121    }
122
123    public void test_verifySignedCertificateTimestamps_withInvalidEncoding() throws Exception {
124        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
125
126        // Just some garbage data which will fail to deserialize
127        byte[] tlsExtension = new byte[] { 1, 2, 3, 4 };
128
129        CTVerificationResult result =
130            ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
131        assertEquals(0, result.getValidSCTs().size());
132        assertEquals(0, result.getInvalidSCTs().size());
133    }
134
135    public void test_verifySignedCertificateTimestamps_withInvalidOCSPResponse() throws Exception {
136        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
137
138        // Just some garbage data which will fail to deserialize
139        byte[] ocspResponse = new byte[] { 1, 2, 3, 4 };
140
141        CTVerificationResult result =
142            ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
143        assertEquals(0, result.getValidSCTs().size());
144        assertEquals(0, result.getInvalidSCTs().size());
145    }
146
147    public void test_verifySignedCertificateTimestamps_withMultipleTimestamps() throws Exception {
148        OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
149
150        byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-invalid");
151        byte[] ocspResponse = readTestFile("ocsp-response.der");
152
153        CTVerificationResult result =
154            ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, ocspResponse);
155        assertEquals(1, result.getValidSCTs().size());
156        assertEquals(1, result.getInvalidSCTs().size());
157        assertEquals(SignedCertificateTimestamp.Origin.OCSP_RESPONSE,
158                     result.getValidSCTs().get(0).sct.getOrigin());
159        assertEquals(SignedCertificateTimestamp.Origin.TLS_EXTENSION,
160                     result.getInvalidSCTs().get(0).sct.getOrigin());
161    }
162}
163
164