/*- * SSLsplit - transparent SSL/TLS interception * https://www.roe.ch/SSLsplit * * Copyright (c) 2009-2019, Daniel Roethlisberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "base64.h" #include "ssl.h" #include #include #include #include #ifdef __APPLE__ #define DLSUFFIX "dylib" #else #define DLSUFFIX "so" #endif #define TESTKEY "pki/server.key" #define TESTCERT "pki/server.crt" #define TESTCERT2 "pki/rsa.crt" #define ENGINE "engine/dummy-engine."DLSUFFIX static void ssl_setup(void) { if (ssl_init() == -1) exit(EXIT_FAILURE); } static void ssl_teardown(void) { ssl_fini(); } static char wildcard1[] = "*.example.org"; static char wildcard2[] = "www.*.example.org"; static char wildcard3[] = "*.*.org"; static char wildcard4[] = "www*.example.org"; static char wildcard5[] = "*"; static char wildcard6[] = "*.xn--r-1ga.ch"; static char wildcard7[] = "xn--r-1ga*.xn--r-1ga.ch"; static char wildcard8[] = "xn--r-1ga.*.xn--r-1ga.ch"; static char name1[] = "www.example.org"; static char name2[] = "www.example.com"; static char name3[] = "example.org"; static char name4[] = "www.example.org.co.uk"; static char name5[] = "test.www.example.org"; static char name6[] = "www.test.example.org"; static char name7[] = "wwwtest.example.org"; static char name8[] = "ch"; static char name9[] = "www.xn--r-1ga.ch"; static char name10[] = "xn--r-1ga.xn--r-1ga.ch"; static char name11[] = ""; START_TEST(ssl_wildcardify_01) { char *wc = ssl_wildcardify(name1); fail_unless(!strcmp(wc, wildcard1), "mismatch for 'www.example.org'"); free(wc); } END_TEST START_TEST(ssl_wildcardify_02) { char *wc = ssl_wildcardify(name8); fail_unless(!strcmp(wc, wildcard5), "mismatch for 'ch'"); free(wc); } END_TEST START_TEST(ssl_wildcardify_03) { char *wc = ssl_wildcardify(name11); fail_unless(!strcmp(wc, wildcard5), "mismatch for ''"); free(wc); } END_TEST START_TEST(ssl_dnsname_match_01) { fail_unless( ssl_dnsname_match(name1, sizeof(name1) - 1, name1, sizeof(name1) - 1), "Hostname does not match itself"); } END_TEST START_TEST(ssl_dnsname_match_02) { fail_unless( !ssl_dnsname_match(name1, sizeof(name1) - 1, name2, sizeof(name2) - 1), "Hostname matches hostname with different TLD"); } END_TEST START_TEST(ssl_dnsname_match_03) { fail_unless( ssl_dnsname_match(wildcard1, sizeof(wildcard1) - 1, name1, sizeof(name1) - 1), "Regular wildcard does not match"); } END_TEST START_TEST(ssl_dnsname_match_04) { fail_unless( !ssl_dnsname_match(wildcard1, sizeof(wildcard1) - 1, name2, sizeof(name2) - 1), "Regular wildcard matches other TLD"); } END_TEST START_TEST(ssl_dnsname_match_05) { fail_unless( !ssl_dnsname_match(wildcard1, sizeof(wildcard1) - 1, name3, sizeof(name3) - 1), "Regular wildcard matches upper level domain"); } END_TEST START_TEST(ssl_dnsname_match_06) { fail_unless( !ssl_dnsname_match(wildcard1, sizeof(wildcard1) - 1, name4, sizeof(name4) - 1), "Regular wildcard matches despite added suffix"); } END_TEST START_TEST(ssl_dnsname_match_07) { fail_unless( !ssl_dnsname_match(wildcard1, sizeof(wildcard1) - 1, name5, sizeof(name5) - 1), "Regular wildcard matches two elements"); } END_TEST START_TEST(ssl_dnsname_match_08) { fail_unless( !ssl_dnsname_match(wildcard2, sizeof(wildcard2) - 1, name6, sizeof(name6) - 1), "Wildcard matches in non-leftmost element"); } END_TEST START_TEST(ssl_dnsname_match_09) { fail_unless( !ssl_dnsname_match(wildcard3, sizeof(wildcard3) - 1, name5, sizeof(name5) - 1), "Multiple wildcard matches"); } END_TEST START_TEST(ssl_dnsname_match_10) { fail_unless( !ssl_dnsname_match(wildcard4, sizeof(wildcard4) - 1, name7, sizeof(name7) - 1), "Partial label wildcard matches"); } END_TEST START_TEST(ssl_dnsname_match_11) { fail_unless( !ssl_dnsname_match(wildcard5, sizeof(wildcard5) - 1, name1, sizeof(name1) - 1), "Global wildcard * matches fqdn"); } END_TEST START_TEST(ssl_dnsname_match_12) { fail_unless( ssl_dnsname_match(wildcard5, sizeof(wildcard5) - 1, name8, sizeof(name8) - 1), "Global wildcard * does not match TLD"); } END_TEST START_TEST(ssl_dnsname_match_13) { fail_unless( ssl_dnsname_match(wildcard6, sizeof(wildcard6) - 1, name9, sizeof(name9) - 1), "IDN wildcard does not match"); } END_TEST START_TEST(ssl_dnsname_match_14) { fail_unless( ssl_dnsname_match(wildcard6, sizeof(wildcard6) - 1, name10, sizeof(name10) - 1), "IDN wildcard does not match IDN element"); } END_TEST START_TEST(ssl_dnsname_match_15) { fail_unless( !ssl_dnsname_match(wildcard7, sizeof(wildcard7) - 1, name10, sizeof(name10) - 1), "Illegal IDN wildcard matches"); } END_TEST START_TEST(ssl_dnsname_match_16) { fail_unless( !ssl_dnsname_match(wildcard8, sizeof(wildcard8) - 1, name10, sizeof(name10) - 1), "Illegal IDN wildcard matches IDN element"); } END_TEST static unsigned char clienthello00[] = "\x80\x2b\x01\x00\x02\x00\x12\x00\x00\x00\x10\x07\x00\xc0\x03\x00" "\x80\x01\x00\x80\x06\x00\x40\x04\x00\x80\x02\x00\x80\xe0\xc3\x4a" "\xc6\xa4\x89\x23\x21\xb1\xbb\x51\xc7\x9c\x06\xa5\xff"; /* SSL 2.0 */ static unsigned char clienthello01[] = "\x80\x67\x01\x03\x00\x00\x4e\x00\x00\x00\x10\x01\x00\x80\x03\x00" "\x80\x07\x00\xc0\x06\x00\x40\x02\x00\x80\x04\x00\x80\x00\x00\x39" "\x00\x00\x38\x00\x00\x35\x00\x00\x33\x00\x00\x32\x00\x00\x04\x00" "\x00\x05\x00\x00\x2f\x00\x00\x16\x00\x00\x13\x00\xfe\xff\x00\x00" "\x0a\x00\x00\x15\x00\x00\x12\x00\xfe\xfe\x00\x00\x09\x00\x00\x64" "\x00\x00\x62\x00\x00\x03\x00\x00\x06\xa8\xb8\x93\xbb\x90\xe9\x2a" "\xa2\x4d\x6d\xcc\x1c\xe7\x2a\x80\x21"; /* SSL 3.0 in SSL 2.0 record */ static unsigned char clienthello02[] = "\x16\x03\x00\x00\x73\x01\x00\x00\x6f\x03\x00\x00\x34\x01\x1e\x67" "\x3a\xfa\xce\xd9\x51\xba\xe4\xfc\x64\x95\x03\x82\x63\x0f\xe3\x39" "\x6b\xc7\xbd\x2b\xe5\x51\x37\x23\x48\x5b\xfb\x20\xa3\xca\xad\x46" "\x95\x5d\x64\xbb\x33\xec\xb5\x12\x91\x21\xa3\x50\xd2\xc0\xc5\xf6" "\x67\xc3\xcc\x9e\xc0\x4a\x71\x1b\x92\xdc\x58\x55\x00\x28\x00\x39" "\x00\x38\x00\x35\x00\x33\x00\x32\x00\x04\x00\x05\x00\x2f\x00\x16" "\x00\x13\xfe\xff\x00\x0a\x00\x15\x00\x12\xfe\xfe\x00\x09\x00\x64" "\x00\x62\x00\x03\x00\x06\x01\x00"; /* SSL 3.0, no TLS extensions */ static unsigned char clienthello03[] = "\x16\x03\x01\x00\x9b\x01\x00\x00\x97\x03\x01\x4b\x99\x46\xac\x38" "\x08\xbb\xa7\x1c\x9b\xea\x79\xc5\xd6\x70\x3d\xed\x20\x80\x60\xb4" "\x7e\xb5\x07\x13\xcf\x9a\x1c\xec\x6f\x64\xe5\x00\x00\x46\xc0\x0a" "\xc0\x09\xc0\x07\xc0\x08\xc0\x13\xc0\x14\xc0\x11\xc0\x12\xc0\x04" "\xc0\x05\xc0\x02\xc0\x03\xc0\x0e\xc0\x0f\xc0\x0c\xc0\x0d\x00\x2f" "\x00\x05\x00\x04\x00\x35\x00\x0a\x00\x09\x00\x03\x00\x08\x00\x06" "\x00\x32\x00\x33\x00\x38\x00\x39\x00\x16\x00\x15\x00\x14\x00\x13" "\x00\x12\x00\x11\x01\x00\x00\x28\x00\x00\x00\x12\x00\x10\x00\x00" "\x0d\x31\x39\x32\x2e\x31\x36\x38\x2e\x31\x30\x30\x2e\x34\x00\x0a" "\x00\x08\x00\x06\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x02\x01\x00"; /* TLS 1.0, SNI extension with hostname "192.168.100.4"; * Note: IP addresses are not legal values */ static unsigned char clienthello04[] = "\x16\x03\x01\x00\x6c\x01\x00\x00\x68\x03\x01\x4a\x9d\x49\x75\xb2" "\x7e\xf9\xbc\xc3\x76\xac\x19\x78\xfb\x6a\xee\x50\x55\x5e\x35\x4c" "\xca\xf2\x21\x15\xf3\x8a\x2a\xfc\xb5\x35\xed\x00\x00\x28\x00\x39" "\x00\x38\x00\x35\x00\x16\x00\x13\x00\x0a\x00\x33\x00\x32\x00\x2f" "\x00\x07\x00\x05\x00\x04\x00\x15\x00\x12\x00\x09\x00\x14\x00\x11" "\x00\x08\x00\x06\x00\x03\x01\x00\x00\x17\x00\x00\x00\x0f\x00\x0d" "\x00\x00\x0a\x6b\x61\x6d\x65\x73\x68\x2e\x63\x6f\x6d\x00\x23\x00" "\x00"; /* TLS 1.0, SNI extension with hostname "kamesh.com" */ static unsigned char clienthello05[] = "\x16\x03\x03\x01\x7d\x01\x00\x01\x79\x03\x03\x4f\x7f\x27\xd0\x76" "\x5f\xc1\x3b\xba\x73\xd5\x07\x8b\xd9\x79\xf9\x51\xd4\xce\x7d\x9a" "\xdb\xdf\xf8\x4e\x95\x86\x38\x61\xdd\x84\x2a\x00\x00\xca\xc0\x30" "\xc0\x2c\xc0\x28\xc0\x24\xc0\x14\xc0\x0a\xc0\x22\xc0\x21\x00\xa3" "\x00\x9f\x00\x6b\x00\x6a\x00\x39\x00\x38\x00\x88\x00\x87\xc0\x19" "\xc0\x20\x00\xa7\x00\x6d\x00\x3a\x00\x89\xc0\x32\xc0\x2e\xc0\x2a" "\xc0\x26\xc0\x0f\xc0\x05\x00\x9d\x00\x3d\x00\x35\x00\x84\xc0\x12" "\xc0\x08\xc0\x1c\xc0\x1b\x00\x16\x00\x13\xc0\x17\xc0\x1a\x00\x1b" "\xc0\x0d\xc0\x03\x00\x0a\xc0\x2f\xc0\x2b\xc0\x27\xc0\x23\xc0\x13" "\xc0\x09\xc0\x1f\xc0\x1e\x00\xa2\x00\x9e\x00\x67\x00\x40\x00\x33" "\x00\x32\x00\x9a\x00\x99\x00\x45\x00\x44\xc0\x18\xc0\x1d\x00\xa6" "\x00\x6c\x00\x34\x00\x9b\x00\x46\xc0\x31\xc0\x2d\xc0\x29\xc0\x25" "\xc0\x0e\xc0\x04\x00\x9c\x00\x3c\x00\x2f\x00\x96\x00\x41\x00\x07" "\xc0\x11\xc0\x07\xc0\x16\x00\x18\xc0\x0c\xc0\x02\x00\x05\x00\x04" "\x00\x15\x00\x12\x00\x1a\x00\x09\x00\x14\x00\x11\x00\x19\x00\x08" "\x00\x06\x00\x17\x00\x03\x00\xff\x02\x01\x00\x00\x85\x00\x00\x00" "\x12\x00\x10\x00\x00\x0d\x64\x61\x6e\x69\x65\x6c\x2e\x72\x6f\x65" "\x2e\x63\x68\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x34\x00" "\x32\x00\x0e\x00\x0d\x00\x19\x00\x0b\x00\x0c\x00\x18\x00\x09\x00" "\x0a\x00\x16\x00\x17\x00\x08\x00\x06\x00\x07\x00\x14\x00\x15\x00" "\x04\x00\x05\x00\x12\x00\x13\x00\x01\x00\x02\x00\x03\x00\x0f\x00" "\x10\x00\x11\x00\x23\x00\x00\x00\x0d\x00\x22\x00\x20\x06\x01\x06" "\x02\x06\x03\x05\x01\x05\x02\x05\x03\x04\x01\x04\x02\x04\x03\x03" "\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x03\x01\x01\x00\x0f\x00" "\x01\x01"; /* TLS 1.2, SNI extension with hostname "daniel.roe.ch" */ static unsigned char clienthello06[] = "I will start TLS now: " "\x16\x03\x03\x01\x7d\x01\x00\x01\x79\x03\x03\x4f\x7f\x27\xd0\x76" "\x5f\xc1\x3b\xba\x73\xd5\x07\x8b\xd9\x79\xf9\x51\xd4\xce\x7d\x9a" "\xdb\xdf\xf8\x4e\x95\x86\x38\x61\xdd\x84\x2a\x00\x00\xca\xc0\x30" "\xc0\x2c\xc0\x28\xc0\x24\xc0\x14\xc0\x0a\xc0\x22\xc0\x21\x00\xa3" "\x00\x9f\x00\x6b\x00\x6a\x00\x39\x00\x38\x00\x88\x00\x87\xc0\x19" "\xc0\x20\x00\xa7\x00\x6d\x00\x3a\x00\x89\xc0\x32\xc0\x2e\xc0\x2a" "\xc0\x26\xc0\x0f\xc0\x05\x00\x9d\x00\x3d\x00\x35\x00\x84\xc0\x12" "\xc0\x08\xc0\x1c\xc0\x1b\x00\x16\x00\x13\xc0\x17\xc0\x1a\x00\x1b" "\xc0\x0d\xc0\x03\x00\x0a\xc0\x2f\xc0\x2b\xc0\x27\xc0\x23\xc0\x13" "\xc0\x09\xc0\x1f\xc0\x1e\x00\xa2\x00\x9e\x00\x67\x00\x40\x00\x33" "\x00\x32\x00\x9a\x00\x99\x00\x45\x00\x44\xc0\x18\xc0\x1d\x00\xa6" "\x00\x6c\x00\x34\x00\x9b\x00\x46\xc0\x31\xc0\x2d\xc0\x29\xc0\x25" "\xc0\x0e\xc0\x04\x00\x9c\x00\x3c\x00\x2f\x00\x96\x00\x41\x00\x07" "\xc0\x11\xc0\x07\xc0\x16\x00\x18\xc0\x0c\xc0\x02\x00\x05\x00\x04" "\x00\x15\x00\x12\x00\x1a\x00\x09\x00\x14\x00\x11\x00\x19\x00\x08" "\x00\x06\x00\x17\x00\x03\x00\xff\x02\x01\x00\x00\x85\x00\x00\x00" "\x12\x00\x10\x00\x00\x0d\x64\x61\x6e\x69\x65\x6c\x2e\x72\x6f\x65" "\x2e\x63\x68\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x34\x00" "\x32\x00\x0e\x00\x0d\x00\x19\x00\x0b\x00\x0c\x00\x18\x00\x09\x00" "\x0a\x00\x16\x00\x17\x00\x08\x00\x06\x00\x07\x00\x14\x00\x15\x00" "\x04\x00\x05\x00\x12\x00\x13\x00\x01\x00\x02\x00\x03\x00\x0f\x00" "\x10\x00\x11\x00\x23\x00\x00\x00\x0d\x00\x22\x00\x20\x06\x01\x06" "\x02\x06\x03\x05\x01\x05\x02\x05\x03\x04\x01\x04\x02\x04\x03\x03" "\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x03\x01\x01\x00\x0f\x00" "\x01\x01"; /* TLS 1.2, SNI extension with hostname "daniel.roe.ch" */ START_TEST(ssl_tls_clienthello_parse_00) { int rv; const unsigned char *ch = NULL; char *sni = (void *)0xDEADBEEF; rv = ssl_tls_clienthello_parse(clienthello00, sizeof(clienthello00) - 1, 0, &ch, &sni); #ifdef HAVE_SSLV2 fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni == NULL, "sni not NULL"); #else /* !HAVE_SSLV2 */ fail_unless(rv == 1, "rv not 1"); fail_unless(ch == NULL, "ch not NULL"); fail_unless(sni == (void*)0xDEADBEEF, "sni modified"); #endif /* !HAVE_SSLV2 */ } END_TEST START_TEST(ssl_tls_clienthello_parse_01) { int rv; const unsigned char *ch = NULL; char *sni = (void *)0xDEADBEEF; rv = ssl_tls_clienthello_parse(clienthello01, sizeof(clienthello01) - 1, 0, &ch, &sni); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni == NULL, "sni not NULL"); } END_TEST START_TEST(ssl_tls_clienthello_parse_02) { int rv; const unsigned char *ch = NULL; char *sni = (void *)0xDEADBEEF; rv = ssl_tls_clienthello_parse(clienthello02, sizeof(clienthello02) - 1, 0, &ch, &sni); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni == NULL, "sni not NULL"); } END_TEST START_TEST(ssl_tls_clienthello_parse_03) { int rv; const unsigned char *ch = NULL; char *sni = NULL; rv = ssl_tls_clienthello_parse(clienthello03, sizeof(clienthello03) - 1, 0, &ch, &sni); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni && !strcmp(sni, "192.168.100.4"), "sni not '192.168.100.4' but should be"); } END_TEST START_TEST(ssl_tls_clienthello_parse_04) { int rv; const unsigned char *ch = NULL; char *sni = NULL; rv = ssl_tls_clienthello_parse(clienthello04, sizeof(clienthello04) - 1, 0, &ch, &sni); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni && !strcmp(sni, "kamesh.com"), "sni not 'kamesh.com' but should be"); } END_TEST START_TEST(ssl_tls_clienthello_parse_05) { for (size_t i = 0; i < sizeof(clienthello04) - 1; i++) { int rv; const unsigned char *ch = NULL; char *sni = (void*)0xDEADBEEF; ssize_t sz; sz = (ssize_t)i; rv = ssl_tls_clienthello_parse(clienthello04, sz, 0, &ch, &sni); fail_unless(rv == 1, "rv not 1"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni == (void*)0xDEADBEEF, "sni modified"); } } END_TEST START_TEST(ssl_tls_clienthello_parse_06) { int rv; const unsigned char *ch = NULL; char *sni = NULL; rv = ssl_tls_clienthello_parse(clienthello05, sizeof(clienthello05) - 1, 0, &ch, &sni); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni && !strcmp(sni, "daniel.roe.ch"), "sni not 'daniel.roe.ch' but should be"); } END_TEST START_TEST(ssl_tls_clienthello_parse_07) { for (size_t i = 0; i < sizeof(clienthello05) - 1; i++) { int rv; const unsigned char *ch = NULL; char *sni = (void*)0xDEADBEEF; ssize_t sz; sz = (ssize_t)i; rv = ssl_tls_clienthello_parse(clienthello05, sz, 0, &ch, &sni); fail_unless(rv == 1, "rv not 1"); fail_unless(ch != NULL, "ch is NULL"); fail_unless(sni == (void*)0xDEADBEEF, "sni modified"); } } END_TEST START_TEST(ssl_tls_clienthello_parse_08) { int rv; const unsigned char *ch = (void *)0xDEADBEEF; char *sni = (void *)0xDEADBEEF; rv = ssl_tls_clienthello_parse(clienthello06, sizeof(clienthello06) - 1, 0, &ch, &sni); fail_unless(rv == 1, "rv not 1"); fail_unless(ch == NULL, "ch not NULL"); fail_unless(sni == (void*)0xDEADBEEF, "sni modified"); } END_TEST START_TEST(ssl_tls_clienthello_parse_09) { int rv; const unsigned char *ch = NULL; char *sni = NULL; rv = ssl_tls_clienthello_parse(clienthello06, sizeof(clienthello06) - 1, 1, &ch, &sni); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless((ch - clienthello06) != 21, "ch does not point to start"); fail_unless(sni && !strcmp(sni, "daniel.roe.ch"), "sni not 'daniel.roe.ch' but should be"); } END_TEST START_TEST(ssl_tls_clienthello_parse_10) { int rv; const unsigned char *ch = NULL; rv = ssl_tls_clienthello_parse(clienthello06, sizeof(clienthello06) - 1, 1, &ch, NULL); fail_unless(rv == 0, "rv not 0"); fail_unless(ch != NULL, "ch is NULL"); fail_unless((ch - clienthello06) != 21, "ch does not point to start"); } END_TEST START_TEST(ssl_key_identifier_sha1_01) { X509 *c; EVP_PKEY *k; unsigned char keyid[SSL_KEY_IDSZ]; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); k = ssl_key_load(TESTKEY); fail_unless(!!k, "loading key failed"); fail_unless(ssl_key_identifier_sha1(k, keyid) == 0, "ssl_key_identifier_sha1() failed"); int loc = X509_get_ext_by_NID(c, NID_subject_key_identifier, -1); X509_EXTENSION *ext = X509_get_ext(c, loc); fail_unless(!!ext, "loading ext failed"); ASN1_STRING *value = X509_EXTENSION_get_data(ext); fail_unless(ASN1_STRING_length(value) - 2 == SSL_KEY_IDSZ, "extension length mismatch"); fail_unless(!memcmp(ASN1_STRING_get0_data(value) + 2, keyid, SSL_KEY_IDSZ), "key id mismatch"); EVP_PKEY_free(k); X509_free(c); } END_TEST START_TEST(ssl_x509_names_01) { X509 *c; char **names, **p; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); names = ssl_x509_names(c); fail_unless(!!names, "parsing names failed"); fail_unless(!!names[0], "first name"); fail_unless(!strcmp(names[0], "daniel.roe.ch"), "first name"); fail_unless(!!names[1], "second name"); fail_unless(!strcmp(names[1], "daniel.roe.ch"), "second name"); fail_unless(!!names[2], "third name"); fail_unless(!strcmp(names[2], "www.roe.ch"), "third name"); fail_unless(!!names[3], "fourth name"); fail_unless(!strcmp(names[3], "*.roe.ch"), "fourth name"); fail_unless(!names[4], "too many names"); p = names; while (*p) free(*p++); free(names); X509_free(c); } END_TEST START_TEST(ssl_x509_names_to_str_01) { X509 *c; char *names; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); names = ssl_x509_names_to_str(c); fail_unless(!!names, "no string"); fail_unless(!strcmp(names, "daniel.roe.ch/daniel.roe.ch/www.roe.ch/*.roe.ch"), "wrong name string"); X509_free(c); } END_TEST START_TEST(ssl_x509_names_to_str_02) { X509 *c; char *names; c = ssl_x509_load(TESTCERT2); fail_unless(!!c, "loading certificate failed"); names = ssl_x509_names_to_str(c); fail_unless(!!names, "no string"); fail_unless(!strcmp(names, "SSLsplit Root CA"), "wrong name string"); X509_free(c); } END_TEST START_TEST(ssl_x509_subject_01) { X509 *c; char *subject; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); subject = ssl_x509_subject(c); fail_unless(!!subject, "no string"); fail_unless(!strcmp(subject, "/C=CH/O=SSLsplit Test Certificate/" "CN=daniel.roe.ch"), "wrong subject string"); X509_free(c); } END_TEST START_TEST(ssl_x509_subject_cn_01) { X509 *c; char *cn; size_t sz; size_t expsz = strlen("daniel.roe.ch") + 1; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); cn = ssl_x509_subject_cn(c, &sz); fail_unless(!!cn, "no string"); fail_unless(sz >= expsz, "subject CN size too small"); fail_unless(!strcmp(cn, "daniel.roe.ch"), "wrong subject CN string"); #if 0 for (unsigned int i = expsz; i < sz; i++) { fail_unless(cn[i] == '\0', "extra byte != 0"); } #endif X509_free(c); } END_TEST START_TEST(ssl_x509_ocsps_01) { X509 *c; char **ocsps, **p; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); ocsps = ssl_x509_ocsps(c); fail_unless(!!ocsps, "parsing OCSP extensions failed"); fail_unless(!!ocsps[0], "first OCSP"); fail_unless(!strcmp(ocsps[0], "http://daniel.roe.ch/test/ocsp"), "first OCSP"); fail_unless(!ocsps[1], "too many OCSPs"); p = ocsps; while (*p) free(*p++); free(ocsps); X509_free(c); } END_TEST START_TEST(ssl_x509_ocsps_02) { X509 *c; char **ocsps; c = ssl_x509_load(TESTCERT2); fail_unless(!!c, "loading certificate failed"); ocsps = ssl_x509_ocsps(c); fail_unless(!ocsps, "unexpected OCSP extensions"); X509_free(c); } END_TEST static char ocspreq01[] = "MEIwQDA+MDwwOjAJBgUrDgMCGgUABBT4cyABkyiCIhU4JpmIB" "ewdDnn8ZgQUbyBZ44kgy35o7xW5BMzM8FTvyTwCAQE="; START_TEST(ssl_is_ocspreq_01) { unsigned char *buf; size_t sz; buf = base64_dec(ocspreq01, sizeof(ocspreq01) - 1, &sz); fail_unless(!!buf, "failed to base64 decode"); fail_unless(ssl_is_ocspreq(buf, sz), "is not ocsp req"); } END_TEST START_TEST(ssl_features_01) { long vdiff = ((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xfffff000L); fail_unless(!vdiff, "OpenSSL version mismatch at runtime"); } END_TEST START_TEST(ssl_features_02) { int have_threads = 0; #ifdef OPENSSL_THREADS have_threads = 1; #endif /* OPENSSL_THREADS */ fail_unless(have_threads, "!OPENSSL_THREADS: no threading support"); } END_TEST START_TEST(ssl_key_refcount_inc_01) { EVP_PKEY *key; key = ssl_key_load(TESTKEY); fail_unless(!!key, "loading key failed"); ssl_key_refcount_inc(key); ssl_key_refcount_inc(key); ssl_key_refcount_inc(key); EVP_PKEY_free(key); /* these must not crash */ EVP_PKEY_free(key); EVP_PKEY_free(key); EVP_PKEY_free(key); } END_TEST START_TEST(ssl_x509_refcount_inc_01) { X509 *crt; crt = ssl_x509_load(TESTCERT); fail_unless(!!crt, "loading certificate failed"); ssl_x509_refcount_inc(crt); ssl_x509_refcount_inc(crt); ssl_x509_refcount_inc(crt); X509_free(crt); /* these must not crash */ X509_free(crt); X509_free(crt); X509_free(crt); } END_TEST #ifndef OPENSSL_NO_ENGINE START_TEST(ssl_engine_01) { char cwd[PATH_MAX]; char *path; fail_unless(getcwd(cwd, sizeof(cwd)) == cwd, "getcwd() failed"); fail_unless(asprintf(&path, "%s/"ENGINE, cwd) != -1 && !!path, "constructing engine path failed"); fail_unless(ssl_engine(path) == 0, "loading OpenSSL engine failed"); free(path); } END_TEST #endif /* !OPENSSL_NO_ENGINE */ Suite * ssl_suite(void) { Suite *s; TCase *tc; s = suite_create("ssl"); tc = tcase_create("ssl_wildcardify"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_wildcardify_01); tcase_add_test(tc, ssl_wildcardify_02); tcase_add_test(tc, ssl_wildcardify_03); suite_add_tcase(s, tc); tc = tcase_create("ssl_dnsname_match"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_dnsname_match_01); tcase_add_test(tc, ssl_dnsname_match_02); tcase_add_test(tc, ssl_dnsname_match_03); tcase_add_test(tc, ssl_dnsname_match_04); tcase_add_test(tc, ssl_dnsname_match_05); tcase_add_test(tc, ssl_dnsname_match_06); tcase_add_test(tc, ssl_dnsname_match_07); tcase_add_test(tc, ssl_dnsname_match_08); tcase_add_test(tc, ssl_dnsname_match_09); tcase_add_test(tc, ssl_dnsname_match_10); tcase_add_test(tc, ssl_dnsname_match_11); tcase_add_test(tc, ssl_dnsname_match_12); tcase_add_test(tc, ssl_dnsname_match_13); tcase_add_test(tc, ssl_dnsname_match_14); tcase_add_test(tc, ssl_dnsname_match_15); tcase_add_test(tc, ssl_dnsname_match_16); suite_add_tcase(s, tc); tc = tcase_create("ssl_tls_clienthello_parse"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_tls_clienthello_parse_00); tcase_add_test(tc, ssl_tls_clienthello_parse_01); tcase_add_test(tc, ssl_tls_clienthello_parse_02); tcase_add_test(tc, ssl_tls_clienthello_parse_03); tcase_add_test(tc, ssl_tls_clienthello_parse_04); tcase_add_test(tc, ssl_tls_clienthello_parse_05); tcase_add_test(tc, ssl_tls_clienthello_parse_06); tcase_add_test(tc, ssl_tls_clienthello_parse_07); tcase_add_test(tc, ssl_tls_clienthello_parse_08); tcase_add_test(tc, ssl_tls_clienthello_parse_09); tcase_add_test(tc, ssl_tls_clienthello_parse_10); suite_add_tcase(s, tc); tc = tcase_create("ssl_key_identifier_sha1"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_key_identifier_sha1_01); suite_add_tcase(s, tc); tc = tcase_create("ssl_x509_names"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_x509_names_01); suite_add_tcase(s, tc); tc = tcase_create("ssl_x509_names_to_str"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_x509_names_to_str_01); tcase_add_test(tc, ssl_x509_names_to_str_02); suite_add_tcase(s, tc); tc = tcase_create("ssl_x509_subject"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_x509_subject_01); suite_add_tcase(s, tc); tc = tcase_create("ssl_x509_subject_cn"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_x509_subject_cn_01); suite_add_tcase(s, tc); tc = tcase_create("ssl_x509_ocsps"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_x509_ocsps_01); tcase_add_test(tc, ssl_x509_ocsps_02); suite_add_tcase(s, tc); tc = tcase_create("ssl_is_ocspreq"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_is_ocspreq_01); suite_add_tcase(s, tc); tc = tcase_create("ssl_features"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_features_01); tcase_add_test(tc, ssl_features_02); suite_add_tcase(s, tc); tc = tcase_create("ssl_key_refcount_inc"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_key_refcount_inc_01); suite_add_tcase(s, tc); tc = tcase_create("ssl_x509_refcount_inc"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_x509_refcount_inc_01); suite_add_tcase(s, tc); #ifndef OPENSSL_NO_ENGINE tc = tcase_create("ssl_engine"); tcase_add_checked_fixture(tc, ssl_setup, ssl_teardown); tcase_add_test(tc, ssl_engine_01); suite_add_tcase(s, tc); #else /* OPENSSL_NO_ENGINE */ fprintf(stderr, "ssl: 1 test omitted because OpenSSL has no " "engine support\n"); #endif /* OPENSSL_NO_ENGINE */ return s; } /* vim: set noet ft=c: */