diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 4328cbe7411..26d2d13ed29 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -6733,6 +6733,9 @@ long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg( | SSL_OP_NO_TLSv1_1 | Disable TLS 1.1 | | SSL_OP_NO_TLSv1_2 | Disable TLS 1.2 | | SSL_OP_NO_TLSv1_3 | Disable TLS 1.3 (requires WOLFSSL_TLS13) | + | SSL_OP_NO_DTLSv1 | Disable DTLS 1.0; same bit as SSL_OP_NO_TLSv1_1, so it disables TLS 1.1 on a TLS object | + | SSL_OP_NO_DTLSv1_2 | Disable DTLS 1.2; same bit as SSL_OP_NO_TLSv1_2 | + | SSL_OP_NO_DTLSv1_3 | Disable DTLS 1.3 (requires WOLFSSL_DTLS13); same bit as SSL_OP_NO_TLSv1_3 | | SSL_OP_NO_COMPRESSION | Disable record-layer compression (no-op unless HAVE_LIBZ) | | SSL_OP_NO_TICKET | Disable RFC 5077 session tickets (TLS 1.2 only; TLS 1.3 ignores this flag); requires HAVE_SESSION_TICKET and (OPENSSL_EXTRA or HAVE_WEBSERVER or WOLFSSL_WPAS_SMALL) | | SSL_OP_NO_RENEGOTIATION | Reject peer-initiated renegotiation | diff --git a/src/internal.c b/src/internal.c index 4a6d962be7d..6942994d81c 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2816,10 +2816,6 @@ void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv) method->downgrade = 0; } -#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) -static int InitSSL_DtlsServer(WOLFSSL* ssl); -#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ - #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) || \ defined(WOLFSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) int InitSSL_Side(WOLFSSL* ssl, word16 side) @@ -8075,6 +8071,61 @@ int InitSSL_Suites(WOLFSSL* ssl) return WOLFSSL_SUCCESS; } +#ifdef WOLFSSL_DTLS +/* Maps a TLS minimum to the DTLS version that shares its mask bit. */ +byte DtlsMinDowngrade(byte minDowngrade) +{ + if (minDowngrade == TLSv1_3_MINOR) + return DTLSv1_3_MINOR; + if (minDowngrade == TLSv1_2_MINOR) + return DTLSv1_2_MINOR; + if (minDowngrade < DTLSv1_3_MINOR) + return DTLS_MINOR; + return minDowngrade; +} + +/* Returns the newest built DTLS minor, no newer than maxMinor, that the version + * mask and minDowngrade allow, or 0. DTLS minors count down. */ +byte DtlsMaskAllowedMinor(unsigned long mask, byte maxMinor, byte minDowngrade) +{ +#ifdef WOLFSSL_DTLS13 + if (maxMinor <= DTLSv1_3_MINOR && + (mask & WOLFSSL_OP_NO_TLSv1_3) == 0) { + return DTLSv1_3_MINOR; + } +#endif +#ifndef WOLFSSL_NO_TLS12 + if (maxMinor <= DTLSv1_2_MINOR && + (mask & WOLFSSL_OP_NO_TLSv1_2) == 0 && + minDowngrade >= DTLSv1_2_MINOR) { + return DTLSv1_2_MINOR; + } +#endif +#ifndef NO_OLD_TLS + if ((mask & WOLFSSL_OP_NO_TLSv1_1) == 0 && + minDowngrade >= DTLS_MINOR) { + return DTLS_MINOR; + } +#endif + (void)mask; + (void)maxMinor; + (void)minDowngrade; + return 0; +} + +/* DtlsMaskAllowedMinor() with the SSL's own version mask. */ +byte DtlsAllowedMinor(const WOLFSSL* ssl, byte maxMinor, byte minDowngrade) +{ +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ + defined(WOLFSSL_WPAS_SMALL) + return DtlsMaskAllowedMinor(ssl->options.mask, maxMinor, minDowngrade); +#else + (void)ssl; + return DtlsMaskAllowedMinor(0, maxMinor, minDowngrade); +#endif +} +#endif + /* This function inherits a WOLFSSL_CTX's fields into an SSL object. It is used during initialization and to switch an ssl's CTX with wolfSSL_Set_SSL_CTX. Requires ssl->suites alloc and ssl-arrays with PSK @@ -8103,6 +8154,25 @@ static int SetSSL_CTX_CheckVersion(WOLFSSL* ssl, WOLFSSL_CTX* ctx) ssl->version.minor = TLSv1_2_MINOR; } #endif + #ifdef WOLFSSL_DTLS13 + if (ssl->version.major == DTLS_MAJOR && + ssl->version.minor == DTLSv1_3_MINOR && + (ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3) == + WOLFSSL_OP_NO_TLSv1_3) { + byte minor = 0; + + if (ctx->method->downgrade) + minor = DtlsAllowedMinor(ssl, DTLSv1_2_MINOR, ctx->minDowngrade); + if (minor == 0) { + WOLFSSL_MSG("\tInconsistent protocol options. DTLS 1.3 set but " + "not allowed and no lower DTLS version allowed."); + WOLFSSL_ERROR_VERBOSE(VERSION_ERROR); + return VERSION_ERROR; + } + WOLFSSL_MSG("\tOption set to not allow DTLSv1.3, Downgrading"); + ssl->version.minor = minor; + } + #endif if (ssl->version.minor == TLSv1_2_MINOR && (ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) { if (!ctx->method->downgrade) { @@ -9044,7 +9114,7 @@ static void InitSSL_Tls13Options(WOLFSSL* ssl, WOLFSSL_CTX* ctx) * @return 0 on success, and when there is nothing to do. * @return A negative error code when a secret cannot be generated. */ -static int InitSSL_DtlsServer(WOLFSSL* ssl) +int InitSSL_DtlsServer(WOLFSSL* ssl) { int ret; @@ -36320,6 +36390,17 @@ static int IsTls13CipherSuite(byte first, byte second) } } + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls && ssl->options.downgrade && + !ssl->options.handShakeDone && + DtlsAllowedMinor(ssl, ssl->version.minor, DTLS_MINOR) != + ssl->version.minor) { + WOLFSSL_MSG("\tOption set to not allow this DTLS version"); + WOLFSSL_ERROR_VERBOSE(VERSION_ERROR); + return VERSION_ERROR; + } + #endif + /* check if option is set to not allow the current version * set from either wolfSSL_set_options or wolfSSL_CTX_set_options */ if (!ssl->options.dtls && ssl->options.downgrade && @@ -36418,6 +36499,24 @@ static int IsTls13CipherSuite(byte first, byte second) } #endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) + if (ssl->options.echAccepted && + ssl->msgsReceived.got_hello_retry_request) { + WOLFSSL_MSG("ECH accepted in HelloRetryRequest, ServerHello is " + "not TLS 1.3"); + WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); + if (SendAlert(ssl, alert_fatal, illegal_parameter) == + WC_NO_ERR_TRACE(SOCKET_ERROR_E)) { + return SOCKET_ERROR_E; + } + return INVALID_PARAMETER; + } + /* A server negotiating TLS 1.2 or older answers the outer hello. */ + ret = TLSX_EchReplaceExtensions(ssl, 0); + if (ret != 0) + return ret; +#endif + /* random */ XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); i += RAN_LEN; @@ -43124,6 +43223,20 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) TRUE, TRUE, TRUE, TRUE, ssl->options.side); } + #ifdef WOLFSSL_DTLS + ret = DtlsCheckVersionMask(ssl, DTLS_MASK_IN_HELLO); + if (ret == WC_NO_ERR_TRACE(VERSION_ERROR)) { + WOLFSSL_ERROR_VERBOSE(VERSION_ERROR); + /* propagate socket errors to avoid re-calling send alert */ + if (SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version) + == WC_NO_ERR_TRACE(SOCKET_ERROR_E)) { + ret = SOCKET_ERROR_E; + } + } + if (ret != 0) + goto out; + #endif + /* Version the record layer is on before the mask walk below steps it * down. It is one the client offered (or the server's own maximum * when the client offered more), so the two alert exits inside that diff --git a/src/ssl.c b/src/ssl.c index d4dfe1afee7..aaf3d80cd85 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2163,9 +2163,18 @@ int wolfSSL_clear_group_messages(WOLFSSL* ssl) } /* make minVersion the internal equivalent SSL version */ -static int SetMinVersionHelper(byte* minVersion, int version) +static int SetMinVersionHelper(byte* minVersion, int version, byte major) { (void)minVersion; + (void)major; + +#ifdef WOLFSSL_DTLS + if ((version == WOLFSSL_DTLSV1 || version == WOLFSSL_DTLSV1_2 || + version == WOLFSSL_DTLSV1_3) && major != DTLS_MAJOR) { + WOLFSSL_MSG("Mismatched protocol version"); + return BAD_FUNC_ARG; + } +#endif switch (version) { #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) @@ -2216,6 +2225,10 @@ static int SetMinVersionHelper(byte* minVersion, int version) WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; } +#ifdef WOLFSSL_DTLS + if (major == DTLS_MAJOR) + *minVersion = DtlsMinDowngrade(*minVersion); +#endif return WOLFSSL_SUCCESS; } @@ -2240,7 +2253,8 @@ int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) } #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - ret = SetMinVersionHelper(&ctx->minDowngrade, version); + ret = SetMinVersionHelper(&ctx->minDowngrade, version, + ctx->method->version.major); if (ret == WOLFSSL_SUCCESS) ctx->minVersionSet = 1; @@ -2283,7 +2297,8 @@ int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) } #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - ret = SetMinVersionHelper(&ssl->options.minDowngrade, version); + ret = SetMinVersionHelper(&ssl->options.minDowngrade, version, + ssl->version.major); if (ret == WOLFSSL_SUCCESS) { ssl->options.minVersionSet = 1; RestoreDowngrade(ssl); @@ -4890,6 +4905,95 @@ size_t wolfSSL_get_server_random(const WOLFSSL *ssl, unsigned char *out, #endif /* !NO_WOLFSSL_SERVER */ #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || HAVE_SECRET_CALLBACK */ +#ifdef WOLFSSL_DTLS +/* Returns 1 once the first handshake has started, including a first + * ClientHello that is still being built, sent or parsed. */ +static int DtlsHandshakeStarted(const WOLFSSL* ssl) +{ + int ret; + + ret = ssl->options.handShakeDone || + ssl->options.connectState != CONNECT_BEGIN || + ssl->options.acceptState != ACCEPT_BEGIN || + ssl->msgsReceived.got_client_hello || + ssl->buffers.outputBuffer.length > 0; +#ifdef WOLFSSL_ASYNC_CRYPT + if (ssl->options.asyncState != TLS_ASYNC_BEGIN || + (ssl->async != NULL && ssl->async->freeArgs != NULL)) + ret = 1; +#endif + return ret; +} + +/* Steps a DTLS SSL that may downgrade to a version its mask allows, or up to + * the method version for a lift. Returns 1 if it moved, 0, or VERSION_ERROR. */ +static int DtlsMaskVersion(WOLFSSL* ssl, enum DtlsMaskMode mode) +{ + byte maxMinor = ssl->version.minor; + byte resuming = (byte)(ssl->options.resuming && + ssl->options.side == WOLFSSL_CLIENT_END); + byte allowed; + byte minor; + + if (ssl->version.major != DTLS_MAJOR || !ssl->options.downgrade || + ssl->options.handShakeDone) { + return 0; + } + if (mode == DTLS_MASK_IN_HELLO) { + if (ssl->options.connectState != CONNECT_BEGIN || + ssl->options.acceptState != ACCEPT_BEGIN) { + return 0; + } + } + else if (DtlsHandshakeStarted(ssl)) { + return 0; + } + allowed = (byte)(DtlsAllowedMinor(ssl, ssl->version.minor, + ssl->options.minDowngrade) == ssl->version.minor); + if (allowed && (mode != DTLS_MASK_LIFT || resuming)) + return 0; + /* Lifts walk from the method; a resumed session lowered the version. */ + if (mode == DTLS_MASK_LIFT || resuming) + maxMinor = ssl->ctx->method->version.minor; + minor = DtlsAllowedMinor(ssl, maxMinor, ssl->options.minDowngrade); + if (minor == 0 && !allowed) { + WOLFSSL_MSG("No DTLS version left that the options allow"); + return VERSION_ERROR; + } + /* A lift never moves an allowed version down; DTLS minors count down. */ + if (minor == ssl->version.minor || + (allowed && (minor == 0 || minor > ssl->version.minor))) + return 0; + ssl->version.minor = minor; + ssl->options.tls1_3 = 0; + if (resuming && ssl->session != NULL && + ssl->session->version.minor != minor) { + ssl->options.resuming = 0; + #ifdef HAVE_EXTENDED_MASTER + ssl->options.haveEMS = !ssl->options.disableEMS; + #endif + } + return 1; +} + +/* Applies the DTLS version mask and rebuilds the suites when the version + * moved. Returns VERSION_ERROR when no version is left. */ +int DtlsCheckVersionMask(WOLFSSL* ssl, enum DtlsMaskMode mode) +{ + int ret = DtlsMaskVersion(ssl, mode); + + if (ret == 1) { + ret = ResetSuitesForVersion(ssl); + #ifndef NO_WOLFSSL_SERVER + if (ret == 0 && ssl->options.side == WOLFSSL_SERVER_END && + IsAtLeastTLSv1_3(ssl->version)) + ret = InitSSL_DtlsServer(ssl); + #endif + } + return ret; +} +#endif + #ifdef OPENSSL_EXTRA #if !defined(NO_WOLFSSL_SERVER) /* Used to get the peer ephemeral public key sent during the connection @@ -5062,7 +5166,10 @@ static const int protoVerTbl[] = { TLS1_2_VERSION, TLS1_3_VERSION, DTLS1_VERSION, - DTLS1_2_VERSION + DTLS1_2_VERSION, +#ifdef WOLFSSL_DTLS13 + DTLS1_3_VERSION, +#endif }; /* number of protocol versions listed in protoVerTbl */ #define NUMBER_OF_PROTOCOLS (sizeof(protoVerTbl)/sizeof(int)) @@ -5086,6 +5193,7 @@ static const int protoVerTbl[] = { * * TLS1_3_VERSION * * DTLS1_VERSION * * DTLS1_2_VERSION + * * DTLS1_3_VERSION * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ @@ -5134,11 +5242,20 @@ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) case DTLS1_2_VERSION: ctx->minDowngrade = DTLSv1_2_MINOR; break; + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + ctx->minDowngrade = DTLSv1_3_MINOR; + break; + #endif #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (ctx->method->version.major == DTLS_MAJOR) + ctx->minDowngrade = DtlsMinDowngrade(ctx->minDowngrade); +#endif switch (version) { #ifndef NO_TLS @@ -5162,6 +5279,9 @@ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + #endif break; #endif default: @@ -5187,6 +5307,13 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) if (ctx == NULL) { return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if ((version >> 8) == DTLS_MAJOR && + ctx->method->version.major != DTLS_MAJOR) { + WOLFSSL_MSG("Mismatched protocol version"); + return WOLFSSL_FAILURE; + } +#endif if (version != 0) { proto = version; @@ -5218,7 +5345,7 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) break; } } - if (idx < i) { + if (idx < i && ctx->method->version.major != DTLS_MAJOR) { wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); @@ -5252,6 +5379,7 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) * * TLS1_3_VERSION * * DTLS1_VERSION * * DTLS1_2_VERSION + * * DTLS1_3_VERSION * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ @@ -5264,6 +5392,13 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (((ver >> 8) == DTLS_MAJOR) != + (ctx->method->version.major == DTLS_MAJOR)) { + WOLFSSL_MSG("Mismatched protocol version"); + return WOLFSSL_FAILURE; + } +#endif switch (ver) { #ifndef NO_TLS @@ -5289,9 +5424,20 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) break; #endif #ifdef WOLFSSL_DTLS + #ifndef NO_OLD_TLS case DTLS1_VERSION: + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); + FALL_THROUGH; + #endif case DTLS1_2_VERSION: + #ifdef WOLFSSL_DTLS13 + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + #endif + break; + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: break; + #endif #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); @@ -5317,6 +5463,9 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + #endif if (ctx->method->version.major != DTLS_MAJOR) { WOLFSSL_MSG("Mismatched protocol version"); return WOLFSSL_FAILURE; @@ -5350,6 +5499,11 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) case DTLS1_2_VERSION: ctx->method->version.minor = DTLSv1_2_MINOR; break; + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + ctx->method->version.minor = DTLSv1_3_MINOR; + break; + #endif #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); @@ -5410,6 +5564,12 @@ static int Set_SSL_min_proto_version(WOLFSSL* ssl, int ver) if (ssl == NULL) { return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if ((ver >> 8) == DTLS_MAJOR && ssl->version.major != DTLS_MAJOR) { + WOLFSSL_MSG("Mismatched protocol version"); + return WOLFSSL_FAILURE; + } +#endif switch (ver) { #ifndef NO_TLS @@ -5448,11 +5608,20 @@ static int Set_SSL_min_proto_version(WOLFSSL* ssl, int ver) case DTLS1_2_VERSION: ssl->options.minDowngrade = DTLSv1_2_MINOR; break; + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + ssl->options.minDowngrade = DTLSv1_3_MINOR; + break; + #endif #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) + ssl->options.minDowngrade = DtlsMinDowngrade(ssl->options.minDowngrade); +#endif switch (ver) { #ifndef NO_TLS @@ -5476,6 +5645,9 @@ static int Set_SSL_min_proto_version(WOLFSSL* ssl, int ver) #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + #endif break; #endif default: @@ -5519,6 +5691,13 @@ int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int version) static int Set_SSL_max_proto_version(WOLFSSL* ssl, int ver) { +#ifdef WOLFSSL_DTLS + unsigned long mask; + unsigned long maxMask; + unsigned long want = 0; + unsigned long cleared; + int ret; +#endif WOLFSSL_ENTER("Set_SSL_max_proto_version"); @@ -5526,6 +5705,14 @@ static int Set_SSL_max_proto_version(WOLFSSL* ssl, int ver) WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (((ver >> 8) == DTLS_MAJOR) != (ssl->version.major == DTLS_MAJOR)) { + WOLFSSL_MSG("Mismatched protocol version"); + return WOLFSSL_FAILURE; + } + mask = ssl->options.mask; + maxMask = ssl->options.dtlsMaxMask; +#endif switch (ver) { case SSL2_VERSION: @@ -5549,15 +5736,52 @@ static int Set_SSL_max_proto_version(WOLFSSL* ssl, int ver) break; #endif #ifdef WOLFSSL_DTLS + #ifndef NO_OLD_TLS case DTLS1_VERSION: + want = WOLFSSL_OP_NO_TLSv1_2; + FALL_THROUGH; + #endif case DTLS1_2_VERSION: + #ifdef WOLFSSL_DTLS13 + want |= WOLFSSL_OP_NO_TLSv1_3; + #endif + break; + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: break; + #endif #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + /* Clear only the bits the previous maximum set. */ + cleared = mask & ~(maxMask & ~want); + if ((cleared | want) != mask && DtlsHandshakeStarted(ssl)) { + WOLFSSL_MSG("DTLS handshake already started"); + return WOLFSSL_FAILURE; + } + if (!ssl->options.downgrade && DtlsMaskAllowedMinor(want, + ssl->version.minor, DTLS_MINOR) != ssl->version.minor) { + WOLFSSL_MSG("Maximum below the fixed DTLS version"); + return WOLFSSL_FAILURE; + } + ssl->options.dtlsMaxMask = want & (maxMask | ~mask); + ssl->options.mask = cleared | want; + ret = DtlsCheckVersionMask(ssl, cleared != mask ? DTLS_MASK_LIFT : + DTLS_MASK_START); + if (ret != 0) { + if (ret == WC_NO_ERR_TRACE(VERSION_ERROR)) { + ssl->options.mask = mask; + ssl->options.dtlsMaxMask = maxMask; + } + return WOLFSSL_FAILURE; + } + } +#endif return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); } @@ -5571,6 +5795,15 @@ int wolfSSL_set_max_proto_version(WOLFSSL* ssl, int version) if (ssl == NULL) { return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (version == 0 && ssl->version.major == DTLS_MAJOR) { + #ifdef WOLFSSL_DTLS13 + version = DTLS1_3_VERSION; + #else + version = DTLS1_2_VERSION; + #endif + } +#endif if (version != 0) { return Set_SSL_max_proto_version(ssl, version); } @@ -5616,6 +5849,19 @@ static int GetMinProtoVersion(int minDowngrade) case TLSv1_3_MINOR: ret = TLS1_3_VERSION; break; +#endif +#ifdef WOLFSSL_DTLS + #ifndef NO_OLD_TLS + case DTLS_MINOR: + ret = DTLS1_VERSION; + break; + #endif + case DTLSv1_2_MINOR: + ret = DTLS1_2_VERSION; + break; + case DTLSv1_3_MINOR: + ret = DTLS1_3_VERSION; + break; #endif default: ret = 0; @@ -5686,6 +5932,9 @@ int wolfSSL_CTX_get_max_proto_version(WOLFSSL_CTX* ctx) { int ret = 0; long options = 0; /* default to nothing set */ +#ifdef WOLFSSL_DTLS + byte minor; +#endif WOLFSSL_ENTER("wolfSSL_CTX_get_max_proto_version"); @@ -5696,6 +5945,16 @@ int wolfSSL_CTX_get_max_proto_version(WOLFSSL_CTX* ctx) if ((ctx != NULL) && ctx->maxProto) { ret = 0; } +#ifdef WOLFSSL_DTLS + else if ((ctx != NULL) && (ctx->method->version.major == DTLS_MAJOR)) { + minor = DtlsMaskAllowedMinor((unsigned long)options, + ctx->method->version.minor, ctx->minDowngrade); + if (!ctx->method->downgrade && minor != ctx->method->version.minor) + minor = 0; + ret = (minor != 0) ? ((DTLS_MAJOR << 8) | minor) : + WOLFSSL_FATAL_ERROR; + } +#endif else { ret = GetMaxProtoVersion(options); } @@ -5901,6 +6160,9 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #ifdef WOLFSSL_DTLS ssl->options.dtlsStateful = 0; #endif + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->options.asyncState = TLS_ASYNC_BEGIN; + #endif #ifdef WOLFSSL_TLS13 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) ssl->options.pskNegotiated = 0; @@ -5921,10 +6183,8 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #endif #ifdef WOLFSSL_ASYNC_CRYPT ssl->options.buildArgs13Set = 0; - /* An abandoned handshake can leave a mid-flight handler resume - * state and a queued key-schedule event behind; a reused object - * must start fresh. */ - ssl->options.asyncState = TLS_ASYNC_BEGIN; + /* An abandoned handshake can leave a queued key-schedule event + * behind; a reused object must start fresh. */ if (ssl->asyncDev == &ssl->kdfAsyncDev) { if (ssl->kdfAsyncDev.event.state == WOLF_EVENT_STATE_PENDING && ssl->ctx != NULL) { @@ -7581,60 +7841,13 @@ static int FindHashSig(const Suites* suites, byte first, byte second) return MATCH_SUITE_ERROR; } -long wolfSSL_set_options(WOLFSSL* ssl, long op) +/* Rebuilds the cipher suites for the current protocol version. */ +int ResetSuitesForVersion(WOLFSSL* ssl) { word16 haveRSA = 1; word16 havePSK = 0; int keySz = 0; - WOLFSSL_ENTER("wolfSSL_set_options"); - - if (ssl == NULL) { - return 0; - } - - ssl->options.mask = (unsigned long)wolf_set_options((long)ssl->options.mask, op); - - if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3) == WOLFSSL_OP_NO_TLSv1_3) { - WOLFSSL_MSG("Disabling TLS 1.3"); - if (ssl->version.minor == TLSv1_3_MINOR) - ssl->version.minor = TLSv1_2_MINOR; - } - - if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) { - WOLFSSL_MSG("Disabling TLS 1.2"); - if (ssl->version.minor == TLSv1_2_MINOR) - ssl->version.minor = TLSv1_1_MINOR; - } - - if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1) == WOLFSSL_OP_NO_TLSv1_1) { - WOLFSSL_MSG("Disabling TLS 1.1"); - if (ssl->version.minor == TLSv1_1_MINOR) - ssl->version.minor = TLSv1_MINOR; - } - - if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1) == WOLFSSL_OP_NO_TLSv1) { - WOLFSSL_MSG("Disabling TLS 1.0"); - if (ssl->version.minor == TLSv1_MINOR) - ssl->version.minor = SSLv3_MINOR; - } - - if ((ssl->options.mask & WOLFSSL_OP_NO_COMPRESSION) - == WOLFSSL_OP_NO_COMPRESSION) { - #ifdef HAVE_LIBZ - ssl->options.usingCompression = 0; - #endif - } - -#if defined(HAVE_SESSION_TICKET) && (defined(OPENSSL_EXTRA) \ - || defined(HAVE_WEBSERVER) || defined(WOLFSSL_WPAS_SMALL)) - if ((ssl->options.mask & WOLFSSL_OP_NO_TICKET) == WOLFSSL_OP_NO_TICKET) { - ssl->options.noTicketTls12 = 1; - } -#endif - - - /* in the case of a version change the cipher suites should be reset */ #ifndef NO_PSK havePSK = ssl->options.havePSK; #endif @@ -7647,7 +7860,7 @@ long wolfSSL_set_options(WOLFSSL* ssl, long op) if (ssl->options.side != WOLFSSL_NEITHER_END) { if (AllocateSuites(ssl) != 0) - return 0; + return MEMORY_E; if (!ssl->suites->setSuites) { /* Client side won't set DH params, so it needs haveDH set to TRUE. */ if (ssl->options.side == WOLFSSL_CLIENT_END) @@ -7709,6 +7922,66 @@ long wolfSSL_set_options(WOLFSSL* ssl, long op) } } + return 0; +} + +long wolfSSL_set_options(WOLFSSL* ssl, long op) +{ + WOLFSSL_ENTER("wolfSSL_set_options"); + + if (ssl == NULL) { + return 0; + } + + ssl->options.mask = (unsigned long)wolf_set_options((long)ssl->options.mask, op); + + if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3) == WOLFSSL_OP_NO_TLSv1_3) { + WOLFSSL_MSG("Disabling TLS 1.3"); + if (ssl->version.minor == TLSv1_3_MINOR) + ssl->version.minor = TLSv1_2_MINOR; + } + + if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) { + WOLFSSL_MSG("Disabling TLS 1.2"); + if (ssl->version.minor == TLSv1_2_MINOR) + ssl->version.minor = TLSv1_1_MINOR; + } + + if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1) == WOLFSSL_OP_NO_TLSv1_1) { + WOLFSSL_MSG("Disabling TLS 1.1"); + if (ssl->version.minor == TLSv1_1_MINOR) + ssl->version.minor = TLSv1_MINOR; + } + + if ((ssl->options.mask & WOLFSSL_OP_NO_TLSv1) == WOLFSSL_OP_NO_TLSv1) { + WOLFSSL_MSG("Disabling TLS 1.0"); + if (ssl->version.minor == TLSv1_MINOR) + ssl->version.minor = SSLv3_MINOR; + } + + if ((ssl->options.mask & WOLFSSL_OP_NO_COMPRESSION) + == WOLFSSL_OP_NO_COMPRESSION) { + #ifdef HAVE_LIBZ + ssl->options.usingCompression = 0; + #endif + } + +#if defined(HAVE_SESSION_TICKET) && (defined(OPENSSL_EXTRA) \ + || defined(HAVE_WEBSERVER) || defined(WOLFSSL_WPAS_SMALL)) + if ((ssl->options.mask & WOLFSSL_OP_NO_TICKET) == WOLFSSL_OP_NO_TICKET) { + ssl->options.noTicketTls12 = 1; + } +#endif + +#ifdef WOLFSSL_DTLS + ssl->options.dtlsMaxMask &= (unsigned long)~op; + (void)DtlsMaskVersion(ssl, DTLS_MASK_START); +#endif + + /* in the case of a version change the cipher suites should be reset */ + if (ResetSuitesForVersion(ssl) != 0) + return 0; + return (long)ssl->options.mask; } @@ -7770,10 +8043,27 @@ int wolfSSL_SSL_renegotiate_pending(WOLFSSL *s) long wolfSSL_clear_options(WOLFSSL* ssl, long opt) { +#ifdef WOLFSSL_DTLS + unsigned long lifted; + int ret; +#endif + WOLFSSL_ENTER("wolfSSL_clear_options"); if(ssl == NULL) return WOLFSSL_FAILURE; +#ifdef WOLFSSL_DTLS + lifted = ssl->options.mask & (unsigned long)opt & + (WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); + ssl->options.dtlsMaxMask &= (unsigned long)~opt; +#endif ssl->options.mask &= (unsigned long)~opt; +#ifdef WOLFSSL_DTLS + if (lifted != 0) { + ret = DtlsCheckVersionMask(ssl, DTLS_MASK_LIFT); + if (ret != 0 && ret != WC_NO_ERR_TRACE(VERSION_ERROR)) + return 0; + } +#endif return (long)ssl->options.mask; } diff --git a/src/ssl_api_hs.c b/src/ssl_api_hs.c index 5feaff1d091..961531df9c5 100644 --- a/src/ssl_api_hs.c +++ b/src/ssl_api_hs.c @@ -394,6 +394,15 @@ int wolfSSL_connect(WOLFSSL* ssl) #endif #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + #ifdef WOLFSSL_DTLS + if (ssl->options.side == WOLFSSL_CLIENT_END && + (ret = DtlsCheckVersionMask(ssl, DTLS_MASK_START)) != 0) { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #endif + #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ defined(WOLFSSL_TLS13) return wolfSSL_connect_TLSv13(ssl); @@ -882,6 +891,15 @@ int wolfSSL_accept(WOLFSSL* ssl) } #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + #ifdef WOLFSSL_DTLS + if (ssl->options.side == WOLFSSL_SERVER_END && + (ret = DtlsCheckVersionMask(ssl, DTLS_MASK_START)) != 0) { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #endif + #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ defined(WOLFSSL_TLS13) return wolfSSL_accept_TLSv13(ssl); diff --git a/src/ssl_sess.c b/src/ssl_sess.c index ba42dea2168..0311a03b4d3 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -1733,6 +1733,9 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet; #endif +#ifdef WOLFSSL_DTLS + (void)DtlsCheckVersionMask(ssl, DTLS_MASK_START); +#endif return WOLFSSL_SUCCESS; } diff --git a/src/tls.c b/src/tls.c index 60980f51a53..3061168155f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -7480,6 +7480,12 @@ int TLSX_SupportedVersions_Parse(const WOLFSSL* ssl, const byte* input, if (versionIsLesser(isDtls, minor, ssl->options.minDowngrade)) continue; } + #ifdef WOLFSSL_DTLS + if (isDtls && ssl->options.downgrade && + DtlsAllowedMinor(ssl, minor, DTLS_MINOR) != minor) { + continue; + } + #endif if (versionIsGreater(isDtls, minor, clientGreatestMinor)) clientGreatestMinor = minor; @@ -16346,10 +16352,65 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, #ifdef HAVE_SUPPORTED_CURVES +#if defined(HAVE_ECC) && defined(HAVE_ECC_BRAINPOOL) +/* Returns 1 when a client's supported_versions would also offer a version + * before 1.3. */ +static int TLSX_PreTls13Reachable(const WOLFSSL* ssl) +{ + int ret = 0; +#if defined(WOLFSSL_TLS13) && \ + (!defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)) + byte isDtls = (byte)ssl->options.dtls; + + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.downgrade) { + #ifndef WOLFSSL_NO_TLS12 + if (versionIsLessEqual(isDtls, ssl->options.minDowngrade, + (byte)(isDtls ? DTLSv1_2_MINOR : TLSv1_2_MINOR)) + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ + defined(WOLFSSL_WPAS_SMALL) + && (ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2) == 0 + #endif + ) { + ret = 1; + } + #endif + #ifndef NO_OLD_TLS + if (versionIsLessEqual(isDtls, ssl->options.minDowngrade, + (byte)(isDtls ? DTLS_MINOR : TLSv1_1_MINOR)) + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ + defined(WOLFSSL_WPAS_SMALL) + && (ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1) == 0 + #endif + ) { + ret = 1; + } + #ifdef WOLFSSL_ALLOW_TLSV10 + if (!isDtls && (ssl->options.minDowngrade <= TLSv1_MINOR) + #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ + defined(WOLFSSL_WPAS_SMALL) + && (ssl->options.mask & WOLFSSL_OP_NO_TLSv1) == 0 + #endif + ) { + ret = 1; + } + #endif + #endif + } +#else + (void)ssl; +#endif + + return ret; +} +#endif + /* Populates the default supported groups / curves */ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) { int ret = WOLFSSL_SUCCESS; +#if defined(HAVE_ECC) && defined(HAVE_ECC_BRAINPOOL) + int preTls13; +#endif #ifdef WOLFSSL_TLS13 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (ssl->options.resuming && ssl->session->namedGroup != 0) { @@ -16370,6 +16431,12 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) } #endif /* WOLFSSL_TLS13 */ +#if defined(HAVE_ECC) && defined(HAVE_ECC_BRAINPOOL) + preTls13 = !IsAtLeastTLSv1_3(ssl->version) || + TLSX_PreTls13Reachable(ssl); + (void)preTls13; +#endif + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) && \ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) /* Prefer non-experimental PQ/T hybrid groups (only for TLS 1.3) */ @@ -16425,18 +16492,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_BRAINPOOLP512R1TLS13, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; - - /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ - if (ssl->options.downgrade && - (ssl->options.minDowngrade <= TLSv1_2_MINOR || - ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap, ssl->options.side); - if (ret != WOLFSSL_SUCCESS) return ret; - } } - else { - /* TLS 1.2 only */ + if (preTls13) { ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; @@ -16469,18 +16526,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_BRAINPOOLP384R1TLS13, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; - - /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ - if (ssl->options.downgrade && - (ssl->options.minDowngrade <= TLSv1_2_MINOR || - ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap, ssl->options.side); - if (ret != WOLFSSL_SUCCESS) return ret; - } } - else { - /* TLS 1.2 only */ + if (preTls13) { ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; @@ -16526,18 +16573,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_BRAINPOOLP256R1TLS13, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; - - /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ - if (ssl->options.downgrade && - (ssl->options.minDowngrade <= TLSv1_2_MINOR || - ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap, ssl->options.side); - if (ret != WOLFSSL_SUCCESS) return ret; - } } - else { - /* TLS 1.2 only */ + if (preTls13) { ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; @@ -16759,6 +16796,51 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) return ret; } +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && defined(HAVE_ECC) && \ + defined(HAVE_ECC_BRAINPOOL) +/* Gives the ECH outer ClientHello the full default groups list and the inner + * one, which offers only TLS 1.3, the list without the pre-1.3 groups. */ +static int TLSX_EchSplitSupportedGroups(WOLFSSL* ssl) +{ + int ret; + byte downgrade; + TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH); + TLSX* groupsX = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS); + TLSX* innerList = NULL; + TLSX* innerX = NULL; + void* data; + WOLFSSL_ECH* ech; + + /* After a HelloRetryRequest the lists stay as the first hello sent them. */ + if (echX == NULL || echX->data == NULL || groupsX == NULL || + ssl->options.userCurves || + ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE || + !TLSX_PreTls13Reachable(ssl)) { + return 0; + } + + ech = (WOLFSSL_ECH*)echX->data; + ret = TLSX_PopulateSupportedGroups(ssl, &ech->extensions); + if (ret == WOLFSSL_SUCCESS) { + downgrade = ssl->options.downgrade; + ssl->options.downgrade = 0; + ret = TLSX_PopulateSupportedGroups(ssl, &innerList); + ssl->options.downgrade = downgrade; + } + if (ret == WOLFSSL_SUCCESS) + innerX = TLSX_Find(innerList, TLSX_SUPPORTED_GROUPS); + if (innerX != NULL) { + /* Swap only the data so the outer hello keeps the GREASE ECH order. */ + data = groupsX->data; + groupsX->data = innerX->data; + innerX->data = data; + } + TLSX_FreeAll(innerList, ssl->heap); + + return (ret == WOLFSSL_SUCCESS) ? 0 : ret; +} +#endif + #endif /* HAVE_SUPPORTED_CURVES */ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) @@ -16798,7 +16880,8 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #if defined(HAVE_SUPPORTED_CURVES) if (!ssl->options.userCurves && !ssl->ctx->userCurves) { if (TLSX_Find(ssl->ctx->extensions, - TLSX_SUPPORTED_GROUPS) == NULL) { + TLSX_SUPPORTED_GROUPS) == NULL && + TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS) == NULL) { ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions); if (ret != WOLFSSL_SUCCESS) return ret; @@ -17216,6 +17299,11 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) else if (ssl->echConfigs != NULL) { ret = ECH_USE(ssl->echConfigs, &(ssl->extensions), ssl->heap, ssl->rng); + #if defined(HAVE_SUPPORTED_CURVES) && defined(HAVE_ECC) && \ + defined(HAVE_ECC_BRAINPOOL) + if (ret == 0) + ret = TLSX_EchSplitSupportedGroups(ssl); + #endif } } #endif @@ -17432,9 +17520,9 @@ static int TLSX_ECH_IsEncodable(word16 type) * 2-byte extension_type + 2-byte extension_data length + * 1-byte list length + 2*count bytes of extension types */ -static int TLSX_ECH_BuildOuterExtensions(WOLFSSL* ssl, const byte* semaphore, - byte msgType, byte* output, word16* pOffset, word16* outCount, - byte* encodeMask) +static int TLSX_ECH_BuildOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, + const byte* semaphore, byte msgType, byte* output, word16* pOffset, + word16* outCount, byte* encodeMask) { TLSX* list; TLSX* extension; @@ -17471,7 +17559,8 @@ static int TLSX_ECH_BuildOuterExtensions(WOLFSSL* ssl, const byte* semaphore, if (!IS_OFF(seen, semIdx)) continue; TURN_ON(seen, semIdx); - if (!TLSX_ECH_IsEncodable(type)) + if (!TLSX_ECH_IsEncodable(type) || + TLSX_Find(ech->extensions, (TLSX_Type)type) != NULL) continue; if (typesStart != NULL) @@ -17528,7 +17617,7 @@ static int TLSX_GetSizeWithEch(WOLFSSL* ssl, byte* semaphore, byte msgType, * `semaphore` is in/out so encodable extensions will later be ignored */ if (ret == 0 && ech != NULL && ech->type == ECH_TYPE_INNER && ech->writeEncoded) { - ret = TLSX_ECH_BuildOuterExtensions(ssl, semaphore, msgType, + ret = TLSX_ECH_BuildOuterExtensions(ssl, ech, semaphore, msgType, NULL, pLength, &count, semaphore); } if (ret == 0 && ssl->extensions) @@ -18087,7 +18176,7 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore, XMEMSET(encodeMask, 0, SEMAPHORE_SIZE); - ret = TLSX_ECH_BuildOuterExtensions(ssl, semaphore, msgType, + ret = TLSX_ECH_BuildOuterExtensions(ssl, ech, semaphore, msgType, ech->writeEncoded ? output : NULL, ech->writeEncoded ? pOffset : NULL, &count, mask); diff --git a/src/tls13.c b/src/tls13.c index 437218fefa0..8093fc1619d 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -16681,6 +16681,24 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) return WOLFSSL_FATAL_ERROR; } +#ifdef WOLFSSL_DTLS + if (ssl->options.connectState == CONNECT_BEGIN && + (ret = DtlsCheckVersionMask(ssl, DTLS_MASK_START)) != 0) { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) + if (ssl->version.major == DTLS_MAJOR && !IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.tls1_3 = 0; + #ifdef WOLFSSL_EARLY_DATA + ssl->earlyData = no_early_data; + #endif + return wolfSSL_connect(ssl); + } + #endif +#endif + /* make sure this wolfSSL object has arrays and rng setup. Protects * case where the WOLFSSL object is reused via wolfSSL_clear() */ if ((ret = ReinitSSL(ssl, ssl->ctx, 0)) != 0) { @@ -17958,6 +17976,21 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) return WOLFSSL_FATAL_ERROR; } +#ifdef WOLFSSL_DTLS + if (ssl->options.acceptState == TLS13_ACCEPT_BEGIN && + (ret = DtlsCheckVersionMask(ssl, DTLS_MASK_START)) != 0) { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) + if (ssl->version.major == DTLS_MAJOR && !IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.tls1_3 = 0; + return wolfSSL_accept(ssl); + } + #endif +#endif + /* make sure this wolfSSL object has arrays and rng setup. Protects * case where the WOLFSSL object is reused via wolfSSL_clear() */ if ((ret = ReinitSSL(ssl, ssl->ctx, 0)) != 0) { diff --git a/tests/api.c b/tests/api.c index be5c1267a4c..43c9493d094 100644 --- a/tests/api.c +++ b/tests/api.c @@ -47027,6 +47027,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_TLSX_QUIC_TP_non_quic), TEST_DECL(test_TLSX_ALPN_server_response_count), TEST_DECL(test_TLSX_SupportedCurve_empty_or_unsupported), + TEST_DECL(test_TLSX_SupportedCurve_brainpool_downgrade), TEST_DECL(test_TLSX_SignatureAlgorithmsCert_parse), TEST_DECL(test_TLSX_PointFormat_list), TEST_DECL(test_TLSX_MaxFragment_value), diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index 1219f4fbc9a..9de0aa06136 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -15603,3 +15603,1430 @@ int test_dtls_max_fragment_write(void) #endif return EXPECT_RESULT(); } + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(OPENSSL_EXTRA) +static int test_dtls13_has_tls13_suite(WOLFSSL* ssl) +{ + const Suites* suites = WOLFSSL_SUITES(ssl); + word16 i; + + for (i = 0; suites != NULL && i < suites->suiteSz; i += SUITE_LEN) { + if (suites->suites[i] == TLS13_BYTE) + return 1; + } + return 0; +} + +/* Sets opts, opts2 and opts3 in separate calls, and minVer when not 0, on the + * client or server SSL or CTX. An expVersion of 0 means no version is left. */ +static int test_dtls13_mask_case(int onServer, int onCtx, long opts, + long opts2, long opts3, int minVer, int expVersion) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx; + WOLFSSL* ssl; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ctx = onServer ? ctx_s : ctx_c; + if (onCtx && minVer != 0) + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, minVer), WOLFSSL_SUCCESS); + if (onCtx) { + (void)wolfSSL_CTX_set_options(ctx, opts); + (void)wolfSSL_CTX_set_options(ctx, opts2); + (void)wolfSSL_CTX_set_options(ctx, opts3); + } + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method); + if (onCtx && expVersion == 0) { + ExpectIntNE(ret, 0); + ExpectNull(onServer ? ssl_s : ssl_c); + } + else { + ExpectIntEQ(ret, 0); + ssl = onServer ? ssl_s : ssl_c; + if (onCtx) + ExpectIntEQ(wolfSSL_version(ssl), expVersion); + if (!onCtx && minVer != 0) + ExpectIntEQ(wolfSSL_SetMinVersion(ssl, minVer), WOLFSSL_SUCCESS); + if (!onCtx && ssl != NULL) { + (void)wolfSSL_set_options(ssl, opts); + (void)wolfSSL_set_options(ssl, opts2); + (void)wolfSSL_set_options(ssl, opts3); + if (expVersion != 0) + ExpectIntEQ(wolfSSL_version(ssl), expVersion); + } + + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (expVersion != 0) { + ExpectIntEQ(ret, 0); + ExpectIntEQ(wolfSSL_version(ssl_c), expVersion); + ExpectIntEQ(wolfSSL_version(ssl_s), expVersion); + if (expVersion != DTLS1_3_VERSION && ssl != NULL) + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl), 0); + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_1); + ExpectIntEQ(wolfSSL_version(ssl), expVersion); + } + else { + ExpectIntNE(ret, 0); + ExpectIntEQ(wolfSSL_get_error(ssl, ret), + WC_NO_ERR_TRACE(VERSION_ERROR)); + } + } + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +#ifndef WOLFSSL_NO_TLS12 +/* A DTLS server whose mask drops DTLS 1.2 refuses a DTLS 1.2-only client. */ +static int test_dtls13_mask_server_walk(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLS_server_method), 0); + if (ssl_s != NULL) { + (void)wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_1); + } + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(VERSION_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A DTLS client whose mask drops DTLS 1.2 refuses a DTLS 1.2-only server. */ +static int test_dtls13_mask_client_check(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); + if (ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_2); + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(VERSION_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A server refuses a ClientHello whose supported_versions offers DTLS 1.2 + * and nothing newer when its mask allows none of the listed versions. */ +static int test_dtls13_mask_server_sv(long clientOpts, long serverOpts) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int patched = 0; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (ssl_c != NULL && clientOpts != 0) + (void)wolfSSL_set_options(ssl_c, clientOpts); + if (ssl_s != NULL) + (void)wolfSSL_set_options(ssl_s, serverOpts); +#ifdef WOLFSSL_SEND_HRR_COOKIE + ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); +#endif + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + /* supported_versions: type, length, list length, then DTLS 1.3 first. */ + for (i = 0; EXPECT_SUCCESS() && i + 7 <= test_ctx.s_len; i++) { + if (test_ctx.s_buff[i] == 0x00 && test_ctx.s_buff[i + 1] == 0x2b && + test_ctx.s_buff[i + 5] == DTLS_MAJOR && + test_ctx.s_buff[i + 6] == DTLSv1_3_MINOR) { + test_ctx.s_buff[i + 6] = DTLSv1_2_MINOR; + patched = 1; + break; + } + } + ExpectIntEQ(patched, 1); + ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(VERSION_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +#ifdef HAVE_SESSION_TICKET +/* A session made with firstOpts and set before or after secondOpts, which + * mask its version, is not resumed and expVersion is negotiated instead. */ +static int test_dtls13_mask_session(int sessionFirst, long firstOpts, + long secondOpts, int expVersion) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION* sess = NULL; + struct test_memio_ctx test_ctx; + char buf[64]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (ssl_c != NULL && firstOpts != 0) + (void)wolfSSL_set_options(ssl_c, firstOpts); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntNE(wolfSSL_version(ssl_c), expVersion); + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (sessionFirst) + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + if (ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, secondOpts); + if (!sessionFirst) + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_version(ssl_c), expVersion); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.tls1_3, 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), expVersion); + ExpectIntEQ(wolfSSL_version(ssl_s), expVersion); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_EARLY_DATA) +/* A DTLS 1.3 session set after the mask moves the SSL to DTLS 1.2, so early + * data is refused up front and nothing is left pending. */ +static int test_dtls13_mask_early_data(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION* sess = NULL; + struct test_memio_ctx test_ctx; + char buf[64]; + int outSz = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_max_early_data(ctx_s, sizeof(buf)), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_early_data(ssl_s, sizeof(buf)), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_write_early_data(ssl_c, "early", 5, &outSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(outSz, 0); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->earlyData, no_early_data); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_write(ssl_c, "data", 4), 4); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +#if defined(HAVE_SESSION_TICKET) && defined(HAVE_EXTENDED_MASTER) && \ + !defined(NO_OLD_TLS) +/* A dropped resumption of a session without EMS still offers EMS. */ +static int test_dtls13_mask_session_ems(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION* sess = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_DisableExtendedMasterSecret(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + if (ssl_c != NULL) { + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3 | + WOLFSSL_OP_NO_TLSv1_2); + } + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_VERSION); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.haveEMS, 1); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +#ifdef HAVE_SNI +static int test_dtls13_mask_sni_cb(WOLFSSL* ssl, int* ret, void* arg) +{ + (void)ret; + (void)arg; + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + return 0; +} + +/* An option set while the server parses the ClientHello does not move the + * version that ClientHello already settled. */ +static int test_dtls13_mask_in_client_hello(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + static const char host[] = "example.com"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + wolfSSL_CTX_set_servername_callback(ctx_s, test_dtls13_mask_sni_cb); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, host, + (word16)XSTRLEN(host)), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +static int test_dtls13_mask_max_sni_cb(WOLFSSL* ssl, int* ret, void* arg) +{ + int* res = (int*)arg; + + (void)ret; + res[1] = wolfSSL_set_max_proto_version(ssl, res[0]); + return 0; +} + +/* While the server parses the ClientHello, a maximum that changes nothing + * succeeds and one that lifts or tightens the cap fails. */ +static int test_dtls13_mask_max_in_client_hello(int mode) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + static const char host[] = "example.com"; + int res[2]; + + res[0] = (mode == 2) ? DTLS1_2_VERSION : DTLS1_3_VERSION; + res[1] = -2; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + wolfSSL_CTX_set_servername_callback(ctx_s, test_dtls13_mask_max_sni_cb); + ExpectIntEQ(wolfSSL_CTX_set_servername_arg(ctx_s, res), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (mode == 1) { + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_s, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, host, + (word16)XSTRLEN(host)), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(res[1], (mode == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_version(ssl_s), + (mode == 1) ? DTLS1_2_VERSION : DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +/* A CTX maximum of 0 lifts an earlier DTLS maximum. */ +static int test_dtls13_ctx_max_proto_reset(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx_c), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, + wolfSSL_CTX_get_max_proto_version(ctx_c)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A CTX maximum moves a fixed DTLS method down and back up, as it does a fixed + * TLS method. */ +static int test_dtls13_ctx_max_proto_fixed(method_provider method) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A TLS minimum on a DTLS SSL or CTX still offers DTLS 1.3, and a maximum that + * leaves no version fails without changing the SSL. */ +static int test_dtls13_min_max_tls_version(int mode) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + long opts = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (mode == 2) { + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx_c, WOLFSSL_TLSV1_2), + WOLFSSL_SUCCESS); + } + else if (mode == 5) { + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx_c, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + } + else if (mode == 6) { + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, TLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx_c) & WOLFSSL_OP_NO_TLSv1_3, 0); + } + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (mode == 1) { + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_FAILURE); + } + else if (mode == 0) { + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_TLSV1_2), + WOLFSSL_SUCCESS); + } + else if (mode == 3) { + opts = wolfSSL_get_options(ssl_c); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, TLS1_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, TLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl_c), opts); + } +#ifndef NO_OLD_TLS + else if (mode == 4) { + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_TLSV1_1), + WOLFSSL_SUCCESS); + } +#endif + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A TLS 1.3 CTX minimum on a DTLS CTX leaves only DTLS 1.3. */ +static int test_dtls13_ctx_min_tls13(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx_c, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx_c), DTLS1_3_VERSION); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(VERSION_ERROR)); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A minimum set after the mask moved the SSL to DTLS 1.2 still applies. */ +static int test_dtls13_mask_min_after(int onServer, int useProto) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL* ssl; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ssl = onServer ? ssl_s : ssl_c; + if (ssl != NULL) + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_2_VERSION); + if (useProto) { + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + } + else { + ExpectIntEQ(wolfSSL_SetMinVersion(ssl, WOLFSSL_DTLSV1_3), + WOLFSSL_SUCCESS); + } + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_get_error(ssl, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(VERSION_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* wolfSSL_set_max_proto_version() caps a DTLS SSL straight away. */ +static int test_dtls13_mask_max_proto(int onServer, int maxVer, + int expVersion) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL* ssl; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ssl = onServer ? ssl_s : ssl_c; + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, maxVer), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl), expVersion); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), expVersion); + ExpectIntEQ(wolfSSL_version(ssl_s), expVersion); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A maximum or an option that capped a DTLS SSL can be lifted again. */ +static int test_dtls13_mask_lift(int onServer, int mode) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL* ssl; + int capVer = (mode == 3) ? DTLS1_VERSION : DTLS1_2_VERSION; + int liftVer = (mode == 3) ? DTLS1_2_VERSION : DTLS1_3_VERSION; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ssl = onServer ? ssl_s : ssl_c; + if (mode == 2) { + if (ssl != NULL) + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + } + else { + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, capVer), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_version(ssl), capVer); + if (mode == 2 || mode == 4) { + if (ssl != NULL) + (void)wolfSSL_clear_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + } + else { + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, + mode == 1 ? 0 : liftVer), WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_version(ssl), liftVer); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), liftVer); + ExpectIntEQ(wolfSSL_version(ssl_s), liftVer); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A DTLS maximum does not clear a version the CTX or the user masked off, + * before or after an earlier maximum. */ +static int test_dtls13_mask_max_keeps_options(int mode) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (mode == 0) + (void)wolfSSL_CTX_set_options(ctx_c, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (mode == 1 && ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + if (mode == 2 && ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_options(ssl_c) & WOLFSSL_OP_NO_TLSv1_3, + WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A maximum set while the client's first ClientHello is still buffered fails, + * and option calls leave the version that ClientHello was built for. */ +static int test_dtls13_mask_lift_want_write(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + test_ctx.c_force_want_write = 1; + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_WRITE); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + if (ssl_c != NULL) + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_2); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + if (ssl_c != NULL) + (void)wolfSSL_clear_options(ssl_c, WOLFSSL_OP_NO_TLSv1_2); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + test_ctx.c_force_want_write = 0; + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* Option and maximum calls keep the version an SSL got from its CTX after the + * CTX maximum is lowered, also when they lift a mask bit. */ +static int test_dtls13_mask_option_keeps_version(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_1); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + (void)wolfSSL_clear_options(ssl_c, WOLFSSL_OP_NO_TLSv1_1); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_COMPRESSION); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + (void)wolfSSL_clear_options(ssl_c, WOLFSSL_OP_NO_COMPRESSION); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* An SSL keeps the CTX maximum it was created with when the CTX maximum is + * raised later, also when an unrelated version option is cleared. */ +static int test_dtls13_mask_ctx_raise(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_1); + (void)wolfSSL_clear_options(ssl_c, WOLFSSL_OP_NO_TLSv1_1); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A maximum that changes the mask fails once the first ClientHello is sent and + * after the handshake, a repeated one succeeds, and wolfSSL_clear() resets. */ +static int test_dtls13_mask_max_after_hello(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, 0), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl_c) & WOLFSSL_OP_NO_TLSv1_3, + WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_s, DTLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_clear(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +#ifndef NO_OLD_TLS +/* A CTX maximum of DTLS 1.0 masks the newer versions, and an SSL lift that + * finds nothing below the lowered method keeps its allowed version. */ +static int test_dtls13_ctx_max_dtls10(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, DTLS1_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx) & (WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_3), WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), DTLS1_VERSION); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_3, 0); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_2_VERSION); + wolfSSL_free(ssl); + ssl = NULL; + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_VERSION); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} +#endif + +#if defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM) && \ + !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_768) && \ + (!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \ + (defined(WOLFSSL_PQC_HYBRIDS) && defined(HAVE_CURVE25519))) + #define TEST_DTLS13_LIFT_PQ +#endif + +/* A server created below DTLS 1.3 and lifted to it later completes a DTLS 1.3 + * handshake, also with a fragmented post-quantum ClientHello. */ +static int test_dtls13_mask_lift_new_server(int pq) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; +#ifdef TEST_DTLS13_LIFT_PQ +#ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE + int group = WOLFSSL_ML_KEM_768; +#else + int group = WOLFSSL_X25519MLKEM768; +#endif +#endif + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + (void)wolfSSL_CTX_set_options(ctx_s, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + (void)wolfSSL_clear_options(ssl_s, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_3_VERSION); +#ifdef TEST_DTLS13_LIFT_PQ + if (pq) { + ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, group), WOLFSSL_SUCCESS); + } +#endif + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_3_VERSION); + + (void)pq; + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* wolfSSL_clear_options() returns the mask when it still leaves no version, + * and the handshake reports VERSION_ERROR. */ +static int test_dtls13_mask_clear_no_version(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + if (ssl_c != NULL) { + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3 | + WOLFSSL_OP_NO_TLSv1_1); + } + ExpectIntEQ(wolfSSL_clear_options(ssl_c, WOLFSSL_OP_NO_TLSv1_1) & + WOLFSSL_OP_NO_TLSv1_3, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(VERSION_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A CTX minimum of 0 keeps DTLS 1.3 in the client's supported_versions. */ +static int test_dtls13_ctx_min_proto_zero(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* The TLS 1.3 entry points hand an SSL already at DTLS 1.2 to the DTLS 1.2 + * handshake, whether the SSL or the CTX mask moved it. */ +static int test_dtls13_mask_tls13_entry(int onCtx) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int retC = WOLFSSL_FATAL_ERROR; + int retS = WOLFSSL_FATAL_ERROR; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (onCtx) { + (void)wolfSSL_CTX_set_options(ctx_c, WOLFSSL_OP_NO_TLSv1_3); + (void)wolfSSL_CTX_set_options(ctx_s, WOLFSSL_OP_NO_TLSv1_3); + } + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (!onCtx && ssl_c != NULL && ssl_s != NULL) { + (void)wolfSSL_set_options(ssl_c, WOLFSSL_OP_NO_TLSv1_3); + (void)wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TLSv1_3); + } + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + for (i = 0; EXPECT_SUCCESS() && i < 10 && + (retC != WOLFSSL_SUCCESS || retS != WOLFSSL_SUCCESS); i++) { + if (retC != WOLFSSL_SUCCESS) { + retC = wolfSSL_connect_TLSv13(ssl_c); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.tls1_3, 0); + } + if (retS != WOLFSSL_SUCCESS) + retS = wolfSSL_accept_TLSv13(ssl_s); + } + ExpectIntEQ(retC, WOLFSSL_SUCCESS); + ExpectIntEQ(retS, WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +#ifdef HAVE_SESSION_TICKET +/* Setting a DTLS 1.3 session and then a DTLS 1.2 one leaves tls1_3 set on a + * DTLS 1.2 SSL; the hand-off between the entry points must not loop. */ +static int test_dtls13_stale_tls13_session(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess13 = NULL, *sess12 = NULL; + struct test_memio_ctx test_ctx; + char buf[8]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), WOLFSSL_FATAL_ERROR); + ExpectNotNull(sess13 = wolfSSL_get1_session(ssl_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + wolfSSL_CTX_free(ctx_s); + ctx_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectNotNull(sess12 = wolfSSL_get1_session(ssl_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess13), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess12), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + + wolfSSL_SESSION_free(sess13); + wolfSSL_SESSION_free(sess12); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +/* wolfSSL_negotiate() applies the mask too, on the server here. */ +static int test_dtls13_mask_negotiate(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int retC = WOLFSSL_FATAL_ERROR; + int retS = WOLFSSL_FATAL_ERROR; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + if (ssl_s != NULL) + (void)wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TLSv1_3); + for (i = 0; EXPECT_SUCCESS() && i < 10 && + (retC != WOLFSSL_SUCCESS || retS != WOLFSSL_SUCCESS); i++) { + if (retC != WOLFSSL_SUCCESS) + retC = wolfSSL_negotiate(ssl_c); + if (retS != WOLFSSL_SUCCESS) + retS = wolfSSL_negotiate(ssl_s); + } + ExpectIntEQ(retC, WOLFSSL_SUCCESS); + ExpectIntEQ(retS, WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_version(ssl_s), DTLS1_2_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif +#endif + +/* wolfSSL_clear() lets a DTLS maximum change the mask again after a handshake, + * also in async builds without TLS 1.3. */ +int test_dtls_max_proto_after_clear(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_TLS12) && \ + (defined(WOLFSSL_DTLS13) || !defined(NO_OLD_TLS)) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; +#ifdef WOLFSSL_DTLS13 + int ver = DTLS1_2_VERSION; +#else + int ver = DTLS1_VERSION; +#endif + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx_c) & WOLFSSL_OP_NO_TLSv1_3, 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_options(ssl_c) & WOLFSSL_OP_NO_TLSv1_3, 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, ver), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_clear(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, ver), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), ver); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* WOLFSSL_OP_NO_TLSv1_3 moves a DTLS 1.3 client or server to the newest older + * DTLS version the mask and minimum allow, or is refused when none is left. + * + * @return TEST_SUCCESS on success. + */ +int test_dtls13_no_tls13_option(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(OPENSSL_EXTRA) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int onServer; + int onCtx; +#ifndef NO_OLD_TLS + int dtls10 = DTLS1_VERSION; +#else + int dtls10 = 0; +#endif +#ifndef WOLFSSL_NO_TLS12 + int dtls12 = DTLS1_2_VERSION; +#else + int dtls12 = dtls10; +#endif + + for (onServer = 0; onServer <= 1; onServer++) { + for (onCtx = 0; onCtx <= 1; onCtx++) { + ExpectIntEQ(test_dtls13_mask_case(onServer, onCtx, + WOLFSSL_OP_NO_TLSv1_3, 0, 0, 0, dtls12), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_case(onServer, onCtx, + WOLFSSL_OP_NO_TLSv1_3 | WOLFSSL_OP_NO_TLSv1_2, 0, 0, 0, + dtls10), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_case(onServer, onCtx, + WOLFSSL_OP_NO_TLSv1_3, WOLFSSL_OP_NO_TLSv1_2, 0, 0, dtls10), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_case(onServer, onCtx, + WOLFSSL_OP_NO_TLSv1_3 | WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_1, 0, 0, 0, 0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_case(onServer, onCtx, + WOLFSSL_OP_NO_TLSv1_3, WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_1, 0, 0, 0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_case(onServer, onCtx, + WOLFSSL_OP_NO_TLSv1_3, WOLFSSL_OP_NO_TLSv1_2, + WOLFSSL_OP_NO_TLSv1_1, 0, 0), TEST_SUCCESS); + } + ExpectIntEQ(test_dtls13_mask_case(onServer, 0, WOLFSSL_OP_NO_TLSv1_3, + 0, 0, WOLFSSL_DTLSV1_3, 0), TEST_SUCCESS); + } + ExpectIntEQ(test_dtls13_mask_case(0, 1, WOLFSSL_OP_NO_TLSv1_3, 0, 0, + WOLFSSL_DTLSV1_3, 0), TEST_SUCCESS); +#ifndef OPENSSL_COEXIST + ExpectIntEQ(test_dtls13_mask_case(0, 0, SSL_OP_NO_DTLSv1_3, + SSL_OP_NO_DTLSv1_2, SSL_OP_NO_DTLSv1, 0, 0), TEST_SUCCESS); +#endif +#ifndef WOLFSSL_NO_TLS12 + ExpectIntEQ(test_dtls13_mask_server_walk(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_client_check(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_negotiate(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_ctx_max_proto_reset(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_ctx_max_proto_fixed(wolfDTLSv1_3_client_method), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_ctx_max_proto_fixed(wolfDTLSv1_2_client_method), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_min_max_tls_version(0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_min_max_tls_version(1), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_min_max_tls_version(2), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_min_max_tls_version(3), TEST_SUCCESS); +#ifndef NO_OLD_TLS + ExpectIntEQ(test_dtls13_min_max_tls_version(4), TEST_SUCCESS); +#endif + ExpectIntEQ(test_dtls13_min_max_tls_version(5), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_min_max_tls_version(6), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_ctx_min_tls13(), TEST_SUCCESS); + for (onServer = 0; onServer <= 1; onServer++) { + ExpectIntEQ(test_dtls13_mask_min_after(onServer, 0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_min_after(onServer, 1), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_proto(onServer, DTLS1_2_VERSION, + DTLS1_2_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_proto(onServer, DTLS1_3_VERSION, + DTLS1_3_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_proto(onServer, 0, DTLS1_3_VERSION), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift(onServer, 0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift(onServer, 1), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift(onServer, 2), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift(onServer, 4), TEST_SUCCESS); + #ifndef NO_OLD_TLS + ExpectIntEQ(test_dtls13_mask_max_proto(onServer, DTLS1_VERSION, + DTLS1_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift(onServer, 3), TEST_SUCCESS); + #endif + } + for (onCtx = 0; onCtx <= 1; onCtx++) + ExpectIntEQ(test_dtls13_mask_tls13_entry(onCtx), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_keeps_options(0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_keeps_options(1), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_keeps_options(2), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift_want_write(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_option_keeps_version(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_ctx_raise(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_after_hello(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_clear_no_version(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_lift_new_server(0), TEST_SUCCESS); +#ifdef TEST_DTLS13_LIFT_PQ + ExpectIntEQ(test_dtls13_mask_lift_new_server(1), TEST_SUCCESS); +#endif +#ifndef NO_OLD_TLS + ExpectIntEQ(test_dtls13_ctx_max_dtls10(), TEST_SUCCESS); +#endif +#ifdef HAVE_SESSION_TICKET + ExpectIntEQ(test_dtls13_stale_tls13_session(), TEST_SUCCESS); +#endif + ExpectIntEQ(test_dtls13_ctx_min_proto_zero(), TEST_SUCCESS); +#ifdef HAVE_SNI + ExpectIntEQ(test_dtls13_mask_in_client_hello(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_in_client_hello(0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_in_client_hello(1), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_max_in_client_hello(2), TEST_SUCCESS); +#endif +#ifdef HAVE_SESSION_TICKET + ExpectIntEQ(test_dtls13_mask_session(0, 0, WOLFSSL_OP_NO_TLSv1_3, + DTLS1_2_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_session(1, 0, WOLFSSL_OP_NO_TLSv1_3, + DTLS1_2_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_session(0, WOLFSSL_OP_NO_TLSv1_3, + WOLFSSL_OP_NO_TLSv1_2, DTLS1_3_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_session(1, WOLFSSL_OP_NO_TLSv1_3, + WOLFSSL_OP_NO_TLSv1_2, DTLS1_3_VERSION), TEST_SUCCESS); +#endif + ExpectIntEQ(test_dtls13_mask_server_sv(0, WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_1), TEST_SUCCESS); +#ifndef NO_OLD_TLS + ExpectIntEQ(test_dtls13_mask_server_sv(WOLFSSL_OP_NO_TLSv1_1, + WOLFSSL_OP_NO_TLSv1_2), TEST_SUCCESS); +#endif +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_EARLY_DATA) + ExpectIntEQ(test_dtls13_mask_early_data(), TEST_SUCCESS); +#endif +#if defined(HAVE_SESSION_TICKET) && defined(HAVE_EXTENDED_MASTER) && \ + !defined(NO_OLD_TLS) + ExpectIntEQ(test_dtls13_mask_session_ems(), TEST_SUCCESS); +#endif +#endif + + /* A DTLS 1.3-only method cannot move down or take a lower maximum. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_3, 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, 0), WOLFSSL_SUCCESS); + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, 0), WOLFSSL_SUCCESS); + (void)wolfSSL_connect(ssl); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_3_VERSION); + wolfSSL_free(ssl); + ssl = NULL; + (void)wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), 0); + ExpectNull(wolfSSL_new(ctx)); + (void)wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); + ExpectNull(wolfSSL_new(ctx)); + wolfSSL_CTX_free(ctx); + ctx = NULL; + +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl) & WOLFSSL_OP_NO_TLSv1_2, 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_2_VERSION); + wolfSSL_free(ssl); + ssl = NULL; + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_client_method())); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), DTLS1_3_VERSION); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_3_VERSION); + wolfSSL_free(ssl); + ssl = NULL; + (void)wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), 0); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_3, + WOLFSSL_OP_NO_TLSv1_3); + ExpectNull(wolfSSL_new(ctx)); +#ifdef NO_OLD_TLS + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, DTLS1_VERSION), + WOLFSSL_FAILURE); +#endif + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* DTLS versions are refused as a minimum or maximum on a TLS object. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, DTLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl, WOLFSSL_DTLSV1_2), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wolfSSL_free(ssl); + ssl = NULL; + wolfSSL_CTX_free(ctx); + ctx = NULL; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_require_psk(ssl), 0); + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + (void)wolfSSL_connect(ssl); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_3_VERSION); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index 2e5411a8fe5..718cdf132a0 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -178,6 +178,8 @@ int test_dtls13_hrr_cookie_state_guard(void); int test_dtls12_cookie_secret_generate_fail(void); int test_dtls13_hrr_cookie_secret_generate_fail(void); int test_dtls_max_fragment_write(void); +int test_dtls13_no_tls13_option(void); +int test_dtls_max_proto_after_clear(void); int test_wolfSSL_dtls_export(void); int test_wolfSSL_dtls_import_dh_key_sz(void); int test_wolfSSL_dtls_export_peers(void); @@ -388,5 +390,7 @@ int test_dtls_no_cookie_ch_pause(WOLFSSL* ssl, void* ctx); TEST_DECL_GROUP("dtls", test_dtls13_hrr_cookie_secret_secondary_disabled), \ TEST_DECL_GROUP("dtls", test_dtls12_cookie_secret_generate_fail), \ TEST_DECL_GROUP("dtls", test_dtls13_hrr_cookie_secret_generate_fail), \ - TEST_DECL_GROUP("dtls", test_dtls_max_fragment_write) + TEST_DECL_GROUP("dtls", test_dtls_max_fragment_write), \ + TEST_DECL_GROUP("dtls", test_dtls13_no_tls13_option), \ + TEST_DECL_GROUP("dtls", test_dtls_max_proto_after_clear) #endif /* TESTS_API_DTLS_H */ diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 18730cb07f5..7081a67ce8a 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -8394,6 +8394,109 @@ int test_tls13_ech_hrr_coalesced_server_hello(void) return EXPECT_RESULT(); } +/* A TLS 1.1 ServerHello after a HelloRetryRequest that accepted ECH is + * rejected, like a TLS 1.3 one that rejects ECH (RFC 9849 6.1.5). */ +int test_tls13_ech_hrr_tls11_server_hello(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && defined(HAVE_SNI) && \ + defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \ + !defined(NO_OLD_TLS) + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL_CTX* ctx_c11 = NULL; + WOLFSSL_CTX* ctx_s11 = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + WOLFSSL* ssl_c11 = NULL; + WOLFSSL* ssl_s11 = NULL; + struct test_memio_ctx test_ctx; + struct test_memio_ctx test_ctx11; + byte configs[512]; + word32 configsLen = (word32)sizeof(configs); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + XMEMSET(&test_ctx11, 0, sizeof(test_ctx11)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + ExpectIntEQ(test_memio_setup(&test_ctx11, &ctx_c11, &ctx_s11, &ssl_c11, + &ssl_s11, wolfSSLv23_client_method, wolfTLSv1_1_server_method), 0); + wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx_s, ECH_TEST_PUB_NAME, 0, 0, + 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx_s, configs, &configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetEchConfigs(ssl_c, configs, configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + ECH_TEST_PRIV_NAME, (word16)XSTRLEN(ECH_TEST_PRIV_NAME)), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_TLSV1_1), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_msg_is_hello_retry_request(&test_ctx), 1); + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.echAccepted, 1); + + /* The second ClientHello goes to a TLS 1.1 server. */ + ExpectIntEQ(test_memio_inject_message(&test_ctx11, 0, + (const char*)test_ctx.s_buff, test_ctx.s_len), 0); + ExpectIntEQ(wolfSSL_accept(ssl_s11), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_s11, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char*)test_ctx11.c_buff, test_ctx11.c_len), 0); + + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), + WC_NO_ERR_TRACE(INVALID_PARAMETER)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c11); + wolfSSL_free(ssl_s11); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c11); + wolfSSL_CTX_free(ctx_s11); + ssl_c = NULL; + ssl_s = NULL; + ctx_c = NULL; + ctx_s = NULL; + + /* Without a HelloRetryRequest an echAccepted left from an earlier + * connection does not stop the TLS 1.1 fallback. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfTLSv1_1_server_method), 0); + wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_SetEchConfigs(ssl_c, configs, configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_TLSV1_1), WOLFSSL_SUCCESS); + if (ssl_c != NULL) + ssl_c->options.echAccepted = 1; + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), TLS1_1_VERSION); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + /* The same offsets against a ServerHello reassembled from two records, where * input points at the message body: ECH acceptance used to read 4 bytes past * ssl->pendingMsg and report a rejection the server never sent. */ diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index 123831145b1..2db640f8819 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -57,6 +57,7 @@ int test_tls13_duplicate_extension(void); int test_tls13_duplicate_ech_extension(void); int test_tls13_ech_hrr_coalesced_server_hello(void); int test_tls13_ech_fragmented_server_hello(void); +int test_tls13_ech_hrr_tls11_server_hello(void); int test_key_share_mismatch(void); int test_key_share_mismatch_psk_dhe(void); int test_tls13_middlebox_compat_empty_session_id(void); @@ -236,6 +237,7 @@ int test_tls13_cks_hrr_reparse(void); TEST_DECL_GROUP("tls13", test_tls13_duplicate_ech_extension), \ TEST_DECL_GROUP("tls13", test_tls13_ech_hrr_coalesced_server_hello), \ TEST_DECL_GROUP("tls13", test_tls13_ech_fragmented_server_hello), \ + TEST_DECL_GROUP("tls13", test_tls13_ech_hrr_tls11_server_hello), \ TEST_DECL_GROUP("tls13", test_key_share_mismatch), \ TEST_DECL_GROUP("tls13", test_key_share_mismatch_psk_dhe), \ TEST_DECL_GROUP("tls13", test_tls13_middlebox_compat_empty_session_id), \ diff --git a/tests/api/test_tls_ext.c b/tests/api/test_tls_ext.c index a4eefb08ee2..c1fcac2e3af 100644 --- a/tests/api/test_tls_ext.c +++ b/tests/api/test_tls_ext.c @@ -3178,6 +3178,568 @@ int test_TLSX_SupportedCurve_empty_or_unsupported(void) return EXPECT_RESULT(); } +#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SUPPORTED_CURVES) && \ + defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_TLS12) && defined(HAVE_ECC) && \ + defined(HAVE_ECC_BRAINPOOL) && ECC_MIN_KEY_SZ <= 256 && \ + (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) +static const word16 test_bp_tls13[] = { + WOLFSSL_ECC_BRAINPOOLP256R1TLS13, +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 + WOLFSSL_ECC_BRAINPOOLP384R1TLS13, +#endif +#if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 + WOLFSSL_ECC_BRAINPOOLP512R1TLS13, +#endif +}; +static const word16 test_bp_tls12[] = { + WOLFSSL_ECC_BRAINPOOLP256R1, +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 + WOLFSSL_ECC_BRAINPOOLP384R1, +#endif +#if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 + WOLFSSL_ECC_BRAINPOOLP512R1, +#endif +}; +#define TEST_BP_CNT \ + ((int)(sizeof(test_bp_tls13) / sizeof(test_bp_tls13[0]))) + +static void test_brainpool_count(TLSX* ext, int* tls13Cnt, int* tls12Cnt) +{ + SupportedCurve* curve = NULL; + int i; + + *tls13Cnt = 0; + *tls12Cnt = 0; + if (ext != NULL) + curve = (SupportedCurve*)ext->data; + for (; curve != NULL; curve = curve->next) { + for (i = 0; i < TEST_BP_CNT; i++) { + if (curve->name == test_bp_tls13[i]) + (*tls13Cnt)++; + else if (curve->name == test_bp_tls12[i]) + (*tls12Cnt)++; + } + } +} + +/* Counts the brainpool codepoints of each kind in a client's supported_groups + * list. */ +static int test_brainpool_offer(method_provider method, int ctxMinVersion, + int minVersion, long opts, int* tls13Cnt, int* tls12Cnt) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL* ssl_c = NULL; + TLSX* ext = NULL; + + *tls13Cnt = 0; + *tls12Cnt = 0; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, NULL, NULL, + method, NULL), 0); + if (ctxMinVersion != 0) { + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx_c, ctxMinVersion), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL, + method, NULL), 0); + if (minVersion != 0) { + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, minVersion), + WOLFSSL_SUCCESS); + } + if ((opts != 0) && (ssl_c != NULL)) + (void)wolfSSL_set_options(ssl_c, opts); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + if (ssl_c != NULL) + ext = TLSX_Find(ssl_c->extensions, TLSX_SUPPORTED_GROUPS); + ExpectNotNull(ext); + test_brainpool_count(ext, tls13Cnt, tls12Cnt); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + return EXPECT_RESULT(); +} + +#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) +/* Counts the brainpool codepoints of each kind in the supported_groups list a + * TLS 1.3 server sends when the client lacks the server's first group. */ +static int test_brainpool_server_offer(int* tls13Cnt, int* tls12Cnt) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + TLSX* ext = NULL; + + *tls13Cnt = 0; + *tls12Cnt = 0; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + ExpectIntEQ(wolfSSL_UseSupportedCurve(ssl_c, + WOLFSSL_ECC_BRAINPOOLP256R1TLS13), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_BRAINPOOLP256R1TLS13), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_version(ssl_s), TLS1_3_VERSION); + + if (ssl_s != NULL) + ext = TLSX_Find(ssl_s->extensions, TLSX_SUPPORTED_GROUPS); + ExpectNotNull(ext); + if (ext != NULL) + ExpectIntEQ(ext->resp, 1); + test_brainpool_count(ext, tls13Cnt, tls12Cnt); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +#if defined(HAVE_ECH) && defined(HAVE_SNI) && !defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER) +/* Counts the brainpool codepoints in the ECH inner ClientHello as the server + * parsed it, or in the list the client uses after a TLS 1.2 ServerHello. */ +static int test_brainpool_ech_offer(method_provider serverMethod, + int* tls13Cnt, int* tls12Cnt) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + TLSX* ext = NULL; + static const char pubName[] = "ech-public-name.com"; + static const char privName[] = "ech-private-name.com"; + byte configs[512]; + word32 configsLen = (word32)sizeof(configs); + int tls12Server = (serverMethod == wolfTLSv1_2_server_method); + + *tls13Cnt = 0; + *tls12Cnt = 0; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, serverMethod), 0); + wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx_s, pubName, 0, 0, 0), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx_s, configs, &configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetEchConfigs(ssl_c, configs, configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, privName, + (word16)XSTRLEN(privName)), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + if (tls12Server) { + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_version(ssl_c), TLS1_2_VERSION); + if (ssl_c != NULL) + ext = TLSX_Find(ssl_c->extensions, TLSX_SUPPORTED_GROUPS); + } + else { + ExpectIntEQ(wolfSSL_GetEchStatus(ssl_s), + WOLFSSL_ECH_STATUS_ACCEPTED); + if (ssl_s != NULL) + ext = TLSX_Find(ssl_s->extensions, TLSX_SUPPORTED_GROUPS); + if (ext != NULL) + ExpectIntEQ(ext->resp, 0); + } + ExpectNotNull(ext); + test_brainpool_count(ext, tls13Cnt, tls12Cnt); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +#define TEST_BP_MAX_EXTS 64 + +/* Lists a ClientHello's extension types, less those allowed to change after a + * HelloRetryRequest and supported_versions, and finds supported_groups. */ +static int test_bp_parse_ch(const byte* buf, int len, word16* types, + int* typeCnt, const byte** groups, word16* groupsLen) +{ + int idx = 0; + int end; + word16 recLen; + word16 extLen; + word16 type; + + *typeCnt = 0; + *groups = NULL; + *groupsLen = 0; + while (idx + RECORD_HEADER_SZ <= len && buf[idx] != handshake) { + ato16(buf + idx + 3, &recLen); + idx += RECORD_HEADER_SZ + recLen; + } + if (idx + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ > len || + buf[idx + RECORD_HEADER_SZ] != client_hello) { + return -1; + } + ato16(buf + idx + 3, &recLen); + end = idx + RECORD_HEADER_SZ + recLen; + if (end > len) + return -1; + idx += RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + VERSION_SZ + RAN_LEN; + if (idx >= end) + return -1; + idx += 1 + buf[idx]; + if (idx + OPAQUE16_LEN > end) + return -1; + ato16(buf + idx, &extLen); + idx += OPAQUE16_LEN + extLen; + if (idx >= end) + return -1; + idx += 1 + buf[idx]; + idx += OPAQUE16_LEN; + while (idx + 2 * OPAQUE16_LEN <= end && *typeCnt < TEST_BP_MAX_EXTS) { + ato16(buf + idx, &type); + ato16(buf + idx + OPAQUE16_LEN, &extLen); + if (idx + 2 * OPAQUE16_LEN + extLen > end) + return -1; + if (type == TLSXT_SUPPORTED_GROUPS) { + *groups = buf + idx + 2 * OPAQUE16_LEN; + *groupsLen = extLen; + } + if (type != TLSXT_KEY_SHARE && type != TLSXT_EARLY_DATA && + type != TLSXT_COOKIE && type != TLSXT_PRE_SHARED_KEY && + type != TLSXT_ECH && type != TLSXT_SUPPORTED_VERSIONS) { + types[(*typeCnt)++] = type; + } + idx += 2 * OPAQUE16_LEN + extLen; + } + return (*groups != NULL && idx == end) ? 0 : -1; +} + +/* Compares the ClientHellos before and after a HelloRetryRequest with ECH and + * counts the brainpool codepoints in the second one. */ +static int test_brainpool_ech_hrr(int accept, int* tls13Cnt, int* tls12Cnt) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL_CTX* ctx_o = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + static const char pubName[] = "ech-public-name.com"; + static const char privName[] = "ech-private-name.com"; + byte configs[512]; + word32 configsLen = (word32)sizeof(configs); + byte ch1[TEST_MEMIO_BUF_SZ]; + int ch1Len = 0; + word16 types1[TEST_BP_MAX_EXTS]; + word16 types2[TEST_BP_MAX_EXTS]; + int cnt1 = 0; + int cnt2 = 0; + const byte* groups1 = NULL; + const byte* groups2 = NULL; + word16 groupsLen1 = 0; + word16 groupsLen2 = 0; + word16 name; + int innerTls13Cnt = 0; + int innerTls12Cnt = 0; + int i; + int j; + + *tls13Cnt = 0; + *tls12Cnt = 0; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx_s, pubName, 0, 0, 0), + WOLFSSL_SUCCESS); + if (accept) { + ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx_s, configs, &configsLen), + WOLFSSL_SUCCESS); + } + else { + /* Keys the server does not hold, so it rejects ECH. */ + ExpectNotNull(ctx_o = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx_o, pubName, 0, 0, 0), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx_o, configs, &configsLen), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_SetEchConfigs(ssl_c, configs, configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, privName, + (word16)XSTRLEN(privName)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + if (EXPECT_SUCCESS()) { + ch1Len = test_ctx.s_len; + XMEMCPY(ch1, test_ctx.s_buff, (size_t)ch1Len); + } + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + if (ssl_c != NULL) { + ExpectIntEQ(ssl_c->options.serverState, + SERVER_HELLO_RETRY_REQUEST_COMPLETE); + } + + ExpectIntEQ(test_bp_parse_ch(ch1, ch1Len, types1, &cnt1, &groups1, + &groupsLen1), 0); + ExpectIntEQ(test_bp_parse_ch(test_ctx.s_buff, test_ctx.s_len, types2, + &cnt2, &groups2, &groupsLen2), 0); + ExpectIntEQ(cnt1, cnt2); + if (EXPECT_SUCCESS()) + ExpectIntEQ(XMEMCMP(types1, types2, (size_t)cnt1 * sizeof(word16)), 0); + ExpectIntEQ(groupsLen1, groupsLen2); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(XMEMCMP(groups1, groups2, groupsLen1), 0); + for (i = OPAQUE16_LEN; i + OPAQUE16_LEN <= groupsLen2; + i += OPAQUE16_LEN) { + ato16(groups2 + i, &name); + for (j = 0; j < TEST_BP_CNT; j++) { + if (name == test_bp_tls13[j]) + (*tls13Cnt)++; + else if (name == test_bp_tls12[j]) + (*tls12Cnt)++; + } + } + } + + if (accept) { + if (ssl_c != NULL) { + test_brainpool_count(TLSX_Find(ssl_c->extensions, + TLSX_SUPPORTED_GROUPS), &innerTls13Cnt, &innerTls12Cnt); + } + ExpectIntEQ(innerTls13Cnt, TEST_BP_CNT); + ExpectIntEQ(innerTls12Cnt, 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_GetEchStatus(ssl_c), WOLFSSL_ECH_STATUS_ACCEPTED); + } + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_o); + return EXPECT_RESULT(); +} + +/* Lists the extension types of the first ClientHello with real ECH, or with + * GREASE ECH when real is 0. */ +static int test_bp_ech_ch_types(int real, word16* types, int* typeCnt) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + static const char pubName[] = "ech-public-name.com"; + static const char privName[] = "ech-private-name.com"; + byte configs[512]; + word32 configsLen = (word32)sizeof(configs); + const byte* groups = NULL; + word16 groupsLen = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + if (real) { + ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(ctx_s, pubName, 0, 0, 0), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(ctx_s, configs, &configsLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetEchConfigs(ssl_c, configs, configsLen), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, privName, + (word16)XSTRLEN(privName)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_bp_parse_ch(test_ctx.s_buff, test_ctx.s_len, types, + typeCnt, &groups, &groupsLen), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +/* A real ECH outer ClientHello orders its extensions like a GREASE one. */ +static int test_brainpool_ech_order(void) +{ + EXPECT_DECLS; + word16 realTypes[TEST_BP_MAX_EXTS]; + word16 greaseTypes[TEST_BP_MAX_EXTS]; + int realCnt = 0; + int greaseCnt = 0; + + ExpectIntEQ(test_bp_ech_ch_types(1, realTypes, &realCnt), TEST_SUCCESS); + ExpectIntEQ(test_bp_ech_ch_types(0, greaseTypes, &greaseCnt), + TEST_SUCCESS); + ExpectIntEQ(realCnt, greaseCnt); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(XMEMCMP(realTypes, greaseTypes, + (size_t)realCnt * sizeof(word16)), 0); + } + return EXPECT_RESULT(); +} +#endif +#endif + +/* The RFC 7027 brainpool codepoints are offered only when TLS 1.2 or older can + * still be negotiated; TLS 1.3 uses the RFC 8734 ones. */ +int test_TLSX_SupportedCurve_brainpool_downgrade(void) +{ + EXPECT_DECLS; +#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SUPPORTED_CURVES) && \ + defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_TLS12) && defined(HAVE_ECC) && \ + defined(HAVE_ECC_BRAINPOOL) && ECC_MIN_KEY_SZ <= 256 && \ + (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) + int tls13Cnt = 0; + int tls12Cnt = 0; + + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, 0, 0, 0, + &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); + + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, 0, + WOLFSSL_TLSV1_2, 0, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); + + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, 0, + WOLFSSL_TLSV1_3, 0, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); + + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, + WOLFSSL_TLSV1_3, 0, 0, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); + + ExpectIntEQ(test_brainpool_offer(wolfTLSv1_3_client_method, 0, 0, 0, + &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); + + ExpectIntEQ(test_brainpool_offer(wolfTLSv1_2_client_method, 0, 0, 0, + &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, 0); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ + defined(WOLFSSL_WPAS_SMALL) + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, 0, 0, + WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | + WOLFSSL_OP_NO_TLSv1_2, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); +#ifndef NO_OLD_TLS + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, 0, + WOLFSSL_TLSV1_1, WOLFSSL_OP_NO_TLSv1_2, &tls13Cnt, &tls12Cnt), + TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); +#ifdef WOLFSSL_ALLOW_TLSV10 + ExpectIntEQ(test_brainpool_offer(wolfSSLv23_client_method, 0, + WOLFSSL_TLSV1, WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2, + &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); +#endif +#ifdef WOLFSSL_DTLS13 + ExpectIntEQ(test_brainpool_offer(wolfDTLS_client_method, 0, + WOLFSSL_DTLSV1, WOLFSSL_OP_NO_TLSv1_2, &tls13Cnt, &tls12Cnt), + TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); +#endif +#endif +#endif + +#ifdef WOLFSSL_DTLS + ExpectIntEQ(test_brainpool_offer(wolfDTLS_client_method, 0, + WOLFSSL_DTLSV1_2, 0, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); +#ifdef WOLFSSL_DTLS13 + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); +#else + ExpectIntEQ(tls13Cnt, 0); +#endif + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); +#endif + +#ifdef WOLFSSL_DTLS13 + ExpectIntEQ(test_brainpool_offer(wolfDTLS_client_method, 0, + WOLFSSL_DTLSV1_3, 0, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ + defined(WOLFSSL_WPAS_SMALL) + ExpectIntEQ(test_brainpool_offer(wolfDTLS_client_method, 0, 0, + WOLFSSL_OP_NO_TLSv1_3, &tls13Cnt, &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, 0); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); +#endif +#endif + +#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT) + ExpectIntEQ(test_brainpool_server_offer(&tls13Cnt, &tls12Cnt), + TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); +#endif + +#if defined(HAVE_ECH) && defined(HAVE_SNI) && !defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER) + ExpectIntEQ(test_brainpool_ech_offer(wolfSSLv23_server_method, &tls13Cnt, + &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, 0); + + ExpectIntEQ(test_brainpool_ech_offer(wolfTLSv1_2_server_method, &tls13Cnt, + &tls12Cnt), TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); + + ExpectIntEQ(test_brainpool_ech_hrr(1, &tls13Cnt, &tls12Cnt), + TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); + + ExpectIntEQ(test_brainpool_ech_hrr(0, &tls13Cnt, &tls12Cnt), + TEST_SUCCESS); + ExpectIntEQ(tls13Cnt, TEST_BP_CNT); + ExpectIntEQ(tls12Cnt, TEST_BP_CNT); + + ExpectIntEQ(test_brainpool_ech_order(), TEST_SUCCESS); +#endif +#endif + return EXPECT_RESULT(); +} + /* The signature_algorithms_cert list is allocated only when a peer sends the * extension: first list, replacement, truncation, and release. */ int test_TLSX_SignatureAlgorithmsCert_parse(void) diff --git a/tests/api/test_tls_ext.h b/tests/api/test_tls_ext.h index 3ba806a662b..eb7d76e0222 100644 --- a/tests/api/test_tls_ext.h +++ b/tests/api/test_tls_ext.h @@ -67,6 +67,7 @@ int test_TLSX_TCA_tls13_msg_type_validation(void); int test_TLSX_QUIC_TP_non_quic(void); int test_TLSX_ALPN_server_response_count(void); int test_TLSX_SupportedCurve_empty_or_unsupported(void); +int test_TLSX_SupportedCurve_brainpool_downgrade(void); int test_TLSX_SignatureAlgorithmsCert_parse(void); int test_TLSX_PointFormat_list(void); int test_TLSX_MaxFragment_value(void); @@ -102,6 +103,7 @@ int test_wolfSSL_custom_ext_add_null(void); TEST_DECL_GROUP("tls", test_TLSX_SRTP_msg_type_validation), \ TEST_DECL_GROUP("tls", test_TLSX_ALPN_server_response_count), \ TEST_DECL_GROUP("tls", test_TLSX_SupportedCurve_empty_or_unsupported), \ + TEST_DECL_GROUP("tls", test_TLSX_SupportedCurve_brainpool_downgrade), \ TEST_DECL_GROUP("tls", test_TLSX_PointFormat_uncompressed_required) #endif /* TESTS_API_TEST_TLS_EXT_H */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 991a818a541..faf1788f7a8 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2380,6 +2380,7 @@ WOLFSSL_LOCAL void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv); WOLFSSL_LOCAL void InitSSL_CTX_Suites(const WOLFSSL_CTX* ctx, Suites* suites); WOLFSSL_LOCAL int InitSSL_Suites(WOLFSSL* ssl); +WOLFSSL_LOCAL int ResetSuitesForVersion(WOLFSSL* ssl); WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side); @@ -5759,6 +5760,9 @@ struct Options { void* psk_ctx; #endif /* NO_PSK */ unsigned long mask; /* store SSL_OP_ flags */ +#ifdef WOLFSSL_DTLS + unsigned long dtlsMaxMask; /* mask bits the DTLS maximum added */ +#endif #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(WOLFSSL_WPAS_SMALL) word16 minProto:1; /* sets min to min available */ word16 maxProto:1; /* sets max to max available */ @@ -8276,6 +8280,20 @@ WOLFSSL_LOCAL int DtlsUpdateWindow(WOLFSSL* ssl); WOLFSSL_LOCAL void DtlsResetState(WOLFSSL *ssl); WOLFSSL_LOCAL int DtlsIgnoreError(int err); WOLFSSL_LOCAL void DtlsSetSeqNumForReply(WOLFSSL* ssl); +WOLFSSL_LOCAL byte DtlsMinDowngrade(byte minDowngrade); +#ifndef NO_WOLFSSL_SERVER +WOLFSSL_LOCAL int InitSSL_DtlsServer(WOLFSSL* ssl); +#endif +WOLFSSL_LOCAL byte DtlsMaskAllowedMinor(unsigned long mask, byte maxMinor, + byte minDowngrade); +WOLFSSL_LOCAL byte DtlsAllowedMinor(const WOLFSSL* ssl, byte maxMinor, + byte minDowngrade); +enum DtlsMaskMode { + DTLS_MASK_START, + DTLS_MASK_LIFT, + DTLS_MASK_IN_HELLO +}; +WOLFSSL_LOCAL int DtlsCheckVersionMask(WOLFSSL* ssl, enum DtlsMaskMode mode); #ifndef NO_WOLFSSL_SERVER WOLFSSL_LOCAL int DtlsNoCookieChGood(WOLFSSL* ssl); #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 24ebab8000d..c594eb143db 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3072,6 +3072,12 @@ enum { #define SSL_OP_NO_TLSv1_3 WOLFSSL_OP_NO_TLSv1_3 #endif +#define SSL_OP_NO_DTLSv1 WOLFSSL_OP_NO_TLSv1_1 +#define SSL_OP_NO_DTLSv1_2 WOLFSSL_OP_NO_TLSv1_2 +#ifdef WOLFSSL_DTLS13 +#define SSL_OP_NO_DTLSv1_3 WOLFSSL_OP_NO_TLSv1_3 +#endif + #ifdef HAVE_SESSION_TICKET #define SSL_OP_NO_TICKET WOLFSSL_OP_NO_TICKET #endif