SSLproxy/ssl.t.c
2019-08-08 12:23:04 +03:00

892 lines
27 KiB
C

/*-
* SSLsplit - transparent SSL/TLS interception
* https://www.roe.ch/SSLsplit
*
* Copyright (c) 2009-2019, Daniel Roethlisberger <daniel@roe.ch>.
* 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 <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <check.h>
#ifdef __APPLE__
#define DLSUFFIX "dylib"
#else
#define DLSUFFIX "so"
#endif
#define TESTKEY "extra/pki/server.key"
#define TESTCERT "extra/pki/server.crt"
#define TESTCERT2 "extra/pki/rsa.crt"
#define ENGINE "extra/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: */