/* $OpenBSD: tlsexttest.c,v 1.1 2017/07/16 18:18:10 jsing Exp $ */ /* * Copyright (c) 2017 Joel Sing * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "ssl_locl.h" #include "bytestring.h" #include "ssl_tlsext.h" static void hexdump(const unsigned char *buf, size_t len) { size_t i; for (i = 1; i <= len; i++) fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); fprintf(stderr, "\n"); } #define TEST_SNI_SERVERNAME "www.libressl.org" static unsigned char tlsext_sni_clienthello[] = { 0x00, 0x13, 0x00, 0x00, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x6c, 0x69, 0x62, 0x72, 0x65, 0x73, 0x73, 0x6c, 0x2e, 0x6f, 0x72, 0x67, }; static unsigned char tlsext_sni_serverhello[] = { }; static int test_tlsext_sni_clienthello(void) { unsigned char *data = NULL; SSL_CTX *ssl_ctx = NULL; SSL *ssl = NULL; int failure = 0; size_t dlen; int alert; CBB cbb; CBS cbs; CBB_init(&cbb, 0); if ((ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL) errx(1, "failed to create SSL_CTX"); if ((ssl = SSL_new(ssl_ctx)) == NULL) errx(1, "failed to create SSL"); if (tlsext_sni_clienthello_needs(ssl)) { fprintf(stderr, "FAIL: clienthello should not need SNI\n"); failure = 1; goto done; } if (!SSL_set_tlsext_host_name(ssl, TEST_SNI_SERVERNAME)) { fprintf(stderr, "FAIL: client failed to set server name\n"); failure = 1; goto done; } if (!tlsext_sni_clienthello_needs(ssl)) { fprintf(stderr, "FAIL: clienthello should need SNI\n"); failure = 1; goto done; } if (!tlsext_sni_clienthello_build(ssl, &cbb)) { fprintf(stderr, "FAIL: clienthello failed to build SNI\n"); failure = 1; goto done; } if (!CBB_finish(&cbb, &data, &dlen)) errx(1, "failed to finish CBB"); if (dlen != sizeof(tlsext_sni_clienthello)) { fprintf(stderr, "FAIL: got clienthello SNI with length %zu, " "want length %zu\n", dlen, sizeof(tlsext_sni_clienthello)); failure = 1; goto done; } if (memcmp(data, tlsext_sni_clienthello, dlen) != 0) { fprintf(stderr, "FAIL: clienthello SNI differs:\n"); fprintf(stderr, "received:\n"); hexdump(data, dlen); fprintf(stderr, "test data:\n"); hexdump(tlsext_sni_clienthello, sizeof(tlsext_sni_clienthello)); failure = 1; goto done; } if ((ssl->session = SSL_SESSION_new()) == NULL) errx(1, "failed to create session"); ssl->internal->hit = 0; CBS_init(&cbs, tlsext_sni_clienthello, sizeof(tlsext_sni_clienthello)); if (!tlsext_sni_clienthello_parse(ssl, &cbs, &alert)) { fprintf(stderr, "FAIL: failed to parse clienthello SNI\n"); failure = 1; goto done; } if (ssl->session->tlsext_hostname == NULL) { fprintf(stderr, "FAIL: no tlsext_hostname from clienthello SNI\n"); failure = 1; goto done; } if (strlen(ssl->session->tlsext_hostname) != strlen(TEST_SNI_SERVERNAME) || strncmp(ssl->session->tlsext_hostname, TEST_SNI_SERVERNAME, strlen(TEST_SNI_SERVERNAME)) != 0) { fprintf(stderr, "FAIL: got tlsext_hostname `%s', want `%s'\n", ssl->session->tlsext_hostname, TEST_SNI_SERVERNAME); failure = 1; goto done; } done: CBB_cleanup(&cbb); SSL_CTX_free(ssl_ctx); SSL_free(ssl); free(data); return (failure); } static int test_tlsext_sni_serverhello(void) { unsigned char *data = NULL; SSL_CTX *ssl_ctx = NULL; SSL *ssl = NULL; int failure = 0; size_t dlen; int alert; CBB cbb; CBS cbs; CBB_init(&cbb, 0); if ((ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) errx(1, "failed to create SSL_CTX"); if ((ssl = SSL_new(ssl_ctx)) == NULL) errx(1, "failed to create SSL"); if ((ssl->session = SSL_SESSION_new()) == NULL) errx(1, "failed to create session"); if (tlsext_sni_serverhello_needs(ssl)) { fprintf(stderr, "FAIL: serverhello should not need SNI\n"); failure = 1; goto done; } if (!SSL_set_tlsext_host_name(ssl, TEST_SNI_SERVERNAME)) { fprintf(stderr, "FAIL: client failed to set server name\n"); failure = 1; goto done; } if ((ssl->session->tlsext_hostname = strdup(TEST_SNI_SERVERNAME)) == NULL) errx(1, "failed to strdup tlsext_hostname"); if (!tlsext_sni_serverhello_needs(ssl)) { fprintf(stderr, "FAIL: serverhello should need SNI\n"); failure = 1; goto done; } if (!tlsext_sni_serverhello_build(ssl, &cbb)) { fprintf(stderr, "FAIL: serverhello failed to build SNI\n"); failure = 1; goto done; } if (!CBB_finish(&cbb, &data, &dlen)) errx(1, "failed to finish CBB"); if (dlen != sizeof(tlsext_sni_serverhello)) { fprintf(stderr, "FAIL: got serverhello SNI with length %zu, " "want length %zu\n", dlen, sizeof(tlsext_sni_serverhello)); failure = 1; goto done; } if (memcmp(data, tlsext_sni_serverhello, dlen) != 0) { fprintf(stderr, "FAIL: serverhello SNI differs:\n"); fprintf(stderr, "received:\n"); hexdump(data, dlen); fprintf(stderr, "test data:\n"); hexdump(tlsext_sni_serverhello, sizeof(tlsext_sni_serverhello)); failure = 1; goto done; } CBS_init(&cbs, tlsext_sni_serverhello, sizeof(tlsext_sni_serverhello)); if (!tlsext_sni_serverhello_parse(ssl, &cbs, &alert)) { fprintf(stderr, "FAIL: failed to parse serverhello SNI\n"); failure = 1; goto done; } /* XXX - test parse with session with mismatched name. */ done: CBB_cleanup(&cbb); SSL_CTX_free(ssl_ctx); SSL_free(ssl); free(data); return (failure); } int main(int argc, char **argv) { int failed = 0; SSL_library_init(); failed |= test_tlsext_sni_clienthello(); failed |= test_tlsext_sni_serverhello(); return (failed); }