/*
* Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
#include "testutil.h"
#include "testutil/output.h"
#include "internal/nelem.h"
+#include "internal/ktls.h"
#include "../ssl/ssl_locl.h"
#ifndef OPENSSL_NO_TLS1_3
return testresult;
}
+#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS)
+
+/* sock must be connected */
+static int ktls_chk_platform(int sock)
+{
+ if (!ktls_enable(sock))
+ return 0;
+ return 1;
+}
+
+static int ping_pong_query(SSL *clientssl, SSL *serverssl, int cfd, int sfd)
+{
+ static char count = 1;
+ unsigned char cbuf[16000] = {0};
+ unsigned char sbuf[16000];
+ size_t err = 0;
+ char crec_wseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char crec_wseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_wseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_wseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_rseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_rseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+
+ cbuf[0] = count++;
+ memcpy(crec_wseq_before, &clientssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_wseq_before, &serverssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_rseq_before, &serverssl->rlayer.read_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+
+ if (!TEST_true(SSL_write(clientssl, cbuf, sizeof(cbuf)) == sizeof(cbuf)))
+ goto end;
+
+ while ((err = SSL_read(serverssl, &sbuf, sizeof(sbuf))) != sizeof(sbuf)) {
+ if (SSL_get_error(serverssl, err) != SSL_ERROR_WANT_READ) {
+ goto end;
+ }
+ }
+
+ if (!TEST_true(SSL_write(serverssl, sbuf, sizeof(sbuf)) == sizeof(sbuf)))
+ goto end;
+
+ while ((err = SSL_read(clientssl, &cbuf, sizeof(cbuf))) != sizeof(cbuf)) {
+ if (SSL_get_error(clientssl, err) != SSL_ERROR_WANT_READ) {
+ goto end;
+ }
+ }
+
+ memcpy(crec_wseq_after, &clientssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_wseq_after, &serverssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_rseq_after, &serverssl->rlayer.read_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+
+ /* verify the payload */
+ if (!TEST_mem_eq(cbuf, sizeof(cbuf), sbuf, sizeof(sbuf)))
+ goto end;
+
+ /* ktls is used then kernel sequences are used instead of OpenSSL sequences */
+ if (clientssl->mode & SSL_MODE_NO_KTLS_TX) {
+ if (!TEST_mem_ne(crec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ crec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ } else {
+ if (!TEST_mem_eq(crec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ crec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ }
+
+ if (serverssl->mode & SSL_MODE_NO_KTLS_TX) {
+ if (!TEST_mem_ne(srec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ } else {
+ if (!TEST_mem_eq(srec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ }
+
+ if (!TEST_mem_ne(srec_rseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_rseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+
+ return 1;
+end:
+ return 0;
+}
+
+static int execute_test_ktls(int cis_ktls_tx, int sis_ktls_tx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ int cfd, sfd;
+
+ if (!TEST_true(create_test_sockets(&cfd, &sfd)))
+ goto end;
+
+ /* Skip this test if the platform does not support ktls */
+ if (!ktls_chk_platform(cfd))
+ return 1;
+
+ /* Create a session based on SHA-256 */
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_2_VERSION, TLS1_2_VERSION,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+ "AES128-GCM-SHA256"))
+ || !TEST_true(create_ssl_objects2(sctx, cctx, &serverssl,
+ &clientssl, sfd, cfd)))
+ goto end;
+
+ if (!cis_ktls_tx) {
+ if (!TEST_true(SSL_set_mode(clientssl, SSL_MODE_NO_KTLS_TX)))
+ goto end;
+ }
+
+ if (!sis_ktls_tx) {
+ if (!TEST_true(SSL_set_mode(serverssl, SSL_MODE_NO_KTLS_TX)))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ if (!cis_ktls_tx) {
+ if (!TEST_false(BIO_get_ktls_send(clientssl->wbio)))
+ goto end;
+ } else {
+ if (!TEST_true(BIO_get_ktls_send(clientssl->wbio)))
+ goto end;
+ }
+
+ if (!sis_ktls_tx) {
+ if (!TEST_false(BIO_get_ktls_send(serverssl->wbio)))
+ goto end;
+ } else {
+ if (!TEST_true(BIO_get_ktls_send(serverssl->wbio)))
+ goto end;
+ }
+
+ if (!TEST_true(ping_pong_query(clientssl, serverssl, cfd, sfd)))
+ goto end;
+
+ testresult = 1;
+end:
+ if (clientssl) {
+ SSL_shutdown(clientssl);
+ SSL_free(clientssl);
+ }
+ if (serverssl) {
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ }
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ serverssl = clientssl = NULL;
+ return testresult;
+}
+
+static int test_ktls_client_server(void)
+{
+ return execute_test_ktls(1, 1);
+}
+
+static int test_ktls_no_client_server(void)
+{
+ return execute_test_ktls(0, 1);
+}
+
+static int test_ktls_client_no_server(void)
+{
+ return execute_test_ktls(1, 0);
+}
+
+static int test_ktls_no_client_no_server(void)
+{
+ return execute_test_ktls(0, 0);
+}
+
+#endif
+
static int test_large_message_tls(void)
{
return execute_test_large_message(TLS_server_method(), TLS_client_method(),
* no test vectors so all we do is test that both sides of the communication
* produce the same results for different protocol versions.
*/
+#define SMALL_LABEL_LEN 10
+#define LONG_LABEL_LEN 249
static int test_export_key_mat(int tst)
{
int testresult = 0;
SSL_CTX *cctx = NULL, *sctx = NULL, *sctx2 = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
- const char label[] = "test label";
+ const char label[LONG_LABEL_LEN + 1] = "test label";
const unsigned char context[] = "context";
const unsigned char *emptycontext = NULL;
unsigned char ckeymat1[80], ckeymat2[80], ckeymat3[80];
unsigned char skeymat1[80], skeymat2[80], skeymat3[80];
+ size_t labellen;
const int protocols[] = {
TLS1_VERSION,
TLS1_1_VERSION,
TLS1_2_VERSION,
+ TLS1_3_VERSION,
+ TLS1_3_VERSION,
TLS1_3_VERSION
};
return 1;
#endif
#ifdef OPENSSL_NO_TLS1_3
- if (tst == 3)
+ if (tst >= 3)
return 1;
#endif
if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
SSL_ERROR_NONE)))
goto end;
+ if (tst == 5) {
+ /*
+ * TLSv1.3 imposes a maximum label len of 249 bytes. Check we fail if we
+ * go over that.
+ */
+ if (!TEST_int_le(SSL_export_keying_material(clientssl, ckeymat1,
+ sizeof(ckeymat1), label,
+ LONG_LABEL_LEN + 1, context,
+ sizeof(context) - 1, 1), 0))
+ goto end;
+
+ testresult = 1;
+ goto end;
+ } else if (tst == 4) {
+ labellen = LONG_LABEL_LEN;
+ } else {
+ labellen = SMALL_LABEL_LEN;
+ }
+
if (!TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat1,
sizeof(ckeymat1), label,
- sizeof(label) - 1, context,
+ labellen, context,
sizeof(context) - 1, 1), 1)
|| !TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat2,
sizeof(ckeymat2), label,
- sizeof(label) - 1,
+ labellen,
emptycontext,
0, 1), 1)
|| !TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat3,
sizeof(ckeymat3), label,
- sizeof(label) - 1,
+ labellen,
NULL, 0, 0), 1)
|| !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat1,
sizeof(skeymat1), label,
- sizeof(label) - 1,
+ labellen,
context,
sizeof(context) -1, 1),
1)
|| !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat2,
sizeof(skeymat2), label,
- sizeof(label) - 1,
+ labellen,
emptycontext,
0, 1), 1)
|| !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat3,
sizeof(skeymat3), label,
- sizeof(label) - 1,
+ labellen,
NULL, 0, 0), 1)
/*
* Check that both sides created the same key material with the
* Check that an empty context and no context produce different results in
* protocols less than TLSv1.3. In TLSv1.3 they should be the same.
*/
- if ((tst != 3 && !TEST_mem_ne(ckeymat2, sizeof(ckeymat2), ckeymat3,
+ if ((tst < 3 && !TEST_mem_ne(ckeymat2, sizeof(ckeymat2), ckeymat3,
sizeof(ckeymat3)))
- || (tst ==3 && !TEST_mem_eq(ckeymat2, sizeof(ckeymat2), ckeymat3,
- sizeof(ckeymat3))))
+ || (tst >= 3 && !TEST_mem_eq(ckeymat2, sizeof(ckeymat2), ckeymat3,
+ sizeof(ckeymat3))))
goto end;
testresult = 1;
return testresult;
}
+static int client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
+{
+ X509 *xcert, *peer;
+ EVP_PKEY *privpkey;
+ BIO *in = NULL;
+
+ /* Check that SSL_get_peer_certificate() returns something sensible */
+ peer = SSL_get_peer_certificate(ssl);
+ if (!TEST_ptr(peer))
+ return 0;
+ X509_free(peer);
+
+ in = BIO_new_file(cert, "r");
+ if (!TEST_ptr(in))
+ return 0;
+
+ xcert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ BIO_free(in);
+ if (!TEST_ptr(xcert))
+ return 0;
+
+ in = BIO_new_file(privkey, "r");
+ if (!TEST_ptr(in)) {
+ X509_free(xcert);
+ return 0;
+ }
+
+ privpkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
+ BIO_free(in);
+ if (!TEST_ptr(privpkey)) {
+ X509_free(xcert);
+ return 0;
+ }
+
+ *x509 = xcert;
+ *pkey = privpkey;
+
+ return 1;
+}
+
+static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+ return 1;
+}
+
+static int test_client_cert_cb(int tst)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+
+#ifdef OPENSSL_NO_TLS1_2
+ if (tst == 0)
+ return 1;
+#endif
+#ifdef OPENSSL_NO_TLS1_3
+ if (tst == 1)
+ return 1;
+#endif
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_VERSION,
+ tst == 0 ? TLS1_2_VERSION
+ : TLS1_3_VERSION,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ /*
+ * Test that setting a client_cert_cb results in a client certificate being
+ * sent.
+ */
+ SSL_CTX_set_client_cert_cb(cctx, client_cert_cb);
+ SSL_CTX_set_verify(sctx,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ verify_cb);
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+#if !defined(OPENSSL_NO_TLS1_2) || !defined(OPENSSL_NO_TLS1_3)
+/*
+ * Test setting certificate authorities on both client and server.
+ *
+ * Test 0: SSL_CTX_set0_CA_list() only
+ * Test 1: Both SSL_CTX_set0_CA_list() and SSL_CTX_set_client_CA_list()
+ * Test 2: Only SSL_CTX_set_client_CA_list()
+ */
+static int test_ca_names_int(int prot, int tst)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ size_t i;
+ X509_NAME *name[] = { NULL, NULL, NULL, NULL };
+ char *strnames[] = { "Jack", "Jill", "John", "Joanne" };
+ STACK_OF(X509_NAME) *sk1 = NULL, *sk2 = NULL;
+ const STACK_OF(X509_NAME) *sktmp = NULL;
+
+ for (i = 0; i < OSSL_NELEM(name); i++) {
+ name[i] = X509_NAME_new();
+ if (!TEST_ptr(name[i])
+ || !TEST_true(X509_NAME_add_entry_by_txt(name[i], "CN",
+ MBSTRING_ASC,
+ (unsigned char *)
+ strnames[i],
+ -1, -1, 0)))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_VERSION,
+ prot,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ SSL_CTX_set_verify(sctx, SSL_VERIFY_PEER, NULL);
+
+ if (tst == 0 || tst == 1) {
+ if (!TEST_ptr(sk1 = sk_X509_NAME_new_null())
+ || !TEST_true(sk_X509_NAME_push(sk1, X509_NAME_dup(name[0])))
+ || !TEST_true(sk_X509_NAME_push(sk1, X509_NAME_dup(name[1])))
+ || !TEST_ptr(sk2 = sk_X509_NAME_new_null())
+ || !TEST_true(sk_X509_NAME_push(sk2, X509_NAME_dup(name[0])))
+ || !TEST_true(sk_X509_NAME_push(sk2, X509_NAME_dup(name[1]))))
+ goto end;
+
+ SSL_CTX_set0_CA_list(sctx, sk1);
+ SSL_CTX_set0_CA_list(cctx, sk2);
+ sk1 = sk2 = NULL;
+ }
+ if (tst == 1 || tst == 2) {
+ if (!TEST_ptr(sk1 = sk_X509_NAME_new_null())
+ || !TEST_true(sk_X509_NAME_push(sk1, X509_NAME_dup(name[2])))
+ || !TEST_true(sk_X509_NAME_push(sk1, X509_NAME_dup(name[3])))
+ || !TEST_ptr(sk2 = sk_X509_NAME_new_null())
+ || !TEST_true(sk_X509_NAME_push(sk2, X509_NAME_dup(name[2])))
+ || !TEST_true(sk_X509_NAME_push(sk2, X509_NAME_dup(name[3]))))
+ goto end;
+
+ SSL_CTX_set_client_CA_list(sctx, sk1);
+ SSL_CTX_set_client_CA_list(cctx, sk2);
+ sk1 = sk2 = NULL;
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ /*
+ * We only expect certificate authorities to have been sent to the server
+ * if we are using TLSv1.3 and SSL_set0_CA_list() was used
+ */
+ sktmp = SSL_get0_peer_CA_list(serverssl);
+ if (prot == TLS1_3_VERSION
+ && (tst == 0 || tst == 1)) {
+ if (!TEST_ptr(sktmp)
+ || !TEST_int_eq(sk_X509_NAME_num(sktmp), 2)
+ || !TEST_int_eq(X509_NAME_cmp(sk_X509_NAME_value(sktmp, 0),
+ name[0]), 0)
+ || !TEST_int_eq(X509_NAME_cmp(sk_X509_NAME_value(sktmp, 1),
+ name[1]), 0))
+ goto end;
+ } else if (!TEST_ptr_null(sktmp)) {
+ goto end;
+ }
+
+ /*
+ * In all tests we expect certificate authorities to have been sent to the
+ * client. However, SSL_set_client_CA_list() should override
+ * SSL_set0_CA_list()
+ */
+ sktmp = SSL_get0_peer_CA_list(clientssl);
+ if (!TEST_ptr(sktmp)
+ || !TEST_int_eq(sk_X509_NAME_num(sktmp), 2)
+ || !TEST_int_eq(X509_NAME_cmp(sk_X509_NAME_value(sktmp, 0),
+ name[tst == 0 ? 0 : 2]), 0)
+ || !TEST_int_eq(X509_NAME_cmp(sk_X509_NAME_value(sktmp, 1),
+ name[tst == 0 ? 1 : 3]), 0))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ for (i = 0; i < OSSL_NELEM(name); i++)
+ X509_NAME_free(name[i]);
+ sk_X509_NAME_pop_free(sk1, X509_NAME_free);
+ sk_X509_NAME_pop_free(sk2, X509_NAME_free);
+
+ return testresult;
+}
+#endif
+
+static int test_ca_names(int tst)
+{
+ int testresult = 1;
+
+#ifndef OPENSSL_NO_TLS1_2
+ testresult &= test_ca_names_int(TLS1_2_VERSION, tst);
+#endif
+#ifndef OPENSSL_NO_TLS1_3
+ testresult &= test_ca_names_int(TLS1_3_VERSION, tst);
+#endif
+
+ return testresult;
+}
+
int setup_tests(void)
{
if (!TEST_ptr(cert = test_get_argument(0))
#endif
}
+#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS)
+ ADD_TEST(test_ktls_client_server);
+ ADD_TEST(test_ktls_no_client_server);
+ ADD_TEST(test_ktls_client_no_server);
+ ADD_TEST(test_ktls_no_client_no_server);
+#endif
ADD_TEST(test_large_message_tls);
ADD_TEST(test_large_message_tls_read_ahead);
#ifndef OPENSSL_NO_DTLS
ADD_ALL_TESTS(test_custom_exts, 3);
#endif
ADD_ALL_TESTS(test_serverinfo, 8);
- ADD_ALL_TESTS(test_export_key_mat, 4);
+ ADD_ALL_TESTS(test_export_key_mat, 6);
#ifndef OPENSSL_NO_TLS1_3
ADD_ALL_TESTS(test_export_key_mat_early, 3);
#endif
ADD_ALL_TESTS(test_ticket_callbacks, 12);
ADD_ALL_TESTS(test_shutdown, 7);
ADD_ALL_TESTS(test_cert_cb, 3);
+ ADD_ALL_TESTS(test_client_cert_cb, 2);
+ ADD_ALL_TESTS(test_ca_names, 3);
return 1;
}