/* * Custom call back tests. * Test 0: callbacks in TLSv1.2 * Test 1: callbacks in TLSv1.2 with SNI */ static int test_custom_exts(int tst) { SSL_CTX *cctx = NULL, *sctx = NULL, *sctx2 = NULL; SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; static int server = 1; static int client = 0; SSL_SESSION *sess = NULL; /* Reset callback counters */ clntaddcb = clntparsecb = srvaddcb = srvparsecb = 0; snicb = 0; if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx, &cctx, cert, privkey)) { printf("Unable to create SSL_CTX pair\n"); goto end; } if (tst == 1 && !create_ssl_ctx_pair(TLS_server_method(), NULL, &sctx2, NULL, cert, privkey)) { printf("Unable to create SSL_CTX pair (2)\n"); goto end; } /* Create a client side custom extension */ if (!SSL_CTX_add_client_custom_ext(cctx, TEST_EXT_TYPE1, add_cb, free_cb, &client, parse_cb, &client)) { printf("Unable to add client custom extension\n"); goto end; } /* Should not be able to add duplicates */ if (SSL_CTX_add_client_custom_ext(cctx, TEST_EXT_TYPE1, add_cb, free_cb, &client, parse_cb, &client)) { printf("Unexpected success adding duplicate extension\n"); goto end; } /* Create a server side custom extension */ if (!SSL_CTX_add_server_custom_ext(sctx, TEST_EXT_TYPE1, add_cb, free_cb, &server, parse_cb, &server)) { printf("Unable to add server custom extension\n"); goto end; } if (sctx2 != NULL && !SSL_CTX_add_server_custom_ext(sctx2, TEST_EXT_TYPE1, add_cb, free_cb, &server, parse_cb, &server)) { printf("Unable to add server custom extension for SNI\n"); goto end; } /* Should not be able to add duplicates */ if (SSL_CTX_add_server_custom_ext(sctx, TEST_EXT_TYPE1, add_cb, free_cb, &server, parse_cb, &server)) { printf("Unexpected success adding duplicate extension (2)\n"); goto end; } if (tst == 1) { /* Set up SNI */ if (!SSL_CTX_set_tlsext_servername_callback(sctx, sni_cb) || !SSL_CTX_set_tlsext_servername_arg(sctx, sctx2)) { printf("Cannot set SNI callbacks\n"); goto end; } } if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL) || !create_ssl_connection(serverssl, clientssl)) { printf("Cannot create SSL connection\n"); goto end; } if (clntaddcb != 1 || clntparsecb != 1 || srvaddcb != 1 || srvparsecb != 1 || (tst != 1 && snicb != 0) || (tst == 1 && snicb != 1)) { printf("Incorrect callback counts\n"); goto end; } sess = SSL_get1_session(clientssl); SSL_shutdown(clientssl); SSL_shutdown(serverssl); SSL_free(serverssl); SSL_free(clientssl); serverssl = clientssl = NULL; if (tst == 1) { /* We don't bother with the resumption aspects for this test */ testresult = 1; goto end; } if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL) || !SSL_set_session(clientssl, sess) || !create_ssl_connection(serverssl, clientssl)) { printf("Cannot create resumption connection\n"); goto end; } /* * For a resumed session we expect to add the ClientHello extension but we * should ignore it on the server side. */ if (clntaddcb != 2 || clntparsecb != 1 || srvaddcb != 1 || srvparsecb != 1) { printf("Incorrect resumption callback counts\n"); goto end; } testresult = 1; end: SSL_SESSION_free(sess); SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx2); SSL_CTX_free(sctx); SSL_CTX_free(cctx); return testresult; }
int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd) { STACK_OF(SSL_CIPHER) *ciphers; method_const SSL_METHOD *dtls_method; SSL_SESSION *dtls_session; SSL *dtls_ssl; BIO *dtls_bio; int dtlsver = DTLS1_BAD_VER; const char *cipher = vpninfo->dtls_cipher; #ifdef HAVE_DTLS12 if (!strcmp(cipher, "OC-DTLS1_2-AES128-GCM")) { dtlsver = DTLS1_2_VERSION; cipher = "AES128-GCM-SHA256"; } else if (!strcmp(cipher, "OC-DTLS1_2-AES256-GCM")) { dtlsver = DTLS1_2_VERSION; cipher = "AES256-GCM-SHA384"; #ifndef OPENSSL_NO_PSK } else if (!strcmp(cipher, "PSK-NEGOTIATE")) { dtlsver = 0; /* Let it negotiate */ #endif } #endif if (!vpninfo->dtls_ctx) { #ifdef HAVE_DTLS12 dtls_method = DTLS_client_method(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (dtlsver == DTLS1_BAD_VER) dtls_method = DTLSv1_client_method(); #ifdef HAVE_DTLS12 else if (dtlsver == DTLS1_2_VERSION) dtls_method = DTLSv1_2_client_method(); #endif #endif vpninfo->dtls_ctx = SSL_CTX_new(dtls_method); if (!vpninfo->dtls_ctx) { vpn_progress(vpninfo, PRG_ERR, _("Initialise DTLSv1 CTX failed\n")); openconnect_report_ssl_errors(vpninfo); vpninfo->dtls_attempt_period = 0; return -EINVAL; } if (dtlsver) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (dtlsver == DTLS1_BAD_VER) SSL_CTX_set_options(vpninfo->dtls_ctx, SSL_OP_CISCO_ANYCONNECT); #else if (!SSL_CTX_set_min_proto_version(vpninfo->dtls_ctx, dtlsver) || !SSL_CTX_set_max_proto_version(vpninfo->dtls_ctx, dtlsver)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS CTX version failed\n")); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } #endif #if defined (HAVE_DTLS12) && !defined(OPENSSL_NO_PSK) } else { SSL_CTX_set_psk_client_callback(vpninfo->dtls_ctx, psk_callback); /* For PSK we override the DTLS master secret with one derived * from the HTTPS session. */ if (!SSL_export_keying_material(vpninfo->https_ssl, vpninfo->dtls_secret, PSK_KEY_SIZE, PSK_LABEL, PSK_LABEL_SIZE, NULL, 0, 0)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to generate DTLS key\n")); openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } SSL_CTX_add_client_custom_ext(vpninfo->dtls_ctx, DTLS_APP_ID_EXT, pskident_add, pskident_free, vpninfo, pskident_parse, vpninfo); /* For SSL_CTX_set_cipher_list() */ cipher = "PSK"; #endif } /* If we don't readahead, then we do short reads and throw away the tail of data packets. */ SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1); if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, cipher)) { vpn_progress(vpninfo, PRG_ERR, _("Set DTLS cipher list failed\n")); SSL_CTX_free(vpninfo->dtls_ctx); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } } dtls_ssl = SSL_new(vpninfo->dtls_ctx); SSL_set_connect_state(dtls_ssl); SSL_set_app_data(dtls_ssl, vpninfo); if (dtlsver) { ciphers = SSL_get_ciphers(dtls_ssl); if (dtlsver != 0 && sk_SSL_CIPHER_num(ciphers) != 1) { vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n")); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* We're going to "resume" a session which never existed. Fake it... */ dtls_session = generate_dtls_session(vpninfo, dtlsver, sk_SSL_CIPHER_value(ciphers, 0)); if (!dtls_session) { SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; return -EINVAL; } /* Add the generated session to the SSL */ if (!SSL_set_session(dtls_ssl, dtls_session)) { vpn_progress(vpninfo, PRG_ERR, _("SSL_set_session() failed with old protocol version 0x%x\n" "Are you using a version of OpenSSL older than 0.9.8m?\n" "See http://rt.openssl.org/Ticket/Display.html?id=1751\n" "Use the --no-dtls command line option to avoid this message\n"), DTLS1_BAD_VER); SSL_CTX_free(vpninfo->dtls_ctx); SSL_free(dtls_ssl); vpninfo->dtls_ctx = NULL; vpninfo->dtls_attempt_period = 0; SSL_SESSION_free(dtls_session); return -EINVAL; } /* We don't need our own refcount on it any more */ SSL_SESSION_free(dtls_session); } dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE); /* Set non-blocking */ BIO_set_nbio(dtls_bio, 1); SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio); vpninfo->dtls_ssl = dtls_ssl; return 0; }