Fix wolfSSL_set_SSL_CTX() to be usable during handshake.

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.
This commit is contained in:
Stefan Eissing
2022-12-15 09:33:01 +01:00
parent a3f3c76faa
commit 78fd5d7dbc
2 changed files with 154 additions and 2 deletions

View File

@@ -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;
}

View File

@@ -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),