ac739ff7555d8444d8ad321c42ab771c2da0e9ae
[openssl.git] / test / ct_test.c
1 /*
2  * Tests the Certificate Transparency public and internal APIs.
3  *
4  * Author:    Rob Percival (robpercival@google.com)
5  * Date:        2016-01-26
6  *
7  * ====================================================================
8  * Copyright (c) 2016 The OpenSSL Project.    All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *        notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *        notice, this list of conditions and the following disclaimer in
19  *        the documentation and/or other materials provided with the
20  *        distribution.
21  *
22  * 3. All advertising materials mentioning features or use of this
23  *        software must display the following acknowledgment:
24  *        "This product includes software developed by the OpenSSL Project
25  *        for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
26  *
27  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
28  *        endorse or promote products derived from this software without
29  *        prior written permission. For written permission, please contact
30  *        licensing@OpenSSL.org.
31  *
32  * 5. Products derived from this software may not be called "OpenSSL"
33  *        nor may "OpenSSL" appear in their names without prior written
34  *        permission of the OpenSSL Project.
35  *
36  * 6. Redistributions of any form whatsoever must retain the following
37  *        acknowledgment:
38  *        "This product includes software developed by the OpenSSL Project
39  *        for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT AS IS'' AND ANY
42  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44  * PURPOSE ARE DISCLAIMED.    IN NO EVENT SHALL THE OpenSSL PROJECT OR
45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52  * OF THE POSSIBILITY OF SUCH DAMAGE.
53  * ====================================================================
54  */
55
56 #include <ctype.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 #include <openssl/ct.h>
62 #include <openssl/err.h>
63 #include <openssl/ssl.h>
64 #include <openssl/x509.h>
65 #include <openssl/x509v3.h>
66 #include "testutil.h"
67
68 #if !defined(OPENSSL_NO_CT) && !defined(OPENSSL_NO_UNIT_TEST)
69
70 /* Used when declaring buffers to read text files into */
71 #define CT_TEST_MAX_FILE_SIZE 8096
72
73 typedef struct ct_test_fixture {
74     const char *test_case_name;
75     /* Set the following to test handling of SCTs in X509 certificates */
76     const char *certificate_file_path;
77     size_t expected_sct_count;
78     /* Set the following to test handling of SCTs in TLS format */
79     const uint8_t *tls_sct;
80     size_t tls_sct_len;
81     const SCT *sct;
82     /*
83      * A file to load the expected SCT text from.
84      * This text will be compared to the actual text output during the test.
85      * A maximum of |CT_TEST_MAX_FILE_SIZE| bytes will be read of this file.
86      */
87     const char *sct_text_file_path;
88
89 } CT_TEST_FIXTURE;
90
91 static CT_TEST_FIXTURE set_up(const char *const test_case_name)
92 {
93     CT_TEST_FIXTURE fixture;
94     int setup_ok = 1;
95
96     memset(&fixture, 0, sizeof(fixture));
97     fixture.test_case_name = test_case_name;
98
99     if (!setup_ok) {
100         exit(EXIT_FAILURE);
101     }
102     return fixture;
103 }
104
105 static void tear_down(CT_TEST_FIXTURE fixture)
106 {
107     ERR_print_errors_fp(stderr);
108 }
109
110 static X509 *load_pem_cert(const char *file)
111 {
112     BIO *cert_io = BIO_new_file(file, "r");
113     X509 *cert = NULL;
114
115     if (cert_io == NULL) goto end;
116
117     cert = PEM_read_bio_X509(cert_io, NULL, NULL, NULL);
118
119 end:
120     BIO_free(cert_io);
121     return cert;
122 }
123
124 static int read_text_file(const char *path, char *buffer, int buffer_length)
125 {
126     BIO *file = BIO_new_file(path, "r");
127     int result = -1;
128
129     if (file != NULL) {
130         result = BIO_read(file, buffer, buffer_length);
131         BIO_free(file);
132     }
133
134     return result;
135 }
136
137 static int compare_sct_printout(SCT *sct,
138     const char *expected_output)
139 {
140     BIO *text_buffer = NULL;
141     char *actual_output = NULL;
142     int result = 1;
143
144     text_buffer = BIO_new(BIO_s_mem());
145     if (text_buffer == NULL) {
146         fprintf(stderr, "Unable to allocate buffer\n");
147         goto end;
148     }
149
150     SCT_print(sct, text_buffer, 0);
151
152     /* Append null terminator because we're about to use the buffer contents
153     * as a string. */
154     if (BIO_write(text_buffer, "\0", 1) != 1) {
155         fprintf(stderr, "Failed to append null terminator to SCT text\n");
156         goto end;
157     }
158
159     BIO_get_mem_data(text_buffer, &actual_output);
160     result = strcmp(actual_output, expected_output);
161
162     if (result != 0) {
163         fprintf(stderr,
164             "Expected SCT printout:\n%s\nActual SCT printout:\n%s\n",
165             expected_output, actual_output);
166     }
167
168 end:
169     BIO_free(text_buffer);
170     return result;
171 }
172
173 static int compare_extension_printout(X509_EXTENSION *extension,
174                                       const char *expected_output)
175 {
176     BIO *text_buffer = NULL;
177     char *actual_output = NULL;
178     int result = 1;
179
180     text_buffer = BIO_new(BIO_s_mem());
181     if (text_buffer == NULL) {
182         fprintf(stderr, "Unable to allocate buffer\n");
183         goto end;
184     }
185
186     if (!X509V3_EXT_print(text_buffer, extension, X509V3_EXT_DEFAULT, 0)) {
187         fprintf(stderr, "Failed to print extension\n");
188         goto end;
189     }
190
191     /* Append null terminator because we're about to use the buffer contents
192      * as a string. */
193     if (BIO_write(text_buffer, "\0", 1) != 1) {
194         fprintf(stderr, "Failed to append null terminator to extension text\n");
195         goto end;
196     }
197
198     BIO_get_mem_data(text_buffer, &actual_output);
199     result = strcmp(actual_output, expected_output);
200
201     if (result != 0) {
202         fprintf(stderr,
203                 "Expected SCT printout:\n%s\nActual SCT printout:\n%s\n",
204                 expected_output, actual_output);
205     }
206
207 end:
208     BIO_free(text_buffer);
209     return result;
210 }
211
212 static int execute_cert_test(CT_TEST_FIXTURE fixture)
213 {
214     int result = 0;
215     X509 *cert = NULL;
216     SCT *sct = NULL;
217     char expected_sct_text[CT_TEST_MAX_FILE_SIZE];
218     int sct_text_len = 0;
219
220     if (fixture.sct_text_file_path != NULL) {
221         sct_text_len = read_text_file(
222             fixture.sct_text_file_path,
223             expected_sct_text,
224             CT_TEST_MAX_FILE_SIZE - 1);
225
226         if (sct_text_len < 0) {
227             result = 1;
228             fprintf(stderr, "Test data file not found: %s\n",
229                 fixture.sct_text_file_path);
230             goto end;
231         }
232
233         expected_sct_text[sct_text_len] = '\0';
234     }
235
236     if (fixture.certificate_file_path != NULL) {
237         int sct_extension_index;
238         X509_EXTENSION *sct_extension = NULL;
239         cert = load_pem_cert(fixture.certificate_file_path);
240
241         if (cert == NULL) {
242             result = 1;
243             fprintf(stderr, "Unable to load certificate: %s\n",
244                 fixture.certificate_file_path);
245             goto end;
246         }
247
248         sct_extension_index = X509_get_ext_by_NID(cert, NID_ct_precert_scts, -1);
249         sct_extension = X509_get_ext(cert, sct_extension_index);
250         if (fixture.expected_sct_count > 0) {
251             if (sct_extension == NULL) {
252                 result = 1;
253                 fprintf(stderr, "SCT extension not found in: %s\n",
254                     fixture.certificate_file_path);
255                 goto end;
256             }
257
258             if (fixture.sct_text_file_path) {
259                 result = compare_extension_printout(sct_extension,
260                                                     expected_sct_text);
261                 if (result != 0)
262                     goto end;
263             }
264         } else if (sct_extension != NULL) {
265             result = 1;
266             fprintf(stderr, "Expected no SCTs, but found SCT extension in: %s\n",
267                 fixture.certificate_file_path);
268             goto end;
269         }
270     }
271
272     if (fixture.tls_sct != NULL) {
273         const unsigned char *p = fixture.tls_sct;
274         unsigned char *tls_sct;
275         size_t tls_sct_len;
276         if (o2i_SCT(&sct, &p, fixture.tls_sct_len) == NULL) {
277             result = 1;
278             fprintf(stderr, "Failed to decode SCT from TLS format\n");
279             goto end;
280         }
281
282         if (fixture.sct_text_file_path) {
283             result = compare_sct_printout(sct, expected_sct_text);
284             if (result != 0)
285                 goto end;
286         }
287
288         tls_sct_len = i2o_SCT(sct, &tls_sct);
289         if (tls_sct_len != fixture.tls_sct_len ||
290             memcmp(fixture.tls_sct, tls_sct, tls_sct_len) != 0) {
291             result = 1;
292             fprintf(stderr, "Failed to encode SCT into TLS format correctly\n");
293             goto end;
294         }
295     }
296
297 end:
298     X509_free(cert);
299     SCT_free(sct);
300     return result;
301 }
302
303 #define SETUP_CT_TEST_FIXTURE() SETUP_TEST_FIXTURE(CT_TEST_FIXTURE, set_up)
304 #define EXECUTE_CT_TEST() EXECUTE_TEST(execute_cert_test, tear_down)
305
306 static int test_no_scts_in_certificate()
307 {
308     SETUP_CT_TEST_FIXTURE();
309     fixture.certificate_file_path = "certs/leaf.pem";
310     fixture.expected_sct_count = 0;
311     EXECUTE_CT_TEST();
312 }
313
314 static int test_one_sct_in_certificate()
315 {
316     SETUP_CT_TEST_FIXTURE();
317     fixture.certificate_file_path = "certs/embeddedSCTs1.pem";
318     fixture.expected_sct_count = 1;
319     fixture.sct_text_file_path = "certs/embeddedSCTs1.sct";
320     EXECUTE_CT_TEST();
321 }
322
323 static int test_multiple_scts_in_certificate()
324 {
325     SETUP_CT_TEST_FIXTURE();
326     fixture.certificate_file_path = "certs/embeddedSCTs3.pem";
327     fixture.expected_sct_count = 3;
328     fixture.sct_text_file_path = "certs/embeddedSCTs3.sct";
329     EXECUTE_CT_TEST();
330 }
331
332 static int test_decode_tls_sct()
333 {
334     SETUP_CT_TEST_FIXTURE();
335     fixture.tls_sct = (unsigned char *)
336         "\x00" /* version */
337         /* log ID */
338         "\xDF\x1C\x2E\xC1\x15\x00\x94\x52\x47\xA9\x61\x68\x32\x5D\xDC\x5C\x79"
339         "\x59\xE8\xF7\xC6\xD3\x88\xFC\x00\x2E\x0B\xBD\x3F\x74\xD7\x64"
340         "\x00\x00\x01\x3D\xDB\x27\xDF\x93" /* timestamp */
341         "\x00\x00" /* extensions length */
342         "" /* extensions */
343         "\x04\x03" /* hash and signature algorithms */
344         "\x00\x47" /* signature length */
345         "\x30\x45\x02\x20\x48\x2F\x67\x51\xAF\x35\xDB\xA6\x54\x36\xBE\x1F\xD6"
346         "\x64\x0F\x3D\xBF\x9A\x41\x42\x94\x95\x92\x45\x30\x28\x8F\xA3\xE5\xE2"
347         "\x3E\x06\x02\x21\x00\xE4\xED\xC0\xDB\x3A\xC5\x72\xB1\xE2\xF5\xE8\xAB"
348         "\x6A\x68\x06\x53\x98\x7D\xCF\x41\x02\x7D\xFE\xFF\xA1\x05\x51\x9D\x89"
349         "\xED\xBF\x08"; /* signature */
350     fixture.tls_sct_len = 118;
351     fixture.sct_text_file_path = "ct/tls1.sct";
352     EXECUTE_CT_TEST();
353 }
354
355 static int test_encode_tls_sct()
356 {
357     SETUP_CT_TEST_FIXTURE();
358
359     SCT *sct = SCT_new();
360     SCT_set_version(sct, 0);
361     SCT_set1_log_id(sct, (unsigned char *)
362         "\xDF\x1C\x2E\xC1\x15\x00\x94\x52\x47\xA9\x61\x68\x32\x5D\xDC\x5C\x79"
363         "\x59\xE8\xF7\xC6\xD3\x88\xFC\x00\x2E\x0B\xBD\x3F\x74\xD7\x64", 32);
364     SCT_set_timestamp(sct, 1);
365     SCT_set1_extensions(sct, (unsigned char *)"", 0);
366     SCT_set_signature_nid(sct, NID_ecdsa_with_SHA256);
367     SCT_set1_signature(sct, (unsigned char *)
368         "\x45\x02\x20\x48\x2F\x67\x51\xAF\x35\xDB\xA6\x54\x36\xBE"
369         "\x1F\xD6\x64\x0F\x3D\xBF\x9A\x41\x42\x94\x95\x92\x45\x30\x28\x8F\xA3"
370         "\xE5\xE2\x3E\x06\x02\x21\x00\xE4\xED\xC0\xDB\x3A\xC5\x72\xB1\xE2\xF5"
371         "\xE8\xAB\x6A\x68\x06\x53\x98\x7D\xCF\x41\x02\x7D\xFE\xFF\xA1\x05\x51"
372         "\x9D\x89\xED\xBF\x08", 71);
373     fixture.sct = sct;
374     fixture.sct_text_file_path = "ct/tls1.sct";
375     EXECUTE_CT_TEST();
376
377     SCT_free(sct);
378 }
379
380 int main(int argc, char *argv[])
381 {
382     int result = 0;
383
384     ADD_TEST(test_no_scts_in_certificate);
385     ADD_TEST(test_one_sct_in_certificate);
386     ADD_TEST(test_multiple_scts_in_certificate);
387     ADD_TEST(test_decode_tls_sct);
388     ADD_TEST(test_encode_tls_sct);
389
390     result = run_tests(argv[0]);
391     ERR_print_errors_fp(stderr);
392
393     return result;
394 }
395
396 #else /* OPENSSL_NO_CT */
397
398 int main(int argc, char* argv[])
399 {
400     return EXIT_SUCCESS;
401 }
402
403 #endif /* OPENSSL_NO_CT */