summaryrefslogtreecommitdiffstats
path: root/test/helpers
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2020-11-29 12:40:10 +0100
committerDr. David von Oheimb <David.von.Oheimb@siemens.com>2020-12-01 07:49:38 +0100
commit20f8bc72552932393023f5bc5b436cc40cdd1348 (patch)
tree3d3db6acede00003b309439006cd4bbcb02e2438 /test/helpers
parent93a9ffa6c2d8440328deca5e860ae9cf38d81d8a (diff)
test cleanup: move helper .c and .h files to test/helpers/
Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13568)
Diffstat (limited to 'test/helpers')
-rw-r--r--test/helpers/cmp_testlib.c123
-rw-r--r--test/helpers/cmp_testlib.h36
-rw-r--r--test/helpers/handshake.c1779
-rw-r--r--test/helpers/handshake.h81
-rw-r--r--test/helpers/pkcs12.c703
-rw-r--r--test/helpers/pkcs12.h99
-rw-r--r--test/helpers/predefined_dhparams.c172
-rw-r--r--test/helpers/predefined_dhparams.h17
-rw-r--r--test/helpers/ssl_test_ctx.c904
-rw-r--r--test/helpers/ssl_test_ctx.h258
-rw-r--r--test/helpers/ssltestlib.c1042
-rw-r--r--test/helpers/ssltestlib.h59
12 files changed, 5273 insertions, 0 deletions
diff --git a/test/helpers/cmp_testlib.c b/test/helpers/cmp_testlib.c
new file mode 100644
index 0000000000..627b73c3b1
--- /dev/null
+++ b/test/helpers/cmp_testlib.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2019
+ * Copyright Siemens AG 2015-2019
+ *
+ * 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 "cmp_testlib.h"
+#include <openssl/rsa.h> /* needed in case config no-deprecated */
+
+EVP_PKEY *load_pem_key(const char *file, OSSL_LIB_CTX *libctx)
+{
+ EVP_PKEY *key = NULL;
+ BIO *bio = NULL;
+
+ if (!TEST_ptr(bio = BIO_new(BIO_s_file())))
+ return NULL;
+ if (TEST_int_gt(BIO_read_filename(bio, file), 0))
+ (void)TEST_ptr(key = PEM_read_bio_PrivateKey_ex(bio, NULL, NULL, NULL,
+ libctx, NULL));
+
+ BIO_free(bio);
+ return key;
+}
+
+X509 *load_pem_cert(const char *file, OSSL_LIB_CTX *libctx)
+{
+ X509 *cert = NULL;
+ BIO *bio = NULL;
+
+ if (!TEST_ptr(bio = BIO_new(BIO_s_file())))
+ return NULL;
+ if (TEST_int_gt(BIO_read_filename(bio, file), 0)
+ && TEST_ptr(cert = X509_new_ex(libctx, NULL)))
+ (void)TEST_ptr(cert = PEM_read_bio_X509(bio, &cert, NULL, NULL));
+
+ BIO_free(bio);
+ return cert;
+}
+
+OSSL_CMP_MSG *load_pkimsg(const char *file)
+{
+ OSSL_CMP_MSG *msg;
+
+ (void)TEST_ptr((msg = OSSL_CMP_MSG_read(file)));
+ return msg;
+}
+
+X509_REQ *load_csr(const char *file)
+{
+ X509_REQ *csr = NULL;
+ BIO *bio = NULL;
+
+ if (!TEST_ptr(file) || !TEST_ptr(bio = BIO_new_file(file, "rb")))
+ return NULL;
+ (void)TEST_ptr(csr = d2i_X509_REQ_bio(bio, NULL));
+ BIO_free(bio);
+ return csr;
+}
+
+/*
+ * Checks whether the syntax of msg conforms to ASN.1
+ */
+int valid_asn1_encoding(const OSSL_CMP_MSG *msg)
+{
+ return msg != NULL ? i2d_OSSL_CMP_MSG(msg, NULL) > 0 : 0;
+}
+
+/*
+ * Compares two stacks of certificates in the order of their elements.
+ * Returns 0 if sk1 and sk2 are equal and another value otherwise
+ */
+int STACK_OF_X509_cmp(const STACK_OF(X509) *sk1, const STACK_OF(X509) *sk2)
+{
+ int i, res;
+ X509 *a, *b;
+
+ if (sk1 == sk2)
+ return 0;
+ if (sk1 == NULL)
+ return -1;
+ if (sk2 == NULL)
+ return 1;
+ if ((res = sk_X509_num(sk1) - sk_X509_num(sk2)))
+ return res;
+ for (i = 0; i < sk_X509_num(sk1); i++) {
+ a = sk_X509_value(sk1, i);
+ b = sk_X509_value(sk2, i);
+ if (a != b)
+ if ((res = X509_cmp(a, b)) != 0)
+ return res;
+ }
+ return 0;
+}
+
+/*
+ * Up refs and push a cert onto sk.
+ * Returns the number of certificates on the stack on success
+ * Returns -1 or 0 on error
+ */
+int STACK_OF_X509_push1(STACK_OF(X509) *sk, X509 *cert)
+{
+ int res;
+
+ if (sk == NULL || cert == NULL)
+ return -1;
+ if (!X509_up_ref(cert))
+ return -1;
+ res = sk_X509_push(sk, cert);
+ if (res <= 0)
+ X509_free(cert); /* down-ref */
+ return res;
+}
+
+int print_to_bio_out(const char *func, const char *file, int line,
+ OSSL_CMP_severity level, const char *msg)
+{
+ return OSSL_CMP_print_to_bio(bio_out, func, file, line, level, msg);
+}
diff --git a/test/helpers/cmp_testlib.h b/test/helpers/cmp_testlib.h
new file mode 100644
index 0000000000..0bee099a67
--- /dev/null
+++ b/test/helpers/cmp_testlib.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2019
+ * Copyright Siemens AG 2015-2019
+ *
+ * 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
+ */
+
+#ifndef OSSL_TEST_CMP_TESTLIB_H
+# define OSSL_TEST_CMP_TESTLIB_H
+
+# include <openssl/cmp.h>
+# include <openssl/pem.h>
+# include <openssl/rand.h>
+# include "crypto/x509.h" /* for x509_set0_libctx() and x509_dup_ex() */
+
+# include "../../crypto/cmp/cmp_local.h"
+# include "../testutil.h"
+
+# ifndef OPENSSL_NO_CMP
+# define CMP_TEST_REFVALUE_LENGTH 15 /* arbitrary value */
+EVP_PKEY *load_pem_key(const char *file, OSSL_LIB_CTX *libctx);
+X509 *load_pem_cert(const char *file, OSSL_LIB_CTX *libctx);
+X509_REQ *load_csr(const char *file);
+OSSL_CMP_MSG *load_pkimsg(const char *file);
+int valid_asn1_encoding(const OSSL_CMP_MSG *msg);
+int STACK_OF_X509_cmp(const STACK_OF(X509) *sk1, const STACK_OF(X509) *sk2);
+int STACK_OF_X509_push1(STACK_OF(X509) *sk, X509 *cert);
+int print_to_bio_out(const char *func, const char *file, int line,
+ OSSL_CMP_severity level, const char *msg);
+# endif
+
+#endif /* OSSL_TEST_CMP_TESTLIB_H */
diff --git a/test/helpers/handshake.c b/test/helpers/handshake.c
new file mode 100644
index 0000000000..08fcd39bea
--- /dev/null
+++ b/test/helpers/handshake.c
@@ -0,0 +1,1779 @@
+/*
+ * Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * 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 <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+#ifndef OPENSSL_NO_SRP
+#include <openssl/srp.h>
+#endif
+
+#include "../../ssl/ssl_local.h"
+#include "internal/sockets.h"
+#include "internal/nelem.h"
+#include "handshake.h"
+#include "../testutil.h"
+
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+#include <netinet/sctp.h>
+#endif
+
+HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void)
+{
+ HANDSHAKE_RESULT *ret;
+
+ TEST_ptr(ret = OPENSSL_zalloc(sizeof(*ret)));
+ return ret;
+}
+
+void HANDSHAKE_RESULT_free(HANDSHAKE_RESULT *result)
+{
+ if (result == NULL)
+ return;
+ OPENSSL_free(result->client_npn_negotiated);
+ OPENSSL_free(result->server_npn_negotiated);
+ OPENSSL_free(result->client_alpn_negotiated);
+ OPENSSL_free(result->server_alpn_negotiated);
+ OPENSSL_free(result->result_session_ticket_app_data);
+ sk_X509_NAME_pop_free(result->server_ca_names, X509_NAME_free);
+ sk_X509_NAME_pop_free(result->client_ca_names, X509_NAME_free);
+ OPENSSL_free(result->cipher);
+ OPENSSL_free(result);
+}
+
+/*
+ * Since there appears to be no way to extract the sent/received alert
+ * from the SSL object directly, we use the info callback and stash
+ * the result in ex_data.
+ */
+typedef struct handshake_ex_data_st {
+ int alert_sent;
+ int num_fatal_alerts_sent;
+ int alert_received;
+ int session_ticket_do_not_call;
+ ssl_servername_t servername;
+} HANDSHAKE_EX_DATA;
+
+typedef struct ctx_data_st {
+ unsigned char *npn_protocols;
+ size_t npn_protocols_len;
+ unsigned char *alpn_protocols;
+ size_t alpn_protocols_len;
+ char *srp_user;
+ char *srp_password;
+ char *session_ticket_app_data;
+} CTX_DATA;
+
+/* |ctx_data| itself is stack-allocated. */
+static void ctx_data_free_data(CTX_DATA *ctx_data)
+{
+ OPENSSL_free(ctx_data->npn_protocols);
+ ctx_data->npn_protocols = NULL;
+ OPENSSL_free(ctx_data->alpn_protocols);
+ ctx_data->alpn_protocols = NULL;
+ OPENSSL_free(ctx_data->srp_user);
+ ctx_data->srp_user = NULL;
+ OPENSSL_free(ctx_data->srp_password);
+ ctx_data->srp_password = NULL;
+ OPENSSL_free(ctx_data->session_ticket_app_data);
+ ctx_data->session_ticket_app_data = NULL;
+}
+
+static int ex_data_idx;
+
+static void info_cb(const SSL *s, int where, int ret)
+{
+ if (where & SSL_CB_ALERT) {
+ HANDSHAKE_EX_DATA *ex_data =
+ (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
+ if (where & SSL_CB_WRITE) {
+ ex_data->alert_sent = ret;
+ if (strcmp(SSL_alert_type_string(ret), "F") == 0
+ || strcmp(SSL_alert_desc_string(ret), "CN") == 0)
+ ex_data->num_fatal_alerts_sent++;
+ } else {
+ ex_data->alert_received = ret;
+ }
+ }
+}
+
+/* Select the appropriate server CTX.
+ * Returns SSL_TLSEXT_ERR_OK if a match was found.
+ * If |ignore| is 1, returns SSL_TLSEXT_ERR_NOACK on mismatch.
+ * Otherwise, returns SSL_TLSEXT_ERR_ALERT_FATAL on mismatch.
+ * An empty SNI extension also returns SSL_TSLEXT_ERR_NOACK.
+ */
+static int select_server_ctx(SSL *s, void *arg, int ignore)
+{
+ const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+ HANDSHAKE_EX_DATA *ex_data =
+ (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
+
+ if (servername == NULL) {
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ if (strcmp(servername, "server2") == 0) {
+ SSL_CTX *new_ctx = (SSL_CTX*)arg;
+ SSL_set_SSL_CTX(s, new_ctx);
+ /*
+ * Copy over all the SSL_CTX options - reasonable behavior
+ * allows testing of cases where the options between two
+ * contexts differ/conflict
+ */
+ SSL_clear_options(s, 0xFFFFFFFFL);
+ SSL_set_options(s, SSL_CTX_get_options(new_ctx));
+
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER2;
+ return SSL_TLSEXT_ERR_OK;
+ } else if (strcmp(servername, "server1") == 0) {
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
+ return SSL_TLSEXT_ERR_OK;
+ } else if (ignore) {
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
+ return SSL_TLSEXT_ERR_NOACK;
+ } else {
+ /* Don't set an explicit alert, to test library defaults. */
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+}
+
+static int client_hello_select_server_ctx(SSL *s, void *arg, int ignore)
+{
+ const char *servername;
+ const unsigned char *p;
+ size_t len, remaining;
+ HANDSHAKE_EX_DATA *ex_data =
+ (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
+
+ /*
+ * The server_name extension was given too much extensibility when it
+ * was written, so parsing the normal case is a bit complex.
+ */
+ if (!SSL_client_hello_get0_ext(s, TLSEXT_TYPE_server_name, &p,
+ &remaining) ||
+ remaining <= 2)
+ return 0;
+ /* Extract the length of the supplied list of names. */
+ len = (*(p++) << 8);
+ len += *(p++);
+ if (len + 2 != remaining)
+ return 0;
+ remaining = len;
+ /*
+ * The list in practice only has a single element, so we only consider
+ * the first one.
+ */
+ if (remaining == 0 || *p++ != TLSEXT_NAMETYPE_host_name)
+ return 0;
+ remaining--;
+ /* Now we can finally pull out the byte array with the actual hostname. */
+ if (remaining <= 2)
+ return 0;
+ len = (*(p++) << 8);
+ len += *(p++);
+ if (len + 2 > remaining)
+ return 0;
+ remaining = len;
+ servername = (const char *)p;
+
+ if (len == strlen("server2") && strncmp(servername, "server2", len) == 0) {
+ SSL_CTX *new_ctx = arg;
+ SSL_set_SSL_CTX(s, new_ctx);
+ /*
+ * Copy over all the SSL_CTX options - reasonable behavior
+ * allows testing of cases where the options between two
+ * contexts differ/conflict
+ */
+ SSL_clear_options(s, 0xFFFFFFFFL);
+ SSL_set_options(s, SSL_CTX_get_options(new_ctx));
+
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER2;
+ return 1;
+ } else if (len == strlen("server1") &&
+ strncmp(servername, "server1", len) == 0) {
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
+ return 1;
+ } else if (ignore) {
+ ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
+ return 1;
+ }
+ return 0;
+}
+/*
+ * (RFC 6066):
+ * If the server understood the ClientHello extension but
+ * does not recognize the server name, the server SHOULD take one of two
+ * actions: either abort the handshake by sending a fatal-level
+ * unrecognized_name(112) alert or continue the handshake.
+ *
+ * This behaviour is up to the application to configure; we test both
+ * configurations to ensure the state machine propagates the result
+ * correctly.
+ */
+static int servername_ignore_cb(SSL *s, int *ad, void *arg)
+{
+ return select_server_ctx(s, arg, 1);
+}
+
+static int servername_reject_cb(SSL *s, int *ad, void *arg)
+{
+ return select_server_ctx(s, arg, 0);
+}
+
+static int client_hello_ignore_cb(SSL *s, int *al, void *arg)
+{
+ if (!client_hello_select_server_ctx(s, arg, 1)) {
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return SSL_CLIENT_HELLO_ERROR;
+ }
+ return SSL_CLIENT_HELLO_SUCCESS;
+}
+
+static int client_hello_reject_cb(SSL *s, int *al, void *arg)
+{
+ if (!client_hello_select_server_ctx(s, arg, 0)) {
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return SSL_CLIENT_HELLO_ERROR;
+ }
+ return SSL_CLIENT_HELLO_SUCCESS;
+}
+
+static int client_hello_nov12_cb(SSL *s, int *al, void *arg)
+{
+ int ret;
+ unsigned int v;
+ const unsigned char *p;
+
+ v = SSL_client_hello_get0_legacy_version(s);
+ if (v > TLS1_2_VERSION || v < SSL3_VERSION) {
+ *al = SSL_AD_PROTOCOL_VERSION;
+ return SSL_CLIENT_HELLO_ERROR;
+ }
+ (void)SSL_client_hello_get0_session_id(s, &p);
+ if (p == NULL ||
+ SSL_client_hello_get0_random(s, &p) == 0 ||
+ SSL_client_hello_get0_ciphers(s, &p) == 0 ||
+ SSL_client_hello_get0_compression_methods(s, &p) == 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return SSL_CLIENT_HELLO_ERROR;
+ }
+ ret = client_hello_select_server_ctx(s, arg, 0);
+ SSL_set_max_proto_version(s, TLS1_1_VERSION);
+ if (!ret) {
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return SSL_CLIENT_HELLO_ERROR;
+ }
+ return SSL_CLIENT_HELLO_SUCCESS;
+}
+
+static unsigned char dummy_ocsp_resp_good_val = 0xff;
+static unsigned char dummy_ocsp_resp_bad_val = 0xfe;
+
+static int server_ocsp_cb(SSL *s, void *arg)
+{
+ unsigned char *resp;
+
+ resp = OPENSSL_malloc(1);
+ if (resp == NULL)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ /*
+ * For the purposes of testing we just send back a dummy OCSP response
+ */
+ *resp = *(unsigned char *)arg;
+ if (!SSL_set_tlsext_status_ocsp_resp(s, resp, 1))
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static int client_ocsp_cb(SSL *s, void *arg)
+{
+ const unsigned char *resp;
+ int len;
+
+ len = SSL_get_tlsext_status_ocsp_resp(s, &resp);
+ if (len != 1 || *resp != dummy_ocsp_resp_good_val)
+ return 0;
+
+ return 1;
+}
+
+static int verify_reject_cb(X509_STORE_CTX *ctx, void *arg) {
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
+ return 0;
+}
+
+static int verify_accept_cb(X509_STORE_CTX *ctx, void *arg) {
+ return 1;
+}
+
+static int broken_session_ticket_cb(SSL *s, unsigned char *key_name,
+ unsigned char *iv, EVP_CIPHER_CTX *ctx,
+ EVP_MAC_CTX *hctx, int enc)
+{
+ return 0;
+}
+
+static int do_not_call_session_ticket_cb(SSL *s, unsigned char *key_name,
+ unsigned char *iv,
+ EVP_CIPHER_CTX *ctx,
+ EVP_MAC_CTX *hctx, int enc)
+{
+ HANDSHAKE_EX_DATA *ex_data =
+ (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
+ ex_data->session_ticket_do_not_call = 1;
+ return 0;
+}
+
+/* Parse the comma-separated list into TLS format. */
+static int parse_protos(const char *protos, unsigned char **out, size_t *outlen)
+{
+ size_t len, i, prefix;
+
+ len = strlen(protos);
+
+ /* Should never have reuse. */
+ if (!TEST_ptr_null(*out)
+ /* Test values are small, so we omit length limit checks. */
+ || !TEST_ptr(*out = OPENSSL_malloc(len + 1)))
+ return 0;
+ *outlen = len + 1;
+
+ /*
+ * foo => '3', 'f', 'o', 'o'
+ * foo,bar => '3', 'f', 'o', 'o', '3', 'b', 'a', 'r'
+ */
+ memcpy(*out + 1, protos, len);
+
+ prefix = 0;
+ i = prefix + 1;
+ while (i <= len) {
+ if ((*out)[i] == ',') {
+ if (!TEST_int_gt(i - 1, prefix))
+ goto err;
+ (*out)[prefix] = (unsigned char)(i - 1 - prefix);
+ prefix = i;
+ }
+ i++;
+ }
+ if (!TEST_int_gt(len, prefix))
+ goto err;
+ (*out)[prefix] = (unsigned char)(len - prefix);
+ return 1;
+
+err:
+ OPENSSL_free(*out);
+ *out = NULL;
+ return 0;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * The client SHOULD select the first protocol advertised by the server that it
+ * also supports. In the event that the client doesn't support any of server's
+ * protocols, or the server doesn't advertise any, it SHOULD select the first
+ * protocol that it supports.
+ */
+static int client_npn_cb(SSL *s, unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ void *arg)
+{
+ CTX_DATA *ctx_data = (CTX_DATA*)(arg);
+ int ret;
+
+ ret = SSL_select_next_proto(out, outlen, in, inlen,
+ ctx_data->npn_protocols,
+ ctx_data->npn_protocols_len);
+ /* Accept both OPENSSL_NPN_NEGOTIATED and OPENSSL_NPN_NO_OVERLAP. */
+ return TEST_true(ret == OPENSSL_NPN_NEGOTIATED || ret == OPENSSL_NPN_NO_OVERLAP)
+ ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_ALERT_FATAL;
+}
+
+static int server_npn_cb(SSL *s, const unsigned char **data,
+ unsigned int *len, void *arg)
+{
+ CTX_DATA *ctx_data = (CTX_DATA*)(arg);
+ *data = ctx_data->npn_protocols;
+ *len = ctx_data->npn_protocols_len;
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+/*
+ * The server SHOULD select the most highly preferred protocol that it supports
+ * and that is also advertised by the client. In the event that the server
+ * supports no protocols that the client advertises, then the server SHALL
+ * respond with a fatal "no_application_protocol" alert.
+ */
+static int server_alpn_cb(SSL *s, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in,
+ unsigned int inlen, void *arg)
+{
+ CTX_DATA *ctx_data = (CTX_DATA*)(arg);
+ int ret;
+
+ /* SSL_select_next_proto isn't const-correct... */
+ unsigned char *tmp_out;
+
+ /*
+ * The result points either to |in| or to |ctx_data->alpn_protocols|.
+ * The callback is allowed to point to |in| or to a long-lived buffer,
+ * so we can return directly without storing a copy.
+ */
+ ret = SSL_select_next_proto(&tmp_out, outlen,
+ ctx_data->alpn_protocols,
+ ctx_data->alpn_protocols_len, in, inlen);
+
+ *out = tmp_out;
+ /* Unlike NPN, we don't tolerate a mismatch. */
+ return ret == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK
+ : SSL_TLSEXT_ERR_ALERT_FATAL;
+}
+
+#ifndef OPENSSL_NO_SRP
+static char *client_srp_cb(SSL *s, void *arg)
+{
+ CTX_DATA *ctx_data = (CTX_DATA*)(arg);
+ return OPENSSL_strdup(ctx_data->srp_password);
+}
+
+static int server_srp_cb(SSL *s, int *ad, void *arg)
+{
+ CTX_DATA *ctx_data = (CTX_DATA*)(arg);
+ if (strcmp(ctx_data->srp_user, SSL_get_srp_username(s)) != 0)
+ return SSL3_AL_FATAL;
+ if (SSL_set_srp_server_param_pw(s, ctx_data->srp_user,
+ ctx_data->srp_password,
+ "2048" /* known group */) < 0) {
+ *ad = SSL_AD_INTERNAL_ERROR;
+ return SSL3_AL_FATAL;
+ }
+ return SSL_ERROR_NONE;
+}
+#endif /* !OPENSSL_NO_SRP */
+
+static int generate_session_ticket_cb(SSL *s, void *arg)
+{
+ CTX_DATA *server_ctx_data = arg;
+ SSL_SESSION *ss = SSL_get_session(s);
+ char *app_data = server_ctx_data->session_ticket_app_data;
+
+ if (ss == NULL || app_data == NULL)
+ return 0;
+
+ return SSL_SESSION_set1_ticket_appdata(ss, app_data, strlen(app_data));
+}
+
+static int decrypt_session_ticket_cb(SSL *s, SSL_SESSION *ss,
+ const unsigned char *keyname,
+ size_t keyname_len,
+ SSL_TICKET_STATUS status,
+ void *arg)
+{
+ switch (status) {
+ case SSL_TICKET_EMPTY:
+ case SSL_TICKET_NO_DECRYPT:
+ return SSL_TICKET_RETURN_IGNORE_RENEW;
+ case SSL_TICKET_SUCCESS:
+ return SSL_TICKET_RETURN_USE;
+ case SSL_TICKET_SUCCESS_RENEW:
+ return SSL_TICKET_RETURN_USE_RENEW;
+ default:
+ break;
+ }
+ return SSL_TICKET_RETURN_ABORT;
+}
+
+/*
+ * Configure callbacks and other properties that can't be set directly
+ * in the server/client CONF.
+ */
+static int configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
+ SSL_CTX *client_ctx,
+ const SSL_TEST_CTX *test,
+ const SSL_TEST_EXTRA_CONF *extra,
+ CTX_DATA *server_ctx_data,
+ CTX_DATA *server2_ctx_data,
+ CTX_DATA *client_ctx_data)
+{
+ unsigned char *ticket_keys;
+ size_t ticket_key_len;
+
+ if (!TEST_int_eq(SSL_CTX_set_max_send_fragment(server_ctx,
+ test->max_fragment_size), 1))
+ goto err;
+ if (server2_ctx != NULL) {
+ if (!TEST_int_eq(SSL_CTX_set_max_send_fragment(server2_ctx,
+ test->max_fragment_size),
+ 1))
+ goto err;
+ }
+ if (!TEST_int_eq(SSL_CTX_set_max_send_fragment(client_ctx,
+ test->max_fragment_size), 1))
+ goto err;
+
+ switch (extra->client.verify_callback) {
+ case SSL_TEST_VERIFY_ACCEPT_ALL:
+ SSL_CTX_set_cert_verify_callback(client_ctx, &verify_accept_cb, NULL);
+ break;
+ case SSL_TEST_VERIFY_REJECT_ALL:
+ SSL_CTX_set_cert_verify_callback(client_ctx, &verify_reject_cb, NULL);
+ break;
+ case SSL_TEST_VERIFY_NONE:
+ break;
+ }
+
+ switch (extra->client.max_fragment_len_mode) {
+ case TLSEXT_max_fragment_length_512:
+ case TLSEXT_max_fragment_length_1024:
+ case TLSEXT_max_fragment_length_2048:
+ case TLSEXT_max_fragment_length_4096:
+ case TLSEXT_max_fragment_length_DISABLED:
+ SSL_CTX_set_tlsext_max_fragment_length(
+ client_ctx, extra->client.max_fragment_len_mode);
+ break;
+ }
+
+ /*
+ * Link the two contexts for SNI purposes.
+ * Also do ClientHello callbacks here, as setting both ClientHello and SNI
+ * is bad.
+ */
+ switch (extra->server.servername_callback) {
+ case SSL_TEST_SERVERNAME_IGNORE_MISMATCH:
+ SSL_CTX_set_tlsext_servername_callback(server_ctx, servername_ignore_cb);
+ SSL_CTX_set_tlsext_servername_arg(server_ctx, server2_ctx);
+ break;
+ case SSL_TEST_SERVERNAME_REJECT_MISMATCH:
+ SSL_CTX_set_tlsext_servername_callback(server_ctx, servername_reject_cb);
+ SSL_CTX_set_tlsext_servername_arg(server_ctx, server2_ctx);
+ break;
+ case SSL_TEST_SERVERNAME_CB_NONE:
+ break;
+ case SSL_TEST_SERVERNAME_CLIENT_HELLO_IGNORE_MISMATCH:
+ SSL_CTX_set_client_hello_cb(server_ctx, client_hello_ignore_cb, server2_ctx);
+ break;
+ case SSL_TEST_SERVERNAME_CLIENT_HELLO_REJECT_MISMATCH:
+ SSL_CTX_set_client_hello_cb(server_ctx, client_hello_reject_cb, server2_ctx);
+ break;
+ case SSL_TEST_SERVERNAME_CLIENT_HELLO_NO_V12:
+ SSL_CTX_set_client_hello_cb(server_ctx, client_hello_nov12_cb, server2_ctx);
+ }
+
+ if (extra->server.cert_status != SSL_TEST_CERT_STATUS_NONE) {
+ SSL_CTX_set_tlsext_status_type(client_ctx, TLSEXT_STATUSTYPE_ocsp);
+ SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb);
+ SSL_CTX_set_tlsext_status_arg(client_ctx, NULL);
+ SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb);
+ SSL_CTX_set_tlsext_status_arg(server_ctx,
+ ((extra->server.cert_status == SSL_TEST_CERT_STATUS_GOOD_RESPONSE)
+ ? &dummy_ocsp_resp_good_val : &dummy_ocsp_resp_bad_val));
+ }
+
+ /*
+ * The initial_ctx/session_ctx always handles the encrypt/decrypt of the
+ * session ticket. This ticket_key callback is assigned to the second
+ * session (assigned via SNI), and should never be invoked
+ */
+ if (server2_ctx != NULL)
+ SSL_CTX_set_tlsext_ticket_key_evp_cb(server2_ctx,
+ do_not_call_session_ticket_cb);
+
+ if (extra->server.broken_session_ticket) {
+ SSL_CTX_set_tlsext_ticket_key_evp_cb(server_ctx,
+ broken_session_ticket_cb);
+ }
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ if (extra->server.npn_protocols != NULL) {
+ if (!TEST_true(parse_protos(extra->server.npn_protocols,
+ &server_ctx_data->npn_protocols,
+ &server_ctx_data->npn_protocols_len)))
+ goto err;
+ SSL_CTX_set_npn_advertised_cb(server_ctx, server_npn_cb,
+ server_ctx_data);
+ }
+ if (extra->server2.npn_protocols != NULL) {
+ if (!TEST_true(parse_protos(extra->server2.npn_protocols,
+ &server2_ctx_data->npn_protocols,
+ &server2_ctx_data->npn_protocols_len))
+ || !TEST_ptr(server2_ctx))
+ goto err;
+ SSL_CTX_set_npn_advertised_cb(server2_ctx, server_npn_cb,
+ server2_ctx_data);
+ }
+ if (extra->client.npn_protocols != NULL) {
+ if (!TEST_true(parse_protos(extra->client.npn_protocols,
+ &client_ctx_data->npn_protocols,
+ &client_ctx_data->npn_protocols_len)))
+ goto err;
+ SSL_CTX_set_next_proto_select_cb(client_ctx, client_npn_cb,
+ client_ctx_data);
+ }
+#endif
+ if (extra->server.alpn_protocols != NULL) {
+ if (!TEST_true(parse_protos(extra->server.alpn_protocols,
+ &server_ctx_data->alpn_protocols,
+ &server_ctx_data->alpn_protocols_len)))
+ goto err;
+ SSL_CTX_set_alpn_select_cb(server_ctx, server_alpn_cb, server_ctx_data);
+ }
+ if (extra->server2.alpn_protocols != NULL) {
+ if (!TEST_ptr(server2_ctx)
+ || !TEST_true(parse_protos(extra->server2.alpn_protocols,
+ &server2_ctx_data->alpn_protocols,
+ &server2_ctx_data->alpn_protocols_len
+ )))
+ goto err;
+ SSL_CTX_set_alpn_select_cb(server2_ctx, server_alpn_cb,
+ server2_ctx_data);
+ }
+ if (extra->client.alpn_protocols != NULL) {
+ unsigned char *alpn_protos = NULL;
+ size_t alpn_protos_len = 0;
+
+ if (!TEST_true(parse_protos(extra->client.alpn_protocols,
+ &alpn_protos, &alpn_protos_len))
+ /* Reversed return value convention... */
+ || !TEST_int_eq(SSL_CTX_set_alpn_protos(client_ctx, alpn_protos,
+ alpn_protos_len), 0))
+ goto err;
+ OPENSSL_free(alpn_protos);
+ }
+
+ if (extra->server.session_ticket_app_data != NULL) {
+ server_ctx_data->session_ticket_app_data =
+ OPENSSL_strdup(extra->server.session_ticket_app_data);
+ SSL_CTX_set_session_ticket_cb(server_ctx, generate_session_ticket_cb,
+ decrypt_session_ticket_cb, server_ctx_data);
+ }
+ if (extra->server2.session_ticket_app_data != NULL) {
+ if (!TEST_ptr(server2_ctx))
+ goto err;
+ server2_ctx_data->session_ticket_app_data =
+ OPENSSL_strdup(extra->server2.session_ticket_app_data);
+ SSL_CTX_set_session_ticket_cb(server2_ctx, NULL,
+ decrypt_session_ticket_cb, server2_ctx_data);
+ }
+
+ /*
+ * Use fixed session ticket keys so that we can decrypt a ticket created with
+ * one CTX in another CTX. Don't address server2 for the moment.
+ */
+ ticket_key_len = SSL_CTX_set_tlsext_ticket_keys(server_ctx, NULL, 0);
+ if (!TEST_ptr(ticket_keys = OPENSSL_zalloc(ticket_key_len))
+ || !TEST_int_eq(SSL_CTX_set_tlsext_ticket_keys(server_ctx,
+ ticket_keys,
+ ticket_key_len), 1)) {
+ OPENSSL_free(ticket_keys);
+ goto err;
+ }
+ OPENSSL_free(ticket_keys);
+
+ /* The default log list includes EC keys, so CT can't work without EC. */
+#if !defined(OPENSSL_NO_CT) && !defined(OPENSSL_NO_EC)
+ if (!TEST_true(SSL_CTX_set_default_ctlog_list_file(client_ctx)))
+ goto err;
+ switch (extra->client.ct_validation) {
+ case SSL_TEST_CT_VALIDATION_PERMISSIVE:
+ if (!TEST_true(SSL_CTX_enable_ct(client_ctx,
+ SSL_CT_VALIDATION_PERMISSIVE)))
+ goto err;
+ break;
+ case SSL_TEST_CT_VALIDATION_STRICT:
+ if (!TEST_true(SSL_CTX_enable_ct(client_ctx, SSL_CT_VALIDATION_STRICT)))
+ goto err;
+ break;
+ case SSL_TEST_CT_VALIDATION_NONE:
+ break;
+ }
+#endif
+#ifndef OPENSSL_NO_SRP
+ if (extra->server.srp_user != NULL) {
+ SSL_CTX_set_srp_username_callback(server_ctx, server_srp_cb);
+ server_ctx_data->srp_user = OPENSSL_strdup(extra->server.srp_user);
+ server_ctx_data->srp_password = OPENSSL_strdup(extra->server.srp_password);
+ SSL_CTX_set_srp_cb_arg(server_ctx, server_ctx_data);
+ }
+ if (extra->server2.srp_user != NULL) {
+ if (!TEST_ptr(server2_ctx))
+ goto err;
+ SSL_CTX_set_srp_username_callback(server2_ctx, server_srp_cb);
+ server2_ctx_data->srp_user = OPENSSL_strdup(extra->server2.srp_user);
+ server2_ctx_data->srp_password = OPENSSL_strdup(extra->server2.srp_password);
+ SSL_CTX_set_srp_cb_arg(server2_ctx, server2_ctx_data);
+ }
+ if (extra->client.srp_user != NULL) {
+ if (!TEST_true(SSL_CTX_set_srp_username(client_ctx,
+ extra->client.srp_user)))
+ goto err;
+ SSL_CTX_set_srp_client_pwd_callback(client_ctx, client_srp_cb);
+ client_ctx_data->srp_password = OPENSSL_strdup(extra->client.srp_password);
+ SSL_CTX_set_srp_cb_arg(client_ctx, client_ctx_data);
+ }
+#endif /* !OPENSSL_NO_SRP */
+ return 1;
+err:
+ return 0;
+}
+
+/* Configure per-SSL callbacks and other properties. */
+static void configure_handshake_ssl(SSL *server, SSL *client,
+ const SSL_TEST_EXTRA_CONF *extra)
+{
+ if (extra->client.servername != SSL_TEST_SERVERNAME_NONE)
+ SSL_set_tlsext_host_name(client,
+ ssl_servername_name(extra->client.servername));
+ if (extra->client.enable_pha)