diff --git a/src/ssl.c b/src/ssl.c index fc09d9810..61d60b583 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -31987,9 +31987,68 @@ const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) { - if (ssl && ctx && SetSSL_CTX(ssl, ctx, 0) == WOLFSSL_SUCCESS) + /* This method requires some explanation. Its sibling is + * int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) + * which re-inits the WOLFSSL* with all settings in the new CTX. + * That one is the right one to use *before* a handshake is started. + * + * This method was added by OpenSSL to be used *during* the handshake, e.g. + * when a server inspects the SNI in a ClientHello callback and + * decides which set of certificates to use. + * + * Since, at the time the SNI callback is run, some decisions on + * Extensions or the ServerHello might already have been taken, this + * method is very restricted in what it does: + * - changing the server certificate(s) + * - changing the server id for session handling + * and everything else in WOLFSSL* needs to remain untouched. + */ + WOLFSSL_ENTER("wolfSSL_set_SSL_CTX"); + if (ssl == NULL || ctx == NULL) + return NULL; + if (ssl->ctx == ctx) return ssl->ctx; - return NULL; + + if (SSL_CTX_RefCount(ctx, 1) < 0) { + /* can only fail on serious stuff, like mutex not working + * or ctx refcount out of whack. */ + return NULL; + } + if (ssl->ctx) { + wolfSSL_CTX_free(ssl->ctx); + } + ssl->ctx = ctx; + +#ifndef NO_CERTS + /* ctx owns certificate, certChain and key */ + ssl->buffers.certificate = ctx->certificate; + ssl->buffers.certChain = ctx->certChain; +#ifdef WOLFSSL_TLS13 + ssl->buffers.certChainCnt = ctx->certChainCnt; +#endif + ssl->buffers.key = ctx->privateKey; + ssl->buffers.keyType = ctx->privateKeyType; + ssl->buffers.keyId = ctx->privateKeyId; + ssl->buffers.keyLabel = ctx->privateKeyLabel; + ssl->buffers.keySz = ctx->privateKeySz; + ssl->buffers.keyDevId = ctx->privateKeyDevId; + /* flags indicating what certs/keys are available */ + ssl->options.haveRSA = ctx->haveRSA; + ssl->options.haveDH = ctx->haveDH; + ssl->options.haveECDSAsig = ctx->haveECDSAsig; + ssl->options.haveECC = ctx->haveECC; + ssl->options.haveStaticECC = ctx->haveStaticECC; + ssl->options.haveFalconSig = ctx->haveFalconSig; + ssl->options.haveDilithiumSig = ctx->haveDilithiumSig; +#endif + +#ifdef OPENSSL_EXTRA + /* copy over application session context ID */ + ssl->sessionCtxSz = ctx->sessionCtxSz; + XMEMCPY(ssl->sessionCtx, ctx->sessionCtx, ctx->sessionCtxSz); +#endif + + return ssl->ctx; } diff --git a/tests/api.c b/tests/api.c index 43ced5e44..6099083a8 100644 --- a/tests/api.c +++ b/tests/api.c @@ -57299,6 +57299,93 @@ static int test_wolfSSL_CTX_get_min_proto_version(void) return res; } +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) +static int test_wolfSSL_set_SSL_CTX(void) +{ + int res = TEST_SKIPPED; +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) \ + && !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_TLS13) + WOLFSSL_CTX *ctx1, *ctx2; + WOLFSSL *ssl; + const byte *session_id1 = (const byte *)"CTX1"; + const byte *session_id2 = (const byte *)"CTX2"; + + AssertNotNull(ctx1 = wolfSSL_CTX_new(wolfTLS_server_method())); + AssertTrue(wolfSSL_CTX_use_certificate_file(ctx1, svrCertFile, + WOLFSSL_FILETYPE_PEM)); + AssertTrue(wolfSSL_CTX_use_PrivateKey_file(ctx1, svrKeyFile, + WOLFSSL_FILETYPE_PEM)); + AssertIntEQ(wolfSSL_CTX_set_min_proto_version(ctx1, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_get_min_proto_version(ctx1), TLS1_2_VERSION); + AssertIntEQ(wolfSSL_CTX_get_max_proto_version(ctx1), TLS1_3_VERSION); + AssertIntEQ(wolfSSL_CTX_set_session_id_context(ctx1, session_id1, 4), + WOLFSSL_SUCCESS); + + AssertNotNull(ctx2 = wolfSSL_CTX_new(wolfTLS_server_method())); + AssertTrue(wolfSSL_CTX_use_certificate_file(ctx2, svrCertFile, + WOLFSSL_FILETYPE_PEM)); + AssertTrue(wolfSSL_CTX_use_PrivateKey_file(ctx2, svrKeyFile, + WOLFSSL_FILETYPE_PEM)); + AssertIntEQ(wolfSSL_CTX_set_min_proto_version(ctx2, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_set_max_proto_version(ctx2, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_get_min_proto_version(ctx2), TLS1_2_VERSION); + AssertIntEQ(wolfSSL_CTX_get_max_proto_version(ctx2), TLS1_2_VERSION); + AssertIntEQ(wolfSSL_CTX_set_session_id_context(ctx2, session_id2, 4), + WOLFSSL_SUCCESS); + +#ifdef HAVE_SESSION_TICKET + AssertIntEQ((wolfSSL_CTX_get_options(ctx1) & SSL_OP_NO_TICKET), 0); + wolfSSL_CTX_set_options(ctx2, SSL_OP_NO_TICKET); + AssertIntNE((wolfSSL_CTX_get_options(ctx2) & SSL_OP_NO_TICKET), 0); +#endif + + AssertNotNull(ssl = wolfSSL_new(ctx2)); + AssertIntNE((wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_3), 0); +#ifdef WOLFSSL_INT_H + AssertIntEQ(XMEMCMP(ssl->sessionCtx, session_id2, 4), 0); + AssertTrue(ssl->buffers.certificate == ctx2->certificate); + AssertTrue(ssl->buffers.certChain == ctx2->certChain); +#endif + +#ifdef HAVE_SESSION_TICKET + AssertIntNE((wolfSSL_get_options(ssl) & SSL_OP_NO_TICKET), 0); +#endif + + /* Set the ctx1 that has TLSv1.3 as max proto version */ + AssertNotNull(wolfSSL_set_SSL_CTX(ssl, ctx1)); + + /* MUST not change proto versions of ssl */ + AssertIntNE((wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_3), 0); +#ifdef HAVE_SESSION_TICKET + /* MUST not change */ + AssertIntNE((wolfSSL_get_options(ssl) & SSL_OP_NO_TICKET), 0); +#endif + /* MUST change */ +#ifdef WOLFSSL_INT_H + AssertTrue(ssl->buffers.certificate == ctx1->certificate); + AssertTrue(ssl->buffers.certChain == ctx1->certChain); + AssertIntEQ(XMEMCMP(ssl->sessionCtx, session_id1, 4), 0); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx1); + wolfSSL_CTX_free(ctx2); + + res = TEST_RES_CHECK(1); +#endif /* defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) */ + return res; +} +#endif /* defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) */ + static int test_wolfSSL_security_level(void) { int res = TEST_SKIPPED; @@ -60062,6 +60149,12 @@ TEST_CASE testCases[] = { #endif TEST_DECL(test_wolfSSL_CTX_get_min_proto_version), +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) + TEST_DECL(test_wolfSSL_set_SSL_CTX), +#endif TEST_DECL(test_wolfSSL_security_level), TEST_DECL(test_wolfSSL_SSL_in_init),