diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 4a1d0e0f51a..f9fffb8d8d6 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -7660,6 +7660,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 34fc49a735b..6a3d8869555 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2818,10 +2818,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) @@ -8050,7 +8046,7 @@ int wolfSSL_CTX_IsPrivatePkSet(WOLFSSL_CTX* ctx) } #endif /* HAVE_PK_CALLBACKS */ -static void InitSuites_EitherSide(Suites* suites, ProtocolVersion pv, int keySz, +void InitSuites_EitherSide(Suites* suites, ProtocolVersion pv, int keySz, word16 haveRSA, word16 havePSK, word16 haveDH, word16 haveECDSAsig, word16 haveECC, word16 haveStaticECC, word16 haveAnon, @@ -8094,6 +8090,20 @@ void InitSSL_CTX_Suites(const WOLFSSL_CTX* ctx, Suites* suites) haveAnon, ctx->method->side); } +/* Returns the newest version a downgrade SSL can be moved back up to. DTLS + * minors count down. */ +ProtocolVersion SslNewestVersion(const WOLFSSL* ssl) +{ + ProtocolVersion pv = ssl->version; + byte methodMinor = ssl->ctx->method->version.minor; + + if (ssl->options.downgrade && (ssl->options.dtls ? + methodMinor < pv.minor : methodMinor > pv.minor)) { + pv = ssl->ctx->method->version; + } + return pv; +} + int InitSSL_Suites(WOLFSSL* ssl) { int keySz = 0; @@ -8152,6 +8162,8 @@ int InitSSL_Suites(WOLFSSL* ssl) havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.useAnon, ssl->options.side); + if (FilterSuitesForVersion(ssl) != 0) + return MEMORY_E; } #if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT) @@ -8200,6 +8212,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 @@ -8228,6 +8295,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) { @@ -9215,7 +9301,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; @@ -10435,6 +10521,8 @@ void FreeSuites(WOLFSSL* ssl) #endif XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); ssl->suites = NULL; + XFREE(ssl->suitesUser, ssl->heap, DYNAMIC_TYPE_SUITES); + ssl->suitesUser = NULL; } @@ -34872,7 +34960,8 @@ int SetCipherList_ex(const WOLFSSL_CTX* ctx, const WOLFSSL* ssl, side = ctx->method->side; } else if (ssl != NULL) { - version = ssl->version; + /* A later lift needs the suites of the newer version in the list. */ + version = SslNewestVersion(ssl); #ifndef NO_CERTS privateKeySz = ssl->buffers.keySz; #endif @@ -35154,9 +35243,7 @@ int SetSuitesHashSigAlgo(Suites* suites, const char* list) const char* s = list; byte sig_alg = 0; byte mac_alg = no_mac; - - /* Setting is destructive on error. */ - suites->hashSigAlgoSz = 0; + byte hashSigAlgo[WOLFSSL_MAX_SIGALGO]; do { if (*list == '+') { @@ -35196,7 +35283,7 @@ int SetSuitesHashSigAlgo(Suites* suites, const char* list) break; } } - AddSuiteHashSigAlgo(suites->hashSigAlgo, mac_alg, sig_alg, 0, &idx); + AddSuiteHashSigAlgo(hashSigAlgo, mac_alg, sig_alg, 0, &idx); sig_alg = 0; mac_alg = no_mac; s = list + 1; @@ -35209,7 +35296,8 @@ int SetSuitesHashSigAlgo(Suites* suites, const char* list) if (s != list && (sig_alg != 0 || mac_alg != 0)) { ret = 0; } - else { + if (ret == 1) { + XMEMCPY(suites->hashSigAlgo, hashSigAlgo, idx); suites->hashSigAlgoSz = idx; } @@ -37558,6 +37646,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 && @@ -37656,6 +37755,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; @@ -44464,6 +44581,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 e3890aeeba9..ae98a243ff6 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2165,9 +2165,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) @@ -2196,6 +2205,10 @@ static int SetMinVersionHelper(byte* minVersion, int version) #endif #ifdef WOLFSSL_TLS13 case WOLFSSL_TLSV1_3: + #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_DTLS13) + if (major == DTLS_MAJOR) + return BAD_FUNC_ARG; + #endif *minVersion = TLSv1_3_MINOR; break; #endif @@ -2218,6 +2231,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; } @@ -2242,7 +2259,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; @@ -2285,7 +2303,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); @@ -2408,6 +2427,8 @@ int wolfSSL_SetVersion(WOLFSSL* ssl, int version) ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, ssl->options.useAnon, TRUE, TRUE, TRUE, TRUE, ssl->options.side); + if (FilterSuitesForVersion(ssl) != 0) + return WOLFSSL_FAILURE; return WOLFSSL_SUCCESS; } #endif /* !leanpsk */ @@ -3334,8 +3355,53 @@ int wolfSSL_CTX_set_cipher_list_bytes(WOLFSSL_CTX* ctx, const byte* list, } #endif /* OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES */ +/* Builds the default suites for pv into suites, keeping existing sigalgs. */ +static void InitSslDefaultSuites(WOLFSSL* ssl, Suites* suites, + ProtocolVersion pv) +{ + word16 haveRSA = 1; + word16 havePSK = 0; + int keySz = 0; + +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif +#ifdef NO_RSA + haveRSA = 0; +#endif +#ifndef NO_CERTS + keySz = ssl->buffers.keySz; +#endif + InitSuites_EitherSide(suites, pv, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.useAnon, ssl->options.side); +} + +/* Returns the unfiltered list an SSL setter changes. A default list is first + * rebuilt for the newest version, so a merge finds its TLS 1.3 suites. */ +static Suites* SslSuitesToSet(WOLFSSL* ssl) +{ + Suites* suites = (ssl->suitesUser != NULL) ? ssl->suitesUser : + ssl->suites; + + if (!suites->setSuites && ssl->options.side != WOLFSSL_NEITHER_END) + InitSslDefaultSuites(ssl, suites, SslNewestVersion(ssl)); + return suites; +} + +/* Filters the list an SSL setter changed for the SSL's version. */ +static int SslSuitesSetDone(WOLFSSL* ssl, int ret) +{ + if (ResetSuitesForVersion(ssl) != 0) + ret = WOLFSSL_FAILURE; + return ret; +} + int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list) { + int ret; + Suites* suites; + WOLFSSL_ENTER("wolfSSL_set_cipher_list"); if (ssl == NULL || ssl->ctx == NULL) { @@ -3345,19 +3411,24 @@ int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list) if (AllocateSuites(ssl) != 0) return WOLFSSL_FAILURE; + suites = SslSuitesToSet(ssl); #ifdef OPENSSL_EXTRA - return wolfSSL_parse_cipher_list(NULL, ssl, ssl->suites, list); + ret = wolfSSL_parse_cipher_list(NULL, ssl, suites, list); #else - return (SetCipherList_ex(NULL, ssl, ssl->suites, list)) ? + ret = (SetCipherList_ex(NULL, ssl, suites, list)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; #endif + return SslSuitesSetDone(ssl, ret); } #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES) int wolfSSL_set_cipher_list_bytes(WOLFSSL* ssl, const byte* list, const int listSz) { + int ret; + Suites* suites; + WOLFSSL_ENTER("wolfSSL_set_cipher_list_bytes"); if (ssl == NULL || ssl->ctx == NULL) { @@ -3367,9 +3438,11 @@ int wolfSSL_set_cipher_list_bytes(WOLFSSL* ssl, const byte* list, if (AllocateSuites(ssl) != 0) return WOLFSSL_FAILURE; - return (SetCipherListFromBytes(ssl->ctx, ssl->suites, list, listSz)) + suites = SslSuitesToSet(ssl); + ret = (SetCipherListFromBytes(ssl->ctx, suites, list, listSz)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + return SslSuitesSetDone(ssl, ret); } #endif /* OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES */ @@ -4882,6 +4955,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_SERVER_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 @@ -5041,6 +5203,69 @@ static int CheckSslMethodVersion(byte major, unsigned long options) return WOLFSSL_SUCCESS; } +#ifdef WOLFSSL_DTLS +/* Returns 0 when the CTX mask and minimum leave no DTLS version. */ +static int CtxDtlsVersionLeft(const WOLFSSL_CTX* ctx) +{ + byte minor; + + if (ctx->method->version.major != DTLS_MAJOR) + return 1; + minor = DtlsMaskAllowedMinor(ctx->mask, ctx->method->version.minor, + ctx->minDowngrade); + if (minor == 0 || + (!ctx->method->downgrade && minor != ctx->method->version.minor)) { + WOLFSSL_MSG("All compiled in DTLS versions disabled"); + return 0; + } + return 1; +} +#endif + +/* The CTX version settings a rejected minimum or maximum restores. */ +typedef struct CtxVersionState { + unsigned long mask; + ProtocolVersion version; + byte minDowngrade; + byte minVersionSet; + word16 minProto:1; + word16 maxProto:1; +} CtxVersionState; + +static void CtxVersionSave(const WOLFSSL_CTX* ctx, CtxVersionState* st) +{ + st->mask = ctx->mask; + st->version = ctx->method->version; + st->minDowngrade = ctx->minDowngrade; + st->minVersionSet = ctx->minVersionSet; + st->minProto = ctx->minProto; + st->maxProto = ctx->maxProto; +} + +static int CtxVersionRestore(WOLFSSL_CTX* ctx, const CtxVersionState* st, + int ret) +{ + if (ret != WOLFSSL_SUCCESS && (ctx->method->version.major == DTLS_MAJOR || + !ctx->method->downgrade)) { + ctx->mask = st->mask; + ctx->method->version = st->version; + ctx->minDowngrade = st->minDowngrade; + ctx->minVersionSet = st->minVersionSet; + ctx->minProto = st->minProto; + ctx->maxProto = st->maxProto; + } + return ret; +} + +/* Returns <0, >0 or 0 as ver is below, above or at a fixed TLS method's + * version, and 0 for any other method or version. */ +static int FixedTlsVersionCmp(ProtocolVersion pv, int downgrade, int ver) +{ + if (pv.major != SSLv3_MAJOR || downgrade || (ver >> 8) != SSLv3_MAJOR) + return 0; + return (ver & 0xff) - pv.minor; +} + /** * protoVerTbl holds (D)TLS version numbers in ascending order. * Except DTLS versions, the newer version is located in the latter part of @@ -5054,7 +5279,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)) @@ -5078,8 +5306,10 @@ 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. + * protocol versions are left enabled or the version is above the + * version of a method that cannot downgrade. */ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) { @@ -5088,6 +5318,11 @@ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) if (ctx == NULL) { return WOLFSSL_FAILURE; } + if (FixedTlsVersionCmp(ctx->method->version, ctx->method->downgrade, + version) > 0) { + WOLFSSL_MSG("Minimum above the fixed TLS version"); + return WOLFSSL_FAILURE; + } switch (version) { #ifndef NO_TLS @@ -5126,11 +5361,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 @@ -5154,6 +5398,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: @@ -5161,6 +5408,10 @@ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) return WOLFSSL_FAILURE; } +#ifdef WOLFSSL_DTLS + if (!CtxDtlsVersionLeft(ctx)) + return WOLFSSL_FAILURE; +#endif return CheckSslMethodVersion(ctx->method->version.major, ctx->mask); } @@ -5173,12 +5424,21 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) int maxProto = 0; int i; int idx = 0; + CtxVersionState st; WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_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 + CtxVersionSave(ctx, &st); if (version != 0) { proto = version; @@ -5210,7 +5470,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); @@ -5222,6 +5482,7 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) ctx->minVersionSet = (version != 0); } + ret = CtxVersionRestore(ctx, &st, ret); return ret; } @@ -5244,8 +5505,10 @@ 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. + * protocol versions are left enabled or the version is below the + * version of a method that cannot downgrade. */ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) { @@ -5256,6 +5519,18 @@ 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 + if (FixedTlsVersionCmp(ctx->method->version, ctx->method->downgrade, + ver) < 0) { + WOLFSSL_MSG("Maximum below the fixed TLS version"); + return WOLFSSL_FAILURE; + } switch (ver) { #ifndef NO_TLS @@ -5281,9 +5556,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"); @@ -5309,6 +5595,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; @@ -5320,33 +5609,50 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) switch (ver) { #ifndef NO_TLS case SSL3_VERSION: - ctx->method->version.minor = SSLv3_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = SSLv3_MINOR; break; case TLS1_VERSION: - ctx->method->version.minor = TLSv1_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = TLSv1_MINOR; break; case TLS1_1_VERSION: - ctx->method->version.minor = TLSv1_1_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = TLSv1_1_MINOR; break; case TLS1_2_VERSION: - ctx->method->version.minor = TLSv1_2_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = TLSv1_2_MINOR; break; case TLS1_3_VERSION: - ctx->method->version.minor = TLSv1_3_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = TLSv1_3_MINOR; break; #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: - ctx->method->version.minor = DTLS_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = DTLS_MINOR; break; case DTLS1_2_VERSION: - ctx->method->version.minor = DTLSv1_2_MINOR; + if (ctx->method->downgrade) + ctx->method->version.minor = DTLSv1_2_MINOR; + break; + #ifdef WOLFSSL_DTLS13 + case DTLS1_3_VERSION: + if (ctx->method->downgrade) + ctx->method->version.minor = DTLSv1_3_MINOR; break; + #endif #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } + #ifdef WOLFSSL_DTLS + if (!CtxDtlsVersionLeft(ctx)) + ret = WOLFSSL_FAILURE; + #endif } return ret; } @@ -5360,12 +5666,14 @@ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); int minProto; byte minVersionSet; + CtxVersionState st; WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version"); if (ctx == NULL) { return ret; } + CtxVersionSave(ctx, &st); /* clear out flags and reset min protocol version */ minProto = wolfSSL_CTX_get_min_proto_version(ctx); @@ -5377,7 +5685,9 @@ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) ctx->minVersionSet = minVersionSet; /* restoring, not setting, a minimum */ if (version != 0) { ctx->maxProto = 0; /* turn max proto flag off */ - return Set_CTX_max_proto_version(ctx, version); + ret = Set_CTX_max_proto_version(ctx, version); + ret = CtxVersionRestore(ctx, &st, ret); + return ret; } /* when 0 is specified as version, try to find out the min version from @@ -5391,6 +5701,7 @@ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) } } + ret = CtxVersionRestore(ctx, &st, ret); return ret; } @@ -5402,6 +5713,23 @@ 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 + if (FixedTlsVersionCmp(ssl->version, ssl->options.downgrade, ver) > 0) { + WOLFSSL_MSG("Minimum above the fixed TLS version"); + return WOLFSSL_FAILURE; + } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR && !ssl->options.downgrade && + DtlsMinDowngrade((byte)ver) < ssl->version.minor) { + WOLFSSL_MSG("Minimum above the fixed DTLS version"); + return WOLFSSL_FAILURE; + } +#endif switch (ver) { #ifndef NO_TLS @@ -5440,11 +5768,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 @@ -5468,6 +5805,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: @@ -5511,6 +5851,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"); @@ -5518,6 +5865,18 @@ 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 + if (FixedTlsVersionCmp(ssl->version, ssl->options.downgrade, ver) < 0) { + WOLFSSL_MSG("Maximum below the fixed TLS version"); + return WOLFSSL_FAILURE; + } switch (ver) { case SSL2_VERSION: @@ -5541,15 +5900,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); } @@ -5563,6 +5959,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); } @@ -5608,6 +6013,21 @@ 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; + #ifdef WOLFSSL_DTLS13 + case DTLSv1_3_MINOR: + ret = DTLS1_3_VERSION; + break; + #endif #endif default: ret = 0; @@ -5672,12 +6092,31 @@ static int GetMaxProtoVersion(long options) return WOLFSSL_FATAL_ERROR; } +/* Returns the WOLFSSL_OP_NO_* bit that disables a TLS version. */ +static long TlsVersionMaskBit(int version) +{ + switch (version) { + case SSL3_VERSION: + return WOLFSSL_OP_NO_SSLv3; + case TLS1_VERSION: + return WOLFSSL_OP_NO_TLSv1; + case TLS1_1_VERSION: + return WOLFSSL_OP_NO_TLSv1_1; + case TLS1_2_VERSION: + return WOLFSSL_OP_NO_TLSv1_2; + default: + return WOLFSSL_OP_NO_TLSv1_3; + } +} /* returns the maximum protocol version for 'ctx' */ 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"); @@ -5688,6 +6127,22 @@ 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 if ((ctx != NULL) && !ctx->method->downgrade) { + ret = (SSLv3_MAJOR << 8) | ctx->method->version.minor; + if ((options & TlsVersionMaskBit(ret)) != 0 || + ctx->minDowngrade > ctx->method->version.minor) + ret = WOLFSSL_FATAL_ERROR; + } else { ret = GetMaxProtoVersion(options); } @@ -5921,6 +6376,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; @@ -5941,10 +6399,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) { @@ -7580,30 +8036,186 @@ static long wolf_set_options(long old_op, long op) return old_op | op; } -static int FindHashSig(const Suites* suites, byte first, byte second) +/* Returns the newest minor version built for a major version. */ +static byte NewestMinor(byte major) +{ +#ifdef WOLFSSL_DTLS + if (major == DTLS_MAJOR) { + #ifdef WOLFSSL_DTLS13 + return DTLSv1_3_MINOR; + #else + return DTLSv1_2_MINOR; + #endif + } +#endif + (void)major; +#ifdef WOLFSSL_TLS13 + return TLSv1_3_MINOR; +#else + return TLSv1_2_MINOR; +#endif +} + +/* Default suites and sigalgs of a version and of the newest version. */ +typedef struct SuitesFilter { + Suites allowed; + Suites newest; +} SuitesFilter; + +static void InitSuitesFilter(SuitesFilter* f, ProtocolVersion pv) +{ + ProtocolVersion newest = pv; + + XMEMSET(f, 0, sizeof(SuitesFilter)); + newest.minor = NewestMinor(pv.major); + /* Client side so the server's key type removes nothing, and + * SUITES_NULL_EXPLICIT keeps a configured integrity-only suite. */ + InitSuites(&f->allowed, pv, 0, 1, 1, 1, 1, 1, 1, 1, 1, + SUITES_NULL_EXPLICIT, 1, 1, 1, WOLFSSL_CLIENT_END); + InitSuites(&f->newest, newest, 0, 1, 1, 1, 1, 1, 1, 1, 1, + SUITES_NULL_EXPLICIT, 1, 1, 1, WOLFSSL_CLIENT_END); +} + +static int HashSigIn(const Suites* suites, const byte* sigAlg) { word16 i; - if (suites == NULL || suites->hashSigAlgoSz == 0) { - WOLFSSL_MSG("Suites pointer error or suiteSz 0"); - return SUITES_ERROR; + for (i = 0; i + 1 < suites->hashSigAlgoSz; i += 2) { + if (suites->hashSigAlgo[i] == sigAlg[0] && + suites->hashSigAlgo[i+1] == sigAlg[1]) + return 1; } + return 0; +} + +static int SuiteKept(const SuitesFilter* f, const byte* suite) +{ + return f == NULL || FindSuite(&f->allowed, suite[0], suite[1]) >= 0 || + FindSuite(&f->newest, suite[0], suite[1]) < 0; +} + +static int SigAlgKept(const SuitesFilter* f, const byte* sigAlg) +{ + return f == NULL || HashSigIn(&f->allowed, sigAlg) || + !HashSigIn(&f->newest, sigAlg); +} - for (i = 0; i < suites->hashSigAlgoSz-1; i += 2) { - if (suites->hashSigAlgo[i] == first && - suites->hashSigAlgo[i+1] == second ) - return i; +/* Copies the entries of src that f keeps into out, the suites only when they + * are user-set, and returns how many it left out. A NULL out only counts. */ +static int FilterSuites(Suites* out, const Suites* src, const SuitesFilter* f, + int setSuites) +{ + word16 in; + word16 sz = 0; + int dropped = 0; + + if (setSuites) { + for (in = 0; in < src->suiteSz; in += SUITE_LEN) { + if (!SuiteKept(f, &src->suites[in])) { + dropped++; + } + else { + if (out != NULL) { + out->suites[sz] = src->suites[in]; + out->suites[sz+1] = src->suites[in+1]; + } + sz += SUITE_LEN; + } + } + if (out != NULL) + out->suiteSz = sz; + } + sz = 0; + for (in = 0; in < src->hashSigAlgoSz; in += 2) { + if (SigAlgKept(f, &src->hashSigAlgo[in])) { + if (out != NULL) { + out->hashSigAlgo[sz] = src->hashSigAlgo[in]; + out->hashSigAlgo[sz+1] = src->hashSigAlgo[in+1]; + } + sz += 2; + } } + /* An empty list means the defaults, so keep the list as it is instead. */ + if (sz == 0) { + sz = src->hashSigAlgoSz; + if (out != NULL && out != src) + XMEMCPY(out->hashSigAlgo, src->hashSigAlgo, sz); + } + else { + dropped += (src->hashSigAlgoSz - sz) / 2; + } + if (out != NULL) + out->hashSigAlgoSz = sz; + return dropped; +} + +/* Filters ssl->suites for its version from the unfiltered copy in suitesUser, + * saving the copy the first time an entry has to go. */ +int FilterSuitesForVersion(WOLFSSL* ssl) +{ + int ret = 0; + int setSuites; +#ifdef WOLFSSL_SMALL_STACK + SuitesFilter* f; +#else + SuitesFilter f[1]; +#endif - return MATCH_SUITE_ERROR; + if (ssl->suites == NULL) + return 0; + setSuites = ssl->suites->setSuites; + if (ssl->version.minor == NewestMinor(ssl->version.major)) { + if (ssl->suitesUser != NULL) + (void)FilterSuites(ssl->suites, ssl->suitesUser, NULL, setSuites); + return 0; + } +#ifdef WOLFSSL_SMALL_STACK + f = (SuitesFilter*)XMALLOC(sizeof(SuitesFilter), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (f == NULL) + return MEMORY_E; +#endif + InitSuitesFilter(f, ssl->version); + if (ssl->suitesUser == NULL && + FilterSuites(NULL, ssl->suites, f, setSuites) > 0) { + ssl->suitesUser = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, + DYNAMIC_TYPE_SUITES); + if (ssl->suitesUser == NULL) { + (void)FilterSuites(ssl->suites, ssl->suites, f, setSuites); + ret = MEMORY_E; + } + else { + XMEMCPY(ssl->suitesUser, ssl->suites, sizeof(Suites)); + } + } + if (ret == 0 && ssl->suitesUser != NULL) + (void)FilterSuites(ssl->suites, ssl->suitesUser, f, setSuites); +#ifdef WOLFSSL_SMALL_STACK + XFREE(f, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; } -long wolfSSL_set_options(WOLFSSL* ssl, long op) +/* Rebuilds the default cipher suites for the current protocol version and + * filters the list with FilterSuitesForVersion(). */ +int ResetSuitesForVersion(WOLFSSL* ssl) { - word16 haveRSA = 1; - word16 havePSK = 0; - int keySz = 0; + if (ssl->options.side == WOLFSSL_NEITHER_END) { + if (ssl->suitesUser == NULL || ssl->suites == NULL) + return 0; + } + else if (AllocateSuites(ssl) != 0) { + return MEMORY_E; + } + if (ssl->suitesUser != NULL) + ssl->suites->setSuites = ssl->suitesUser->setSuites; + if (!ssl->suites->setSuites && ssl->options.side != WOLFSSL_NEITHER_END) + InitSslDefaultSuites(ssl, ssl->suites, ssl->version); + return FilterSuitesForVersion(ssl); +} +long wolfSSL_set_options(WOLFSSL* ssl, long op) +{ WOLFSSL_ENTER("wolfSSL_set_options"); if (ssl == NULL) { @@ -7650,81 +8262,14 @@ long wolfSSL_set_options(WOLFSSL* ssl, long op) } #endif - - /* in the case of a version change the cipher suites should be reset */ -#ifndef NO_PSK - havePSK = ssl->options.havePSK; -#endif -#ifdef NO_RSA - haveRSA = 0; -#endif -#ifndef NO_CERTS - keySz = ssl->buffers.keySz; +#ifdef WOLFSSL_DTLS + ssl->options.dtlsMaxMask &= (unsigned long)~op; + (void)DtlsMaskVersion(ssl, DTLS_MASK_START); #endif - if (ssl->options.side != WOLFSSL_NEITHER_END) { - if (AllocateSuites(ssl) != 0) - return 0; - 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) - InitSuites(ssl->suites, ssl->version, keySz, haveRSA, - havePSK, TRUE, ssl->options.haveECDSAsig, - ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, - ssl->options.useAnon, - TRUE, TRUE, TRUE, TRUE, ssl->options.side); - else - InitSuites(ssl->suites, ssl->version, keySz, haveRSA, - havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, - ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, - ssl->options.useAnon, - TRUE, TRUE, TRUE, TRUE, ssl->options.side); - } - else { - /* Only preserve overlapping suites */ - Suites tmpSuites; - word16 in, out; - word16 haveECDSAsig, haveStaticECC; -#ifdef NO_RSA - haveECDSAsig = 1; - haveStaticECC = 1; -#else - haveECDSAsig = 0; - haveStaticECC = ssl->options.haveStaticECC; -#endif - XMEMSET(&tmpSuites, 0, sizeof(Suites)); - /* Get all possible ciphers and sigalgs for the version. Following - * options limit the allowed ciphers so let's try to get as many as - * possible. - * - haveStaticECC turns off haveRSA - * - haveECDSAsig turns off haveRSAsig - * - SUITES_NULL_EXPLICIT includes the integrity-only suites, so - * an explicitly configured one is preserved */ - InitSuites(&tmpSuites, ssl->version, 0, 1, 1, 1, haveECDSAsig, 1, 1, - haveStaticECC, 1, SUITES_NULL_EXPLICIT, 1, 1, 1, - ssl->options.side); - for (in = 0, out = 0; in < ssl->suites->suiteSz; in += SUITE_LEN) { - if (FindSuite(&tmpSuites, ssl->suites->suites[in], - ssl->suites->suites[in+1]) >= 0) { - ssl->suites->suites[out] = ssl->suites->suites[in]; - ssl->suites->suites[out+1] = ssl->suites->suites[in+1]; - out += SUITE_LEN; - } - } - ssl->suites->suiteSz = out; - for (in = 0, out = 0; in < ssl->suites->hashSigAlgoSz; in += 2) { - if (FindHashSig(&tmpSuites, ssl->suites->hashSigAlgo[in], - ssl->suites->hashSigAlgo[in+1]) >= 0) { - ssl->suites->hashSigAlgo[out] = - ssl->suites->hashSigAlgo[in]; - ssl->suites->hashSigAlgo[out+1] = - ssl->suites->hashSigAlgo[in+1]; - out += 2; - } - } - ssl->suites->hashSigAlgoSz = out; - } - } + /* in the case of a version change the cipher suites should be reset */ + if (ResetSuitesForVersion(ssl) != 0) + return 0; return (long)ssl->options.mask; } @@ -7787,10 +8332,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_ext.c b/src/ssl_api_ext.c index 412babadbea..cdc80c4afaf 100644 --- a/src/ssl_api_ext.c +++ b/src/ssl_api_ext.c @@ -2139,7 +2139,8 @@ int wolfSSL_set1_sigalgs_list(WOLFSSL* ssl, const char* list) ret = WOLFSSL_FAILURE; } else { - ret = SetSuitesHashSigAlgo(ssl->suites, list); + ret = SetSuitesHashSigAlgo(SslSuitesToSet(ssl), list); + ret = SslSuitesSetDone(ssl, ret); } return ret; diff --git a/src/ssl_api_hs.c b/src/ssl_api_hs.c index 257951af4a1..0fb0cacfda1 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 c1ef5472e89..faaf5afbe29 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -1749,6 +1749,12 @@ 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 + /* No version left is reported when the handshake starts. */ + ret = DtlsCheckVersionMask(ssl, DTLS_MASK_START); + if (ret < 0 && ret != WC_NO_ERR_TRACE(VERSION_ERROR)) + return WOLFSSL_FAILURE; +#endif return WOLFSSL_SUCCESS; } diff --git a/src/tls.c b/src/tls.c index a9277c3220d..667f5084ce7 100644 --- a/src/tls.c +++ b/src/tls.c @@ -169,6 +169,9 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap); #ifdef HAVE_SUPPORTED_CURVES static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions); +#if defined(HAVE_ECC) && defined(HAVE_ECC_BRAINPOOL) +static int TLSX_PreTls13Reachable(const WOLFSSL* ssl); +#endif #endif #if defined(HAVE_ECC) && !defined(NO_ECC_SECP) @@ -5280,15 +5283,15 @@ static int TLSX_DefaultGroupAllowed(const WOLFSSL* ssl, word16 name) case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: return IsAtLeastTLSv1_3(ssl->version); + #if defined(HAVE_ECC) && defined(HAVE_ECC_BRAINPOOL) /* RFC 7027 codepoints, also offered by TLS 1.3 when it may fall back * to TLS 1.2. */ case WOLFSSL_ECC_BRAINPOOLP256R1: case WOLFSSL_ECC_BRAINPOOLP384R1: case WOLFSSL_ECC_BRAINPOOLP512R1: return !IsAtLeastTLSv1_3(ssl->version) || - (ssl->options.downgrade && - (ssl->options.minDowngrade <= TLSv1_2_MINOR || - ssl->options.minDowngrade <= DTLSv1_2_MINOR)); + TLSX_PreTls13Reachable(ssl); + #endif default: return 1; } @@ -7965,6 +7968,15 @@ int TLSX_SupportedVersions_Parse(const WOLFSSL* ssl, const byte* input, if (versionIsLesser(isDtls, minor, ssl->options.minDowngrade)) continue; } + #ifdef WOLFSSL_DTLS + /* The ClientHello after an HRR keeps the version the HRR chose. */ + if (isDtls && ssl->options.downgrade && + ssl->options.serverState != + SERVER_HELLO_RETRY_REQUEST_COMPLETE && + DtlsAllowedMinor(ssl, minor, DTLS_MINOR) != minor) { + continue; + } + #endif if (versionIsGreater(isDtls, minor, clientGreatestMinor)) clientGreatestMinor = minor; @@ -16679,6 +16691,58 @@ 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) { @@ -16697,6 +16761,51 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) return WOLFSSL_SUCCESS; } +#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) @@ -16736,7 +16845,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; @@ -17163,6 +17273,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 @@ -17379,9 +17494,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; @@ -17418,7 +17533,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) @@ -17475,7 +17591,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) @@ -18034,7 +18150,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 869d0665b8c..5551cabfe55 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -16783,6 +16783,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) { @@ -18071,6 +18089,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 403545cd342..2165ddee5e0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -21396,6 +21396,17 @@ static int test_wolfSSL_set1_sigalgs_list(void) ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA+SHA256+RSA"), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA+SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA+SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "RSA+BOGUS"), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA+BOGUS"), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(ctx == NULL ? 0 : ctx->suites->hashSigAlgoSz, 2); + ExpectIntEQ(ssl == NULL ? 0 : WOLFSSL_SUITES(ssl)->hashSigAlgoSz, 2); + { const char entry[] = "RSA+SHA256"; const int entryLen = (int)sizeof(entry) - 1; @@ -48259,6 +48270,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 24aa2593ba2..9c121b78c82 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -16532,3 +16532,2075 @@ int test_dtls_set_rfd_wfd(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_method(int sessionFirst, long firstOpts, + long secondOpts, int expVersion, method_provider method) +{ + 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; + + wolfSSL_CTX_free(ctx_c); + ctx_c = NULL; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + 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(ssl_c->options.resuming, 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(); +} + +/* Runs test_dtls13_mask_session_method() with a client and, when built, an + * either-side object that becomes the client. */ +static int test_dtls13_mask_session(int sessionFirst, long firstOpts, + long secondOpts, int expVersion) +{ + EXPECT_DECLS; + + ExpectIntEQ(test_dtls13_mask_session_method(sessionFirst, firstOpts, + secondOpts, expVersion, wolfDTLS_client_method), TEST_SUCCESS); +#ifdef WOLFSSL_EITHER_SIDE + ExpectIntEQ(test_dtls13_mask_session_method(sessionFirst, firstOpts, + secondOpts, expVersion, wolfDTLS_method), TEST_SUCCESS); +#endif + 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, nor the one a stateful HRR chose. */ +static int test_dtls13_mask_in_client_hello(int hrr) +{ + 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); + if (hrr) { + ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), 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 never moves a fixed DTLS method, and one below it fails. */ +static int test_dtls13_ctx_max_proto_fixed(method_provider method, int ver) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + long mask = 0; + + 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), + ver == DTLS1_2_VERSION ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); +#ifndef NO_OLD_TLS + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_VERSION), + WOLFSSL_FAILURE); +#endif + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, DTLS1_3_VERSION), + 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), ver); + if (ver == DTLS1_2_VERSION) { + if (ssl_c != NULL) + mask = wolfSSL_get_options(ssl_c); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl_c, TLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl_c), mask); + } + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), ver); + + 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(); +} + +#if defined(BUILD_TLS_AES_128_GCM_SHA256) && defined(HAVE_ECC) && \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) && \ + defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) +#ifdef WOLFSSL_SHA224 + #define TEST_DTLS13_SA_SHA224 ":ECDSA+SHA224" +#else + #define TEST_DTLS13_SA_SHA224 "" +#endif +#if !defined(NO_SHA) && \ + (!defined(NO_OLD_TLS) || defined(WOLFSSL_ALLOW_TLS_SHA1)) + #define TEST_DTLS13_SA_SHA1 ":ECDSA+SHA1" +#else + #define TEST_DTLS13_SA_SHA1 "" +#endif + +static int test_dtls13_has_suite(const WOLFSSL* ssl, byte first, byte second) +{ + word16 i; + + for (i = 0; ssl != NULL && ssl->suites != NULL && + i < ssl->suites->suiteSz; i += SUITE_LEN) { + if (ssl->suites->suites[i] == first && + ssl->suites->suites[i+1] == second) + return 1; + } + return 0; +} + +static int test_dtls13_has_sigalg(WOLFSSL* ssl, byte first, byte second) +{ + const Suites* suites = (ssl != NULL) ? WOLFSSL_SUITES(ssl) : NULL; + word16 i; + + for (i = 0; suites != NULL && i + 1 < suites->hashSigAlgoSz; i += 2) { + if (suites->hashSigAlgo[i] == first && + suites->hashSigAlgo[i+1] == second) + return 1; + } + return 0; +} + +static int test_dtls13_suites_eq(const WOLFSSL* ssl, const Suites* exp) +{ + return ssl != NULL && ssl->suites != NULL && + ssl->suites->suiteSz == exp->suiteSz && + ssl->suites->hashSigAlgoSz == exp->hashSigAlgoSz && + XMEMCMP(ssl->suites->suites, exp->suites, exp->suiteSz) == 0 && + XMEMCMP(ssl->suites->hashSigAlgo, exp->hashSigAlgo, + exp->hashSigAlgoSz) == 0; +} + +/* Lifting a cap restores a user list with what modes 1-4 change while capped: + * sigalgs, the TLS 1.2 suites, the whole list by bytes, an unrelated option. */ +static int test_dtls13_mask_lift_list_mode(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; + Suites exp; + static const byte tls13Ecdsa[] = { + TLS13_BYTE, TLS_AES_128_GCM_SHA256, + ECC_BYTE, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + XMEMSET(&exp, 0, sizeof(exp)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ssl = onServer ? ssl_s : ssl_c; + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, + "TLS13-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); +#ifdef HAVE_ECC_BRAINPOOL + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, + "ECDSA+SHA256:ECDSA-BRAINPOOL+SHA256"), WOLFSSL_SUCCESS); +#endif + if (ssl != NULL && ssl->suites != NULL) + XMEMCPY(&exp, ssl->suites, sizeof(exp)); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + if (ssl != NULL && ssl->suites != NULL) + ExpectIntEQ(ssl->suites->suiteSz, exp.suiteSz - SUITE_LEN); + if (mode == 1) { + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "ECDSA+SHA256" + TEST_DTLS13_SA_SHA224 TEST_DTLS13_SA_SHA1), WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_sigalg(ssl, sha224_mac, ecc_dsa_sa_algo), + TEST_DTLS13_SA_SHA224[0] != '\0'); + ExpectIntEQ(test_dtls13_has_sigalg(ssl, sha_mac, ecc_dsa_sa_algo), + TEST_DTLS13_SA_SHA1[0] != '\0'); + if (ssl != NULL && ssl->suites != NULL) { + exp.hashSigAlgoSz = ssl->suites->hashSigAlgoSz; + XMEMCPY(exp.hashSigAlgo, ssl->suites->hashSigAlgo, + exp.hashSigAlgoSz); + } + } + else if (mode == 2) { + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, + "ECDHE-ECDSA-AES128-GCM-SHA256"), WOLFSSL_SUCCESS); + } + else if (mode == 3) { + ExpectIntEQ(wolfSSL_set_cipher_list_bytes(ssl, tls13Ecdsa, + (int)sizeof(tls13Ecdsa)), WOLFSSL_SUCCESS); + } + else if (mode == 4) { + if (ssl != NULL) + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_COMPRESSION); + } + if (mode == 2 || mode == 3) { + ExpectTrue(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)); + ExpectFalse(test_dtls13_has_suite(ssl, TLS13_BYTE, + TLS_AES_128_GCM_SHA256)); + } + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + if (mode == 2 || mode == 3) { + ExpectTrue(test_dtls13_has_suite(ssl, TLS13_BYTE, + TLS_AES_128_GCM_SHA256)); + ExpectTrue(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)); + ExpectFalse(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)); + } + else { + ExpectTrue(test_dtls13_suites_eq(ssl, &exp)); + } + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + ExpectStrEQ(wolfSSL_get_cipher_name(ssl_c), "TLS13-AES128-GCM-SHA256"); + + 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_lift_cipher_list(int onServer) +{ + EXPECT_DECLS; + int mode; + + for (mode = 0; mode <= 4; mode++) { + ExpectIntEQ(test_dtls13_mask_lift_list_mode(onServer, mode), + TEST_SUCCESS); + } + return EXPECT_RESULT(); +} + +/* A list set while capped, by name or keyword, or the default list, is filtered + * for the cap and gets its TLS 1.3 suites and sigalgs back on a lift. */ +static int test_dtls13_mask_list_after_cap(int onServer, const char* list) +{ + 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; + const byte oddList[] = { TLS13_BYTE, TLS_AES_128_GCM_SHA256, ECC_BYTE }; + + 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_use_certificate_file(ssl_s, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ssl = onServer ? ssl_s : ssl_c; + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + if (list != NULL) { + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, list), WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "BOGUS-CIPHER"), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_cipher_list_bytes(ssl, oddList, sizeof(oddList)), + WOLFSSL_FAILURE); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl), 0); +#ifdef HAVE_ECC_BRAINPOOL + ExpectIntEQ(test_dtls13_has_sigalg(ssl, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), 0); +#endif + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl), 1); + if (list != NULL && XSTRCMP(list, "HIGH") != 0) { + ExpectIntEQ(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), 0); + } +#ifdef HAVE_ECC_BRAINPOOL + /* A named list gets TLS 1.3 sigalgs only when it names a TLS 1.3 suite. */ + ExpectIntEQ(test_dtls13_has_sigalg(ssl, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), + list == NULL || XSTRSTR(list, "TLS13") != NULL || + XSTRCMP(list, "HIGH") == 0); +#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(); +} + +#if defined(WOLFSSL_EITHER_SIDE) && defined(HAVE_ECC_BRAINPOOL) +/* An either-side SSL capped before it picks a side drops the TLS 1.3 sigalgs + * once it becomes the client. */ +static int test_dtls13_mask_either_side_sigalgs(int dtls) +{ + EXPECT_DECLS; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(dtls ? wolfDTLS_method() : + wolfSSLv23_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + if (ssl != NULL) + wolfSSL_set_connect_state(ssl); + ExpectIntEQ(wolfSSL_version(ssl), dtls ? DTLS1_2_VERSION : + TLS1_2_VERSION); + ExpectIntEQ(test_dtls13_has_sigalg(ssl, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} + +/* A list set on an SSL with no side, after wolfSSL_SetVersion() filtered its + * suites, is the one it uses once it becomes the client. */ +static int test_dtls13_either_side_list(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_SetVersion(ssl, WOLFSSL_TLSV1_2), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ECDHE-ECDSA-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); + if (ssl != NULL) + wolfSSL_set_connect_state(ssl); + ExpectIntEQ(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), 1); + ExpectIntEQ(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} +#endif + +#ifdef HAVE_ECC_BRAINPOOL +/* Sigalgs set on a default list survive a cap, a failed set and a lift, and a + * list the cap would empty is kept as it is. */ +static int test_dtls13_mask_default_list_sigalgs(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_use_certificate_file(ssl_s, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, + "ECDSA+SHA256:ECDSA-BRAINPOOL+SHA256"), WOLFSSL_SUCCESS); + if (ssl_c != NULL && ssl_c->suites != NULL) + ExpectIntEQ(ssl_c->suites->hashSigAlgoSz, 4); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_sigalg(ssl_c, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), 0); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "NONE+SHA256"), + WOLFSSL_FAILURE); + ExpectIntEQ(test_dtls13_has_sigalg(ssl_c, sha256_mac, ecc_dsa_sa_algo), + 1); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_sigalg(ssl_c, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), 1); + if (ssl_c != NULL && ssl_c->suites != NULL) + ExpectIntEQ(ssl_c->suites->hashSigAlgoSz, 4); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + wolfSSL_free(ssl_c); + ssl_c = NULL; + + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl_c, "ECDSA-BRAINPOOL+SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_sigalg(ssl_c, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), 1); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) +/* A TLS 1.3 list set on a capped TLS server merges with defaults built for the + * ECC key the SSL loaded after wolfSSL_new(). */ +static int test_dtls13_tls_default_copy_key(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + if (ctx != NULL) + (void)wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_use_certificate_file(ssl, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), 1); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} +#endif +#endif + +#ifdef BUILD_WDM_WITH_NULL_SHA256 +/* The multicast suite, which no version lists by default, is not filtered. */ +static int test_dtls13_mask_mcast_suite(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_cipher_list(ssl, "WDM-NULL-SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_suite(ssl, CIPHER_BYTE, WDM_WITH_NULL_SHA256), + 1); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} +#endif + +/* A cipher list set after the CTX maximum was lowered keeps its TLS 1.3 suites + * on an SSL still at DTLS 1.3. */ +static int test_dtls13_ctx_lowered_cipher_list(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_CTX_set_max_proto_version(ctx_c, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), DTLS1_3_VERSION); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "HIGH"), WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl_c), 1); + 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(); +} + +#ifndef NO_WOLFSSL_CLIENT +/* wolfSSL_SetVersion() restores the suites a TLS mask filtered out, also from + * a TLS 1.2 list set under the mask. */ +static int test_dtls13_tls_set_version_suites(int listAfterMask) +{ + EXPECT_DECLS; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (!listAfterMask) { + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, + "TLS13-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); + } + if (ssl != NULL) + (void)wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + if (listAfterMask) { + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, + "ECDHE-ECDSA-AES128-GCM-SHA256"), WOLFSSL_SUCCESS); + } + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl), 0); + if (ssl != NULL) + (void)wolfSSL_clear_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_SetVersion(ssl, WOLFSSL_TLSV1_3), WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl), 1); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} +#endif + +/* A capped user list survives wolfSSL_clear() after a handshake and comes back + * on a lift. */ +static int test_dtls13_mask_clear_list(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_use_certificate_file(ssl_s, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, + "TLS13-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); + 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_c), DTLS1_2_VERSION); + ExpectIntEQ(wolfSSL_clear(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl_c), 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl_c), 1); + ExpectIntEQ(test_dtls13_has_suite(ssl_c, ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), 1); + 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.2 SSL drops the TLS 1.3 suites and sigalgs of a list it is given. */ +static int test_dtls13_tls12_cipher_list(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl, + "TLS13-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_dtls13_has_tls13_suite(ssl), 0); + ExpectIntEQ(test_dtls13_has_suite(ssl, ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), 1); +#ifdef HAVE_ECC_BRAINPOOL + ExpectIntEQ(test_dtls13_has_sigalg(ssl, NEW_SA_MAJOR, + ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR), 0); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + return EXPECT_RESULT(); +} +#endif + +/* 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(); +} + +/* A DTLS object refuses a TLS 1.3 minimum when DTLS 1.3 is not built. */ +int test_dtls_min_tls13_without_dtls13(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_DTLS13) && \ + defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_client_method())); + ExpectIntNE(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3), + WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntNE(wolfSSL_SetMinVersion(ssl, WOLFSSL_TLSV1_3), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#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, + DTLS1_3_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_ctx_max_proto_fixed(wolfDTLSv1_2_client_method, + DTLS1_2_VERSION), 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); + #if defined(BUILD_TLS_AES_128_GCM_SHA256) && defined(HAVE_ECC) && \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) && \ + defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + ExpectIntEQ(test_dtls13_mask_lift_cipher_list(onServer), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_list_after_cap(onServer, NULL), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_list_after_cap(onServer, + "TLS13-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256"), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_list_after_cap(onServer, "HIGH"), + TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_list_after_cap(onServer, + "ECDHE-ECDSA-AES128-GCM-SHA256"), TEST_SUCCESS); + #endif + #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); +#if defined(BUILD_TLS_AES_128_GCM_SHA256) && defined(HAVE_ECC) && \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) && \ + defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) +#ifndef NO_WOLFSSL_CLIENT + ExpectIntEQ(test_dtls13_tls_set_version_suites(0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_tls_set_version_suites(1), TEST_SUCCESS); +#endif + ExpectIntEQ(test_dtls13_mask_clear_list(), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_tls12_cipher_list(), TEST_SUCCESS); +#endif +#if defined(BUILD_TLS_AES_128_GCM_SHA256) && defined(HAVE_ECC) && \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) && \ + defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) && \ + defined(WOLFSSL_EITHER_SIDE) && defined(HAVE_ECC_BRAINPOOL) + ExpectIntEQ(test_dtls13_mask_either_side_sigalgs(1), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_either_side_sigalgs(0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_either_side_list(), TEST_SUCCESS); +#endif +#if defined(BUILD_TLS_AES_128_GCM_SHA256) && defined(HAVE_ECC) && \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) && \ + defined(BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + ExpectIntEQ(test_dtls13_ctx_lowered_cipher_list(), TEST_SUCCESS); +#ifdef HAVE_ECC_BRAINPOOL + ExpectIntEQ(test_dtls13_mask_default_list_sigalgs(), TEST_SUCCESS); +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) + ExpectIntEQ(test_dtls13_tls_default_copy_key(), TEST_SUCCESS); +#endif +#endif +#ifdef BUILD_WDM_WITH_NULL_SHA256 + ExpectIntEQ(test_dtls13_mask_mcast_suite(), TEST_SUCCESS); +#endif +#endif + 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(0), TEST_SUCCESS); + ExpectIntEQ(test_dtls13_mask_in_client_hello(1), 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_FAILURE); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_3, + WOLFSSL_OP_NO_TLSv1_3); + ExpectNull(wolfSSL_new(ctx)); + (void)wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, DTLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, DTLS1_2_VERSION), + WOLFSSL_FAILURE); +#ifdef NO_OLD_TLS + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, DTLS1_VERSION), + WOLFSSL_FAILURE); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_3_VERSION); + wolfSSL_free(ssl); + ssl = NULL; + wolfSSL_CTX_free(ctx); + ctx = NULL; + +#ifndef WOLFSSL_NO_TLS12 + /* A rejected CTX minimum leaves the CTX as it was. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_client_method())); + (void)wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, DTLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_version(ssl), DTLS1_2_VERSION); + wolfSSL_free(ssl); + ssl = NULL; + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + + /* A fixed DTLS 1.3 method has no version left once it is masked off. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); + (void)wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, DTLS1_2_VERSION), + WOLFSSL_FAILURE); + 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 99c342c31bf..3cfac3cbaa0 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -181,6 +181,9 @@ 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_dtls_set_rfd_wfd(void); +int test_dtls13_no_tls13_option(void); +int test_dtls_max_proto_after_clear(void); +int test_dtls_min_tls13_without_dtls13(void); int test_wolfSSL_dtls_export(void); int test_wolfSSL_dtls_import_dh_key_sz(void); int test_wolfSSL_dtls_export_peers(void); @@ -404,5 +407,8 @@ int test_dtls_no_cookie_ch_pause(WOLFSSL* ssl, void* ctx); 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_set_rfd_wfd) + TEST_DECL_GROUP("dtls", test_dtls_set_rfd_wfd), \ + TEST_DECL_GROUP("dtls", test_dtls13_no_tls13_option), \ + TEST_DECL_GROUP("dtls", test_dtls_max_proto_after_clear), \ + TEST_DECL_GROUP("dtls", test_dtls_min_tls13_without_dtls13) #endif /* TESTS_API_DTLS_H */ diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 61e1c86e62c..fb464e122e2 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -2963,6 +2963,165 @@ int test_tls_fallback_scsv_no_downgrade_runtime_max(void) return EXPECT_RESULT(); } +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(OPENSSL_EXTRA) +/* A maximum or minimum past a fixed TLS method fails and never moves it. */ +static int test_tls_max_proto_fixed_case(method_provider method, int ver) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + long mask = 0; + long verBit = (ver == TLS1_3_VERSION) ? WOLFSSL_OP_NO_TLSv1_3 : + WOLFSSL_OP_NO_TLSv1_2; + int minProto = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + method, wolfSSLv23_server_method), 0); + if (ctx_c != NULL) { + mask = wolfSSL_CTX_get_options(ctx_c); + minProto = wolfSSL_CTX_get_min_proto_version(ctx_c); + } + if (ver == TLS1_3_VERSION) { + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, TLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx_c), mask); + } + else { + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx_c, TLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx_c), mask); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx_c), minProto); + } + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, TLS1_1_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx_c), mask); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx_c), minProto); + ExpectIntEQ(ctx_c != NULL ? ctx_c->method->version.minor : 0, ver & 0xff); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx_c, ver), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx_c), ver); + if (ctx_c != NULL) { + wolfSSL_CTX_set_options(ctx_c, verBit); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx_c), 0); + wolfSSL_CTX_clear_options(ctx_c, verBit); + } + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + method, wolfSSLv23_server_method), 0); + if (ssl_c != NULL) + mask = wolfSSL_get_options(ssl_c); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, TLS1_1_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl_c), mask); + if (ver == TLS1_2_VERSION) { + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl_c, TLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl_c), mask); + } + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_c, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl_c), ver); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_version(ssl_s), ver); +#ifdef WOLFSSL_TLS13 + if (ver == TLS1_2_VERSION) { + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx_c, WOLFSSL_TLSV1_3), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx_c), 0); + } +#endif + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif + +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \ + !defined(NO_WOLFSSL_CLIENT) +/* require_psk and SetVersion pin a v23 object, so a lower maximum fails. */ +static int test_tls_max_proto_pinned(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx = NULL; + WOLFSSL *ssl = NULL; + long mask = 0; +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_require_psk(ctx), 0); + if (ctx != NULL) + mask = wolfSSL_CTX_get_options(ctx); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_get_options(ctx), mask); + ExpectIntEQ(ctx != NULL ? ctx->method->version.minor : 0, TLSv1_3_MINOR); + ExpectIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), TLS1_3_VERSION); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_require_psk(ssl), 0); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, TLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_version(ssl), TLS1_3_VERSION); + wolfSSL_free(ssl); + ssl = NULL; +#else + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); +#endif + + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_SetVersion(ssl, WOLFSSL_TLSV1_3), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, TLS1_2_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_version(ssl), TLS1_3_VERSION); + wolfSSL_free(ssl); + ssl = NULL; +#ifndef WOLFSSL_NO_TLS12 + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_SetVersion(ssl, WOLFSSL_TLSV1_2), WOLFSSL_SUCCESS); + if (ssl != NULL) + mask = wolfSSL_get_options(ssl); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl, TLS1_3_VERSION), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_options(ssl), mask); + ExpectIntEQ(wolfSSL_version(ssl), TLS1_2_VERSION); + wolfSSL_free(ssl); +#endif + wolfSSL_CTX_free(ctx); + (void)mask; + return EXPECT_RESULT(); +} +#endif + +int test_tls_max_proto_fixed(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(OPENSSL_EXTRA) +#ifdef WOLFSSL_TLS13 + ExpectIntEQ(test_tls_max_proto_fixed_case(wolfTLSv1_3_client_method, + TLS1_3_VERSION), TEST_SUCCESS); +#endif +#ifndef WOLFSSL_NO_TLS12 + ExpectIntEQ(test_tls_max_proto_fixed_case(wolfTLSv1_2_client_method, + TLS1_2_VERSION), TEST_SUCCESS); +#endif +#endif +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \ + !defined(NO_WOLFSSL_CLIENT) + ExpectIntEQ(test_tls_max_proto_pinned(), TEST_SUCCESS); +#endif + return EXPECT_RESULT(); +} + /* RFC 5246 Section 7.2.2 and RFC 8446 Section 4.1.3: a server that cannot * negotiate any version at or below ClientHello.client_version MUST abort with * a fatal protocol_version alert. diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index 1dc1563da69..56abaf03087 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -56,6 +56,7 @@ int test_dtls_fallback_scsv(void); int test_dtls_fallback_scsv_no_downgrade(void); int test_tls_fallback_scsv_no_downgrade(void); int test_tls_fallback_scsv_no_downgrade_runtime_max(void); +int test_tls_max_proto_fixed(void); int test_tls_no_acceptable_version_alert(void); int test_tls_lesser_version_alerts(void); int test_tls_version_mask_alert_record(void); @@ -170,6 +171,7 @@ int test_tls_unset_fd_no_stdin_io(void); TEST_DECL_GROUP("tls", test_dtls_fallback_scsv_no_downgrade), \ TEST_DECL_GROUP("tls", test_tls_fallback_scsv_no_downgrade), \ TEST_DECL_GROUP("tls", test_tls_fallback_scsv_no_downgrade_runtime_max),\ + TEST_DECL_GROUP("tls", test_tls_max_proto_fixed), \ TEST_DECL_GROUP("tls", test_tls_no_acceptable_version_alert), \ TEST_DECL_GROUP("tls", test_tls_lesser_version_alerts), \ TEST_DECL_GROUP("tls", test_tls_version_mask_alert_record), \ diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 5a78ed63d7e..539104e1db6 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -8454,6 +8454,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 9bb51900267..f3ec056d943 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -58,6 +58,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); @@ -250,6 +251,7 @@ int test_tls13_exporter_suite_decision_coverage(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 5a02b320f1d..b83f2715fed 100644 --- a/tests/api/test_tls_ext.c +++ b/tests/api/test_tls_ext.c @@ -3610,6 +3610,569 @@ 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) +{ + SupportedCurves* curves = NULL; + int i; + int j; + + *tls13Cnt = 0; + *tls12Cnt = 0; + if (ext != NULL) + curves = (SupportedCurves*)ext->data; + for (j = 0; curves != NULL && j < curves->count; j++) { + for (i = 0; i < TEST_BP_CNT; i++) { + if (curves->name[j] == test_bp_tls13[i]) + (*tls13Cnt)++; + else if (curves->name[j] == 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 7e943bdf2c2..b34f7368269 100644 --- a/tests/api/test_tls_ext.h +++ b/tests/api/test_tls_ext.h @@ -69,6 +69,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); @@ -112,6 +113,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 c96be637e07..4ddb22ce4e8 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2376,6 +2376,13 @@ 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 void InitSuites_EitherSide(Suites* suites, ProtocolVersion pv, + int keySz, word16 haveRSA, word16 havePSK, word16 haveDH, + word16 haveECDSAsig, word16 haveECC, word16 haveStaticECC, + word16 haveAnon, int side); +WOLFSSL_LOCAL int ResetSuitesForVersion(WOLFSSL* ssl); +WOLFSSL_LOCAL int FilterSuitesForVersion(WOLFSSL* ssl); +WOLFSSL_LOCAL ProtocolVersion SslNewestVersion(const WOLFSSL* ssl); WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side); @@ -5862,6 +5869,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 */ @@ -7021,6 +7031,7 @@ struct WOLFSSL { * object needs separate instance of suites use * AllocateSuites(). */ Suites* clSuites; + Suites* suitesUser; /* unfiltered copy of user-set suites */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \ defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) WOLF_STACK_OF(WOLFSSL_CIPHER)* suitesStack; /* stack of available cipher @@ -8470,6 +8481,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 ad14fcf5ab4..77fe472f429 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3074,6 +3074,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