From d5fcfbd4f2ce6ce0eb3d3baf364fa6dca0ee3c95 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 30 Oct 2026 09:47:08 +0000 Subject: [PATCH] Leave objects unchanged when version, group and sigalgs setters fail Protocol version setters: - wolfSSL_CTX_set_min_proto_version(), wolfSSL_CTX_set_max_proto_version(), wolfSSL_set_min_proto_version() and wolfSSL_set_max_proto_version() work on a copy of the version limits and store it only on success. A failing call could leave every version disabled, or enable again versions that the application had disabled with options. - The CTX setters record the NO_* options each of them sets and drop only those, so options set by the application are kept and a later call can lower the min or raise the max. The max setter no longer re-applies the min. wolfSSL_CTX_set_options(), wolfSSL_CTX_clear_options() and wolfSSL_CTX_SetMinVersion() update the records. - A call fails when it leaves no version from the min up, counting a min held only in minDowngrade: the default one, one set with wolfSSL_CTX_SetMinVersion() or wolfSSL_SetMinVersion(), or the crypto policy's. In old TLS builds without TLS 1.0, a TLS 1.0 min is TLS 1.1. - A DTLS min on a TLS CTX fails, and so does an SSL max of the other major. - The CTX max setter rebuilds ctx->suites when it changes the method version. - wolfSSL_CTX_SetMinVersion() clears the automatic min flag. - WOLFSSL_MIN_DOWNGRADE is TLS 1.1 in old TLS builds without WOLFSSL_ALLOW_TLSV10. - With WOLFSSL_SYS_CRYPTO_POLICY at level 0, including when no policy is loaded, a new TLS CTX keeps the default min instead of an SSLv3 min. Cipher suites: - The CTX PSK callback setters and wolfSSL_CTX_allow_anon_cipher() rebuild ctx->suites when it was already derived. The max setter no longer leaves the min's options in ctx->mask, so SSLs created after a late PSK callback shared stale CTX suites without PSK. A cipher list set by the application is kept. Groups: - wolfSSL_CTX_set_groups() and wolfSSL_set_groups() build the Supported Groups extension in a local list and replace the old one only on success. They move from tls.c to ssl_api_ext.c. - set_curves_list() sets the groups once, after parsing. - wolfSSL_UseSupportedCurve() and wolfSSL_CTX_UseSupportedCurve() set userCurves only when the group was added. Signature algorithms: - SetSuitesHashSigAlgo() parses into a local buffer and copies it only when the whole list parses. - wolfSSL_CTX_set1_sigalgs_list() on a CTX without suites frees the suites it allocated when the list is rejected, and adds the default cipher suites when it is accepted. --- src/internal.c | 14 +- src/ssl.c | 636 +++++++++++++--------------- src/ssl_api_ext.c | 153 ++++++- src/tls.c | 96 ----- src/tls13.c | 12 + tests/api.c | 1004 +++++++++++++++++++++++++++++++++++++++++++- wolfssl/internal.h | 8 +- 7 files changed, 1467 insertions(+), 456 deletions(-) diff --git a/src/internal.c b/src/internal.c index e4585216985..18f6111416a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3029,7 +3029,7 @@ int wolfSSL_crypto_policy_init_ctx(WOLFSSL_CTX * ctx, break; case 0: default: - ctx->minDowngrade = WOLFSSL_MIN_DOWNGRADE; + minDowngrade = WOLFSSL_MIN_DOWNGRADE; break; } } @@ -3171,7 +3171,6 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap) else #endif /* WOLFSSL_DTLS */ { - /* current default: TLSv1_MINOR */ ctx->minDowngrade = WOLFSSL_MIN_DOWNGRADE; } @@ -33891,7 +33890,7 @@ static byte GetSigAlgFromName(const char* name, int len) * * suites [in,out] Cipher suites and signature algorithms. * list [in] String representing hash/signature algorithms to set. - * returns 0 on failure. + * returns 0 on failure, leaving suites unchanged. * 1 on success. */ int SetSuitesHashSigAlgo(Suites* suites, const char* list) @@ -33901,9 +33900,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 == '+') { @@ -33943,7 +33940,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; @@ -33956,7 +33953,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; } diff --git a/src/ssl.c b/src/ssl.c index d4dfe1afee7..57fce6bf428 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2241,8 +2241,15 @@ int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ ret = SetMinVersionHelper(&ctx->minDowngrade, version); - if (ret == WOLFSSL_SUCCESS) + if (ret == WOLFSSL_SUCCESS) { ctx->minVersionSet = 1; + ctx->minProto = 0; /* no longer the automatic minimum */ + #ifdef OPENSSL_EXTRA + /* replaces a min set with wolfSSL_CTX_set_min_proto_version() */ + ctx->mask &= ~ctx->minProtoMask; + ctx->minProtoMask = 0; + #endif + } return ret; } @@ -4067,6 +4074,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) ctx->havePSK = 1; ctx->client_psk_cb = cb; + if (ctx->suites != NULL) { + /* add PSK to the suites derived before */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } } void wolfSSL_set_psk_client_callback(WOLFSSL* ssl,wc_psk_client_callback cb) @@ -4145,6 +4156,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return; ctx->havePSK = 1; ctx->server_psk_cb = cb; + if (ctx->suites != NULL) { + /* add PSK to the suites derived before */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } } void wolfSSL_set_psk_server_callback(WOLFSSL* ssl,wc_psk_server_callback cb) @@ -4262,6 +4277,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return WOLFSSL_FAILURE; ctx->useAnon = 1; + if (ctx->suites != NULL) { + /* add anon to the suites derived before */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } return WOLFSSL_SUCCESS; } @@ -4693,6 +4712,11 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return BAD_FUNC_ARG; ctx->mask = (unsigned long)wolf_set_options((long)ctx->mask, opt); +#ifdef OPENSSL_EXTRA + /* Versions disabled here belong to the application */ + ctx->minProtoMask &= ~(unsigned long)opt; + ctx->maxProtoMask &= ~(unsigned long)opt; +#endif #if defined(HAVE_SESSION_TICKET) && (defined(OPENSSL_EXTRA) \ || defined(HAVE_WEBSERVER) || defined(WOLFSSL_WPAS_SMALL)) if ((ctx->mask & WOLFSSL_OP_NO_TICKET) == WOLFSSL_OP_NO_TICKET) { @@ -4717,6 +4741,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) if(ctx == NULL) return BAD_FUNC_ARG; ctx->mask &= (unsigned long)~opt; +#ifdef OPENSSL_EXTRA + ctx->minProtoMask &= (unsigned long)~opt; + ctx->maxProtoMask &= (unsigned long)~opt; +#endif return (long)ctx->mask; } @@ -5067,72 +5095,155 @@ static const int protoVerTbl[] = { /* number of protocol versions listed in protoVerTbl */ #define NUMBER_OF_PROTOCOLS (sizeof(protoVerTbl)/sizeof(int)) -/** - * wolfSSL_CTX_set_min_proto_version attempts to set the minimum protocol - * version to use by SSL objects created from this WOLFSSL_CTX. - * This API guarantees that a version of SSL/TLS lower than specified - * here will not be allowed. If the version specified is not compiled in - * then this API sets the lowest compiled in protocol version. - * This API also accept 0 as version, to set the minimum version automatically. - * CheckSslMethodVersion() is called to check if any remaining protocol versions - * are enabled. - * @param ctx The wolfSSL CONTEXT factory for spawning SSL/TLS objects - * @param version Any of the following - * * 0 - * * SSL3_VERSION - * * TLS1_VERSION - * * TLS1_1_VERSION - * * TLS1_2_VERSION - * * TLS1_3_VERSION - * * DTLS1_VERSION - * * DTLS1_2_VERSION - * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no - * protocol versions are left enabled. - */ -static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) +static int GetMaxProtoVersion(long options); + +/* WOLFSSL_OP_NO_* option of each TLS version, indexed by minor version */ +static const unsigned long tlsVersionOptions[] = { + WOLFSSL_OP_NO_SSLv3, + WOLFSSL_OP_NO_TLSv1, + WOLFSSL_OP_NO_TLSv1_1, + WOLFSSL_OP_NO_TLSv1_2, + WOLFSSL_OP_NO_TLSv1_3 +}; + +/* NO_* options of the TLS versions below minor */ +static unsigned long tlsOptionsBelow(byte minor) { - WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version_ex"); + unsigned long op = 0; + int i; - if (ctx == NULL) { - return WOLFSSL_FAILURE; + for (i = 0; i < minor && i < (int)XELEM_CNT(tlsVersionOptions); i++) { + op |= tlsVersionOptions[i]; } + return op; +} + +/* NO_* options of the TLS versions above minor */ +static unsigned long tlsOptionsAbove(byte minor) +{ + unsigned long op = 0; + int i; + + for (i = minor + 1; i < (int)XELEM_CNT(tlsVersionOptions); i++) { + op |= tlsVersionOptions[i]; + } + return op; +} + +/* The version limits of a CTX or an SSL. The version setters change a copy + * and store it only on success, so a failing call leaves the object + * unchanged. */ +typedef struct ProtoLimits { + unsigned long mask; /* NO_* options */ + unsigned long minProtoMask; /* NO_* options set by the min setter */ + unsigned long maxProtoMask; /* NO_* options set by the max setter */ + byte major; + byte maxMinor; + byte minDowngrade; +} ProtoLimits; + +static void getCtxProtoLimits(const WOLFSSL_CTX* ctx, ProtoLimits* lim) +{ + lim->mask = ctx->mask; + lim->minProtoMask = ctx->minProtoMask; + lim->maxProtoMask = ctx->maxProtoMask; + lim->major = ctx->method->version.major; + lim->maxMinor = ctx->method->version.minor; + lim->minDowngrade = ctx->minDowngrade; +} + +static void setCtxProtoLimits(WOLFSSL_CTX* ctx, const ProtoLimits* lim) +{ + ctx->mask = lim->mask; + ctx->minProtoMask = lim->minProtoMask; + ctx->maxProtoMask = lim->maxProtoMask; + /* the method version is the max */ + ctx->method->version.minor = lim->maxMinor; + ctx->minDowngrade = lim->minDowngrade; +} + +/* An SSL does not record the options its setters set, so they only add + * options. */ +static void getSslProtoLimits(const WOLFSSL* ssl, ProtoLimits* lim) +{ + lim->mask = ssl->options.mask; + lim->minProtoMask = 0; + lim->maxProtoMask = 0; + lim->major = ssl->version.major; + lim->maxMinor = ssl->version.minor; + lim->minDowngrade = ssl->options.minDowngrade; +} + +/* An SSL max is held in the mask only, so the SSL version is kept. */ +static void setSslProtoLimits(WOLFSSL* ssl, const ProtoLimits* lim) +{ + ssl->options.mask = lim->mask; + ssl->options.minDowngrade = lim->minDowngrade; +} + +/* Disables versions for a min or max limit. Only options not already set are + * recorded as the limit's own, so options set by the application are kept. */ +static void disableProto(ProtoLimits* lim, unsigned long* own, + unsigned long op) +{ + *own |= op & ~lim->mask; + lim->mask |= op; +} + +/* Checks that a version is left from the min up. A min held only in + * minDowngrade, such as the default one, has no options in the mask. */ +static int checkProtoLimits(const ProtoLimits* lim) +{ + unsigned long op = lim->mask; + + if (lim->major == SSLv3_MAJOR) + op |= tlsOptionsBelow(lim->minDowngrade); + return CheckSslMethodVersion(lim->major, op); +} + +/* Applies a min version to the limits: sets minDowngrade and disables the TLS + * versions below it. Fails for an unknown version or when no version is left. + */ +static int setMinProtoVersion(ProtoLimits* lim, int version) +{ + WOLFSSL_ENTER("setMinProtoVersion"); switch (version) { #ifndef NO_TLS case SSL3_VERSION: #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) - ctx->minDowngrade = SSLv3_MINOR; + lim->minDowngrade = SSLv3_MINOR; break; #endif case TLS1_VERSION: #ifdef WOLFSSL_ALLOW_TLSV10 - ctx->minDowngrade = TLSv1_MINOR; + lim->minDowngrade = TLSv1_MINOR; break; #endif case TLS1_1_VERSION: #ifndef NO_OLD_TLS - ctx->minDowngrade = TLSv1_1_MINOR; + lim->minDowngrade = TLSv1_1_MINOR; break; #endif case TLS1_2_VERSION: #ifndef WOLFSSL_NO_TLS12 - ctx->minDowngrade = TLSv1_2_MINOR; + lim->minDowngrade = TLSv1_2_MINOR; break; #endif case TLS1_3_VERSION: #ifdef WOLFSSL_TLS13 - ctx->minDowngrade = TLSv1_3_MINOR; + lim->minDowngrade = TLSv1_3_MINOR; break; #endif #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: #ifndef NO_OLD_TLS - ctx->minDowngrade = DTLS_MINOR; + lim->minDowngrade = DTLS_MINOR; break; #endif case DTLS1_2_VERSION: - ctx->minDowngrade = DTLSv1_2_MINOR; + lim->minDowngrade = DTLSv1_2_MINOR; break; #endif default: @@ -5140,40 +5251,35 @@ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) return WOLFSSL_FAILURE; } - switch (version) { -#ifndef NO_TLS - case TLS1_3_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); - FALL_THROUGH; - case TLS1_2_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1); - FALL_THROUGH; - case TLS1_1_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1); - FALL_THROUGH; - case TLS1_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_SSLv3); - break; - case SSL3_VERSION: - case SSL2_VERSION: - /* Nothing to do here */ - break; -#endif -#ifdef WOLFSSL_DTLS - case DTLS1_VERSION: - case DTLS1_2_VERSION: - break; -#endif - default: - WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); - return WOLFSSL_FAILURE; + if ((version >> 8) == SSLv3_MAJOR) { + disableProto(lim, &lim->minProtoMask, tlsOptionsBelow((byte)version)); } - return CheckSslMethodVersion(ctx->method->version.major, ctx->mask); + return checkProtoLimits(lim); } -/* Sets the min protocol version allowed with WOLFSSL_CTX - * returns WOLFSSL_SUCCESS on success */ +/** + * wolfSSL_CTX_set_min_proto_version attempts to set the minimum protocol + * version to use by SSL objects created from this WOLFSSL_CTX. + * This API guarantees that a version of SSL/TLS lower than specified + * here will not be allowed. If the version specified is not compiled in + * then this API sets the lowest compiled in protocol version. + * This API also accept 0 as version, to set the minimum version automatically. + * CheckSslMethodVersion() is called to check if any remaining protocol versions + * are enabled. + * @param ctx The wolfSSL CONTEXT factory for spawning SSL/TLS objects + * @param version Any of the following + * * 0 + * * SSL3_VERSION + * * TLS1_VERSION + * * TLS1_1_VERSION + * * TLS1_2_VERSION + * * TLS1_3_VERSION + * * DTLS1_VERSION + * * DTLS1_2_VERSION + * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no + * protocol versions are left enabled. On failure ctx is unchanged. + */ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) { int ret; @@ -5181,16 +5287,28 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) int maxProto = 0; int i; int idx = 0; + ProtoLimits lim; 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 + + getCtxProtoLimits(ctx, &lim); + /* drop the versions disabled for the previous min */ + lim.mask &= ~lim.minProtoMask; + lim.minProtoMask = 0; if (version != 0) { proto = version; - ctx->minProto = 0; /* turn min proto flag off */ for (i = 0; (unsigned)i < NUMBER_OF_PROTOCOLS; i++) { if (protoVerTbl[i] == version) { break; @@ -5200,32 +5318,31 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) else { /* when 0 is specified as version, try to find out the min version */ for (i = 0; (unsigned)i < NUMBER_OF_PROTOCOLS; i++) { - ret = Set_CTX_min_proto_version(ctx, protoVerTbl[i]); + ret = setMinProtoVersion(&lim, protoVerTbl[i]); if (ret == WOLFSSL_SUCCESS) { proto = protoVerTbl[i]; - ctx->minProto = 1; /* turn min proto flag on */ break; } } } - /* check case where max > min , if so then clear the NO_* options - * i is the index into the table for proto version used, see if the max - * proto version index found is smaller */ - maxProto = wolfSSL_CTX_get_max_proto_version(ctx); + /* A min above the max drops the NO_* options set for the max. i is the + * table index of the min and idx the one of the max. */ + maxProto = ctx->maxProto ? 0 : GetMaxProtoVersion((long)lim.mask); for (idx = 0; (unsigned)idx < NUMBER_OF_PROTOCOLS; idx++) { if (protoVerTbl[idx] == maxProto) { break; } } if (idx < i) { - wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_TLSv1 | - WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | - WOLFSSL_OP_NO_TLSv1_3); + lim.mask &= ~lim.maxProtoMask; + lim.maxProtoMask = 0; } - ret = Set_CTX_min_proto_version(ctx, proto); + ret = setMinProtoVersion(&lim, proto); if (ret == WOLFSSL_SUCCESS) { + setCtxProtoLimits(ctx, &lim); + ctx->minProto = (version == 0); /* Version 0 picks the lowest, so the user set no minimum */ ctx->minVersionSet = (version != 0); } @@ -5233,37 +5350,13 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) return ret; } -/** - * wolfSSL_CTX_set_max_proto_version attempts to set the maximum protocol - * version to use by SSL objects created from this WOLFSSL_CTX. - * This API guarantees that a version of SSL/TLS higher than specified - * here will not be allowed. If the version specified is not compiled in - * then this API sets the highest compiled in protocol version. - * This API also accept 0 as version, to set the maximum version automatically. - * CheckSslMethodVersion() is called to check if any remaining protocol versions - * are enabled. - * @param ctx The wolfSSL CONTEXT factory for spawning SSL/TLS objects - * @param ver Any of the following - * * 0 - * * SSL3_VERSION - * * TLS1_VERSION - * * TLS1_1_VERSION - * * TLS1_2_VERSION - * * TLS1_3_VERSION - * * DTLS1_VERSION - * * DTLS1_2_VERSION - * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no - * protocol versions are left enabled. - */ -static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) +/* Applies a max version to the limits: disables the TLS versions above it and + * sets maxMinor. Fails for an unknown version, a version of the other major or + * when no version is left. */ +static int setMaxProtoVersion(ProtoLimits* lim, int ver) { int ret; - WOLFSSL_ENTER("Set_CTX_max_proto_version"); - - if (!ctx || !ctx->method) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } + WOLFSSL_ENTER("setMaxProtoVersion"); switch (ver) { #ifndef NO_TLS @@ -5273,19 +5366,10 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) return WOLFSSL_FAILURE; #endif case SSL3_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1); - FALL_THROUGH; case TLS1_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1); - FALL_THROUGH; case TLS1_1_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); - FALL_THROUGH; case TLS1_2_VERSION: - wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); - FALL_THROUGH; case TLS1_3_VERSION: - /* Nothing to do here */ break; #endif #ifdef WOLFSSL_DTLS @@ -5298,76 +5382,49 @@ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) return WOLFSSL_FAILURE; } - ret = CheckSslMethodVersion(ctx->method->version.major, ctx->mask); + if ((ver >> 8) == SSLv3_MAJOR) { + disableProto(lim, &lim->maxProtoMask, tlsOptionsAbove((byte)ver)); + } + + ret = checkProtoLimits(lim); if (ret == WOLFSSL_SUCCESS) { - /* Check the major */ - switch (ver) { - #ifndef NO_TLS - case SSL3_VERSION: - case TLS1_VERSION: - case TLS1_1_VERSION: - case TLS1_2_VERSION: - case TLS1_3_VERSION: - if (ctx->method->version.major != SSLv3_MAJOR) { - WOLFSSL_MSG("Mismatched protocol version"); - return WOLFSSL_FAILURE; - } - break; - #endif - #ifdef WOLFSSL_DTLS - case DTLS1_VERSION: - case DTLS1_2_VERSION: - if (ctx->method->version.major != DTLS_MAJOR) { - WOLFSSL_MSG("Mismatched protocol version"); - return WOLFSSL_FAILURE; - } - break; - #endif - } - /* Update the method */ - switch (ver) { - #ifndef NO_TLS - case SSL3_VERSION: - ctx->method->version.minor = SSLv3_MINOR; - break; - case TLS1_VERSION: - ctx->method->version.minor = TLSv1_MINOR; - break; - case TLS1_1_VERSION: - ctx->method->version.minor = TLSv1_1_MINOR; - break; - case TLS1_2_VERSION: - ctx->method->version.minor = TLSv1_2_MINOR; - break; - case TLS1_3_VERSION: - ctx->method->version.minor = TLSv1_3_MINOR; - break; - #endif - #ifdef WOLFSSL_DTLS - case DTLS1_VERSION: - ctx->method->version.minor = DTLS_MINOR; - break; - case DTLS1_2_VERSION: - ctx->method->version.minor = DTLSv1_2_MINOR; - break; - #endif - default: - WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); + if ((ver >> 8) != lim->major) { + WOLFSSL_MSG("Mismatched protocol version"); return WOLFSSL_FAILURE; } + lim->maxMinor = (byte)ver; } return ret; } -/* Sets the max protocol version allowed with WOLFSSL_CTX - * returns WOLFSSL_SUCCESS on success */ +/** + * wolfSSL_CTX_set_max_proto_version attempts to set the maximum protocol + * version to use by SSL objects created from this WOLFSSL_CTX. + * This API guarantees that a version of SSL/TLS higher than specified + * here will not be allowed. If the version specified is not compiled in + * then this API sets the highest compiled in protocol version. + * This API also accept 0 as version, to set the maximum version automatically. + * CheckSslMethodVersion() is called to check if any remaining protocol versions + * are enabled. + * @param ctx The wolfSSL CONTEXT factory for spawning SSL/TLS objects + * @param version Any of the following + * * 0 + * * SSL3_VERSION + * * TLS1_VERSION + * * TLS1_1_VERSION + * * TLS1_2_VERSION + * * TLS1_3_VERSION + * * DTLS1_VERSION + * * DTLS1_2_VERSION + * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no + * protocol versions are left enabled. On failure ctx is unchanged. + */ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) { int i; int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - int minProto; - byte minVersionSet; + ProtoLimits lim; WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version"); @@ -5375,140 +5432,66 @@ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) return ret; } - /* clear out flags and reset min protocol version */ - minProto = wolfSSL_CTX_get_min_proto_version(ctx); - wolfSSL_CTX_clear_options(ctx, - WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | - WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); - minVersionSet = ctx->minVersionSet; - wolfSSL_CTX_set_min_proto_version(ctx, minProto); - ctx->minVersionSet = minVersionSet; /* restoring, not setting, a minimum */ + getCtxProtoLimits(ctx, &lim); + /* drop the versions disabled for the previous max */ + lim.mask &= ~lim.maxProtoMask; + lim.maxProtoMask = 0; if (version != 0) { - ctx->maxProto = 0; /* turn max proto flag off */ - return Set_CTX_max_proto_version(ctx, version); + ret = setMaxProtoVersion(&lim, version); } - - /* when 0 is specified as version, try to find out the min version from - * the bottom to top of the protoverTbl. - */ - for (i = NUMBER_OF_PROTOCOLS -1; i >= 0; i--) { - ret = Set_CTX_max_proto_version(ctx, protoVerTbl[i]); - if (ret == WOLFSSL_SUCCESS) { - ctx->maxProto = 1; /* turn max proto flag on */ - break; + else { + /* when 0 is specified as version, try to find out the max version + * from the bottom to top of the protoverTbl. + */ + for (i = NUMBER_OF_PROTOCOLS -1; i >= 0; i--) { + ret = setMaxProtoVersion(&lim, protoVerTbl[i]); + if (ret == WOLFSSL_SUCCESS) { + break; + } } } - return ret; -} - - -static int Set_SSL_min_proto_version(WOLFSSL* ssl, int ver) -{ - WOLFSSL_ENTER("Set_SSL_min_proto_version"); - - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - switch (ver) { -#ifndef NO_TLS - case SSL3_VERSION: -#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) - ssl->options.minDowngrade = SSLv3_MINOR; - break; -#endif - case TLS1_VERSION: - #ifdef WOLFSSL_ALLOW_TLSV10 - ssl->options.minDowngrade = TLSv1_MINOR; - break; - #endif - case TLS1_1_VERSION: - #ifndef NO_OLD_TLS - ssl->options.minDowngrade = TLSv1_1_MINOR; - break; - #endif - case TLS1_2_VERSION: - #ifndef WOLFSSL_NO_TLS12 - ssl->options.minDowngrade = TLSv1_2_MINOR; - break; - #endif - case TLS1_3_VERSION: - #ifdef WOLFSSL_TLS13 - ssl->options.minDowngrade = TLSv1_3_MINOR; - break; - #endif -#endif -#ifdef WOLFSSL_DTLS - case DTLS1_VERSION: - #ifndef NO_OLD_TLS - ssl->options.minDowngrade = DTLS_MINOR; - break; - #endif - case DTLS1_2_VERSION: - ssl->options.minDowngrade = DTLSv1_2_MINOR; - break; -#endif - default: - WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); - return WOLFSSL_FAILURE; - } + if (ret == WOLFSSL_SUCCESS) { + byte minor = ctx->method->version.minor; - switch (ver) { -#ifndef NO_TLS - case TLS1_3_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_2; - FALL_THROUGH; - case TLS1_2_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_1; - FALL_THROUGH; - case TLS1_1_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1; - FALL_THROUGH; - case TLS1_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_SSLv3; - break; - case SSL3_VERSION: - case SSL2_VERSION: - /* Nothing to do here */ - break; -#endif -#ifdef WOLFSSL_DTLS - case DTLS1_VERSION: - case DTLS1_2_VERSION: - break; -#endif - default: - WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); - return WOLFSSL_FAILURE; + setCtxProtoLimits(ctx, &lim); + ctx->maxProto = (version == 0); + if (ctx->suites != NULL && lim.maxMinor != minor) { + /* rebuild the suites derived for the previous max */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } } - return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); + return ret; } int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int version) { int i; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + ProtoLimits lim; WOLFSSL_ENTER("wolfSSL_set_min_proto_version"); if (ssl == NULL) { return WOLFSSL_FAILURE; } + + getSslProtoLimits(ssl, &lim); if (version != 0) { - ret = Set_SSL_min_proto_version(ssl, version); + ret = setMinProtoVersion(&lim, version); } else { /* when 0 is specified as version, try to find out the min version */ for (i= 0; (unsigned)i < NUMBER_OF_PROTOCOLS; i++) { - ret = Set_SSL_min_proto_version(ssl, protoVerTbl[i]); + ret = setMinProtoVersion(&lim, protoVerTbl[i]); if (ret == WOLFSSL_SUCCESS) break; } } if (ret == WOLFSSL_SUCCESS) { + setSslProtoLimits(ssl, &lim); /* Version 0 picks the lowest, so the user set no minimum */ ssl->options.minVersionSet = (version != 0); RestoreDowngrade(ssl); @@ -5517,71 +5500,35 @@ int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int version) return ret; } -static int Set_SSL_max_proto_version(WOLFSSL* ssl, int ver) -{ - - WOLFSSL_ENTER("Set_SSL_max_proto_version"); - - if (!ssl) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - switch (ver) { - case SSL2_VERSION: - WOLFSSL_MSG("wolfSSL does not support SSLv2"); - return WOLFSSL_FAILURE; -#ifndef NO_TLS - case SSL3_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1; - FALL_THROUGH; - case TLS1_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_1; - FALL_THROUGH; - case TLS1_1_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_2; - FALL_THROUGH; - case TLS1_2_VERSION: - ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_3; - FALL_THROUGH; - case TLS1_3_VERSION: - /* Nothing to do here */ - break; -#endif -#ifdef WOLFSSL_DTLS - case DTLS1_VERSION: - case DTLS1_2_VERSION: - break; -#endif - default: - WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); - return WOLFSSL_FAILURE; - } - - return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); -} - int wolfSSL_set_max_proto_version(WOLFSSL* ssl, int version) { int i; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + ProtoLimits lim; WOLFSSL_ENTER("wolfSSL_set_max_proto_version"); if (ssl == NULL) { return WOLFSSL_FAILURE; } + + getSslProtoLimits(ssl, &lim); if (version != 0) { - return Set_SSL_max_proto_version(ssl, version); + ret = setMaxProtoVersion(&lim, version); + } + else { + /* when 0 is specified as version, try to find out the max version + * from the bottom to top of the protoverTbl. + */ + for (i = NUMBER_OF_PROTOCOLS -1; i >= 0; i--) { + ret = setMaxProtoVersion(&lim, protoVerTbl[i]); + if (ret == WOLFSSL_SUCCESS) + break; + } } - /* when 0 is specified as version, try to find out the min version from - * the bottom to top of the protoverTbl. - */ - for (i = NUMBER_OF_PROTOCOLS -1; i >= 0; i--) { - ret = Set_SSL_max_proto_version(ssl, protoVerTbl[i]); - if (ret == WOLFSSL_SUCCESS) - break; + if (ret == WOLFSSL_SUCCESS) { + setSslProtoLimits(ssl, &lim); } return ret; @@ -10021,20 +9968,8 @@ int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names, else { disabled &= ~(1U << curve); } - #if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_TLS) - #if !defined(WOLFSSL_OLD_SET_CURVES_LIST) - /* using the wolfSSL API to set the groups, this will populate - * (ssl|ctx)->groups and reset any TLSX_SUPPORTED_GROUPS. - * The order in (ssl|ctx)->groups will then be respected - * when TLSX_KEY_SHARE needs to be established */ - if ((ssl && wolfSSL_set_groups(ssl, groups, groups_len) - != WOLFSSL_SUCCESS) - || (ctx && wolfSSL_CTX_set_groups(ctx, groups, groups_len) - != WOLFSSL_SUCCESS)) { - WOLFSSL_MSG("Unable to set supported curve"); - goto leave; - } - #elif !defined(NO_WOLFSSL_CLIENT) + #if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_TLS) && \ + defined(WOLFSSL_OLD_SET_CURVES_LIST) && !defined(NO_WOLFSSL_CLIENT) /* set the supported curve so client TLS extension contains only the * desired curves */ if ((ssl && wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS) @@ -10044,9 +9979,24 @@ int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names, goto leave; } #endif - #endif /* HAVE_SUPPORTED_CURVES && !NO_TLS */ } +#if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_TLS) && \ + !defined(WOLFSSL_OLD_SET_CURVES_LIST) + /* using the wolfSSL API to set the groups, this will populate + * (ssl|ctx)->groups and reset any TLSX_SUPPORTED_GROUPS. + * The order in (ssl|ctx)->groups will then be respected + * when TLSX_KEY_SHARE needs to be established */ + if (groups_len > 0 && + ((ssl && wolfSSL_set_groups(ssl, groups, groups_len) + != WOLFSSL_SUCCESS) || + (ctx && wolfSSL_CTX_set_groups(ctx, groups, groups_len) + != WOLFSSL_SUCCESS))) { + WOLFSSL_MSG("Unable to set supported curve"); + goto leave; + } +#endif + if (ssl != NULL) ssl->disabledCurves = disabled; else if (ctx != NULL) diff --git a/src/ssl_api_ext.c b/src/ssl_api_ext.c index 646623c43e9..22ad2f9963c 100644 --- a/src/ssl_api_ext.c +++ b/src/ssl_api_ext.c @@ -600,13 +600,15 @@ int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) ret = BAD_FUNC_ARG; } else { - ssl->options.userCurves = 1; #if defined(NO_TLS) ret = WOLFSSL_FAILURE; #else ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap, ssl->options.side); #endif /* NO_TLS */ + if (ret == WOLFSSL_SUCCESS) { + ssl->options.userCurves = 1; + } } return ret; @@ -629,13 +631,138 @@ int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) ret = BAD_FUNC_ARG; } else { - ctx->userCurves = 1; #if defined(NO_TLS) ret = WOLFSSL_FAILURE; #else ret = TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap, ctx->method->side); #endif /* NO_TLS */ + if (ret == WOLFSSL_SUCCESS) { + ctx->userCurves = 1; + } + } + + return ret; +} + +/* Replace the Supported Groups extension in a list of extensions. + * + * The new extension is built in a list of its own, so a failure leaves the + * list unchanged. + * + * @param [in, out] extensions List of extensions. + * @param [in] groups Named groups in rank order. + * @param [in] count Number of groups. Must be positive. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] side Side the groups are used on. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when a group is invalid or not supported. + * @return MEMORY_E on dynamic memory allocation failure. + */ +static int wolfssl_set_groups_ext(TLSX** extensions, const int* groups, + int count, void* heap, int side) +{ + TLSX* ext = NULL; + int ret = WOLFSSL_SUCCESS; + int i; + + for (i = 0; (i < count) && (ret == WOLFSSL_SUCCESS); i++) { + if (!isValidCurveGroup((word16)groups[i])) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSupportedCurve(&ext, (word16)groups[i], heap, side); + } + } + if (ret == WOLFSSL_SUCCESS) { + TLSX_Remove(extensions, TLSX_SUPPORTED_GROUPS, heap); + ext->next = *extensions; + *extensions = ext; + } + else { + TLSX_FreeAll(ext, heap); + } + + return ret; +} + +/* Set the key exchange groups, in rank order, on the context. A failing + * call leaves the context unchanged. + * + * @param [in, out] ctx SSL/TLS context object. + * @param [in] groups Array of named groups. + * @param [in] count Number of groups in the array. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx or groups is NULL, the method is not TLS, + * count is not positive or greater than WOLFSSL_MAX_GROUP_COUNT, or + * a group is invalid or not supported. + * @return MEMORY_E on dynamic memory allocation failure. + */ +int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) +{ + int ret; +#ifdef WOLFSSL_TLS13 + int i; +#endif + + WOLFSSL_ENTER("wolfSSL_CTX_set_groups"); + if (ctx == NULL || groups == NULL || count <= 0 || + count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsTLS_ex(ctx->method->version)) + return BAD_FUNC_ARG; + + ret = wolfssl_set_groups_ext(&ctx->extensions, groups, count, ctx->heap, + ctx->method->side); + if (ret == WOLFSSL_SUCCESS) { + ctx->userCurves = 1; + #ifdef WOLFSSL_TLS13 + for (i = 0; i < count; i++) { + ctx->group[i] = (word16)groups[i]; + } + ctx->numGroups = (byte)count; + #endif + } + + return ret; +} + +/* Set the key exchange groups, in rank order, on the object. A failing + * call leaves the object unchanged. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] groups Array of named groups. + * @param [in] count Number of groups in the array. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl or groups is NULL, the version is not TLS, + * count is not positive or greater than WOLFSSL_MAX_GROUP_COUNT, or + * a group is invalid or not supported. + * @return MEMORY_E on dynamic memory allocation failure. + */ +int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) +{ + int ret; +#ifdef WOLFSSL_TLS13 + int i; +#endif + + WOLFSSL_ENTER("wolfSSL_set_groups"); + if (ssl == NULL || groups == NULL || count <= 0 || + count > WOLFSSL_MAX_GROUP_COUNT) + return BAD_FUNC_ARG; + if (!IsTLS_ex(ssl->version)) + return BAD_FUNC_ARG; + + ret = wolfssl_set_groups_ext(&ssl->extensions, groups, count, ssl->heap, + ssl->options.side); + if (ret == WOLFSSL_SUCCESS) { + ssl->options.userCurves = 1; + #ifdef WOLFSSL_TLS13 + for (i = 0; i < count; i++) { + ssl->group[i] = (word16)groups[i]; + } + ssl->numGroups = (byte)count; + #endif } return ret; @@ -2107,11 +2234,25 @@ int wolfSSL_CTX_set1_sigalgs_list(WOLFSSL_CTX* ctx, const char* list) WOLFSSL_MSG("Bad function arguments"); ret = WOLFSSL_FAILURE; } - else if (AllocateCtxSuites(ctx) != 0) { - ret = WOLFSSL_FAILURE; - } else { - ret = SetSuitesHashSigAlgo(ctx->suites, list); + byte fresh = (ctx->suites == NULL); + + if (AllocateCtxSuites(ctx) != 0) { + ret = WOLFSSL_FAILURE; + } + else { + ret = SetSuitesHashSigAlgo(ctx->suites, list); + } + if (fresh && ctx->suites != NULL) { + if (ret == WOLFSSL_SUCCESS) { + /* Add the default cipher suites to the new sigalgs */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } + else { + XFREE(ctx->suites, ctx->heap, DYNAMIC_TYPE_SUITES); + ctx->suites = NULL; + } + } } return ret; diff --git a/src/tls.c b/src/tls.c index 9d0ae0acf0f..7dbf8940e3b 100644 --- a/src/tls.c +++ b/src/tls.c @@ -391,102 +391,6 @@ ProtocolVersion MakeTLSv1_3(void) } #endif -#if defined(HAVE_SUPPORTED_CURVES) -/* Sets the key exchange groups in rank order on a context. - * - * ctx SSL/TLS context object. - * groups Array of groups. - * count Number of groups in array. - * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3, count is - * not positive or count is greater than WOLFSSL_MAX_GROUP_COUNT and - * WOLFSSL_SUCCESS on success. - */ -int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) -{ - int ret, i; - - WOLFSSL_ENTER("wolfSSL_CTX_set_groups"); - if (ctx == NULL || groups == NULL || count <= 0 || - count > WOLFSSL_MAX_GROUP_COUNT) - return BAD_FUNC_ARG; - if (!IsTLS_ex(ctx->method->version)) - return BAD_FUNC_ARG; - - #ifdef WOLFSSL_TLS13 - ctx->numGroups = 0; - #endif - #if !defined(NO_TLS) - TLSX_Remove(&ctx->extensions, TLSX_SUPPORTED_GROUPS, ctx->heap); - #endif /* !NO_TLS */ - for (i = 0; i < count; i++) { - /* Call to wolfSSL_CTX_UseSupportedCurve also checks if input groups - * are valid */ - if ((ret = wolfSSL_CTX_UseSupportedCurve(ctx, (word16)groups[i])) - != WOLFSSL_SUCCESS) { - #if !defined(NO_TLS) - TLSX_Remove(&ctx->extensions, TLSX_SUPPORTED_GROUPS, ctx->heap); - #endif /* !NO_TLS */ - return ret; - } - #ifdef WOLFSSL_TLS13 - ctx->group[i] = (word16)groups[i]; - #endif - } - #ifdef WOLFSSL_TLS13 - ctx->numGroups = (byte)count; - #endif - - return WOLFSSL_SUCCESS; -} - -/* Sets the key exchange groups in rank order. - * - * ssl SSL/TLS object. - * groups Array of groups. - * count Number of groups in array. - * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3, count is - * not positive or count is greater than WOLFSSL_MAX_GROUP_COUNT and - * WOLFSSL_SUCCESS on success. - */ -int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) -{ - int ret, i; - - WOLFSSL_ENTER("wolfSSL_set_groups"); - if (ssl == NULL || groups == NULL || count <= 0 || - count > WOLFSSL_MAX_GROUP_COUNT) - return BAD_FUNC_ARG; - if (!IsTLS_ex(ssl->version)) - return BAD_FUNC_ARG; - - #ifdef WOLFSSL_TLS13 - ssl->numGroups = 0; - #endif - #if !defined(NO_TLS) - TLSX_Remove(&ssl->extensions, TLSX_SUPPORTED_GROUPS, ssl->heap); - #endif /* !NO_TLS */ - for (i = 0; i < count; i++) { - /* Call to wolfSSL_UseSupportedCurve also checks if input groups - * are valid */ - if ((ret = wolfSSL_UseSupportedCurve(ssl, (word16)groups[i])) - != WOLFSSL_SUCCESS) { - #if !defined(NO_TLS) - TLSX_Remove(&ssl->extensions, TLSX_SUPPORTED_GROUPS, ssl->heap); - #endif /* !NO_TLS */ - return ret; - } - #ifdef WOLFSSL_TLS13 - ssl->group[i] = (word16)groups[i]; - #endif - } - #ifdef WOLFSSL_TLS13 - ssl->numGroups = (byte)count; - #endif - - return WOLFSSL_SUCCESS; -} -#endif /* HAVE_SUPPORTED_CURVES */ - #ifndef WOLFSSL_NO_TLS12 #ifdef HAVE_EXTENDED_MASTER diff --git a/src/tls13.c b/src/tls13.c index 40946c8e0e6..c7e03d34f24 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -17706,6 +17706,10 @@ void wolfSSL_CTX_set_psk_client_cs_callback(WOLFSSL_CTX* ctx, ctx->havePSK = 1; ctx->client_psk_cs_cb = cb; + if (ctx->suites != NULL) { + /* add PSK to the suites derived before */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } } /* Set the PSK callback, that is passed the cipher suite, for a client to use @@ -17758,6 +17762,10 @@ void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx, ctx->havePSK = 1; ctx->client_psk_tls13_cb = cb; + if (ctx->suites != NULL) { + /* add PSK to the suites derived before */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } } /* Set the PSK callback that returns the cipher suite for a client to use @@ -17808,6 +17816,10 @@ void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx, return; ctx->havePSK = 1; ctx->server_psk_tls13_cb = cb; + if (ctx->suites != NULL) { + /* add PSK to the suites derived before */ + InitSSL_CTX_Suites(ctx, ctx->suites); + } } /* Set the PSK callback that returns the cipher suite for a server to use diff --git a/tests/api.c b/tests/api.c index a2507e33259..38dd096c3fc 100644 --- a/tests/api.c +++ b/tests/api.c @@ -6409,6 +6409,597 @@ static int test_wolfSSL_set_minmax_proto_version(void) return EXPECT_RESULT(); } +#if defined(OPENSSL_EXTRA) && !defined(NO_TLS) +/* Calls a version setter that must fail and checks ctx is unchanged. */ +static int test_proto_version_fail(WOLFSSL_CTX* ctx, int max, int ver) +{ + EXPECT_DECLS; + unsigned long mask; + unsigned long minProtoMask; + unsigned long maxProtoMask; + byte minDowngrade; + byte minProto; + byte maxProto; + byte minVersionSet; + ProtocolVersion pv; + int ret; + + if (ctx == NULL) { + return TEST_FAIL; + } + mask = ctx->mask; + minProtoMask = ctx->minProtoMask; + maxProtoMask = ctx->maxProtoMask; + minDowngrade = ctx->minDowngrade; + minProto = (byte)ctx->minProto; + maxProto = (byte)ctx->maxProto; + minVersionSet = (byte)ctx->minVersionSet; + pv = ctx->method->version; + + if (max) { + ret = wolfSSL_CTX_set_max_proto_version(ctx, ver); + } + else { + ret = wolfSSL_CTX_set_min_proto_version(ctx, ver); + } + ExpectIntEQ(ret, WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectTrue(ctx->mask == mask); + ExpectTrue(ctx->minProtoMask == minProtoMask); + ExpectTrue(ctx->maxProtoMask == maxProtoMask); + ExpectIntEQ(ctx->minDowngrade, minDowngrade); + ExpectIntEQ(ctx->minProto, minProto); + ExpectIntEQ(ctx->maxProto, maxProto); + ExpectIntEQ(ctx->minVersionSet, minVersionSet); + ExpectIntEQ(ctx->method->version.major, pv.major); + ExpectIntEQ(ctx->method->version.minor, pv.minor); + + return EXPECT_RESULT(); +} + +/* Calls an SSL version setter that must fail and checks ssl is unchanged. */ +static int test_ssl_proto_version_fail(WOLFSSL* ssl, int max, int ver) +{ + EXPECT_DECLS; + unsigned long mask; + byte minDowngrade; + byte minVersionSet; + byte downgrade; + ProtocolVersion pv; + int ret; + + if (ssl == NULL) { + return TEST_FAIL; + } + mask = ssl->options.mask; + minDowngrade = ssl->options.minDowngrade; + minVersionSet = (byte)ssl->options.minVersionSet; + downgrade = (byte)ssl->options.downgrade; + pv = ssl->version; + + if (max) { + ret = wolfSSL_set_max_proto_version(ssl, ver); + } + else { + ret = wolfSSL_set_min_proto_version(ssl, ver); + } + ExpectIntEQ(ret, WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectTrue(ssl->options.mask == mask); + ExpectIntEQ(ssl->options.minDowngrade, minDowngrade); + ExpectIntEQ(ssl->options.minVersionSet, minVersionSet); + ExpectIntEQ(ssl->options.downgrade, downgrade); + ExpectIntEQ(ssl->version.major, pv.major); + ExpectIntEQ(ssl->version.minor, pv.minor); + + return EXPECT_RESULT(); +} +#endif + +#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) +/* The server makes a failing max or min call on its ssl. The client offers + * only TLS 1.2, which the server still takes. */ +static int test_ssl_proto_version_fail_hs(int max) +{ + 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; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfSSLv23_server_method), 0); + if (max) { + /* SSL 3.0 is not built */ + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_s, SSL3_VERSION), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + } + else { + wolfSSL_set_options(ssl_s, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_set_min_proto_version(ssl_s, TLS1_3_VERSION), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + } + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + 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(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) +/* The server disables versions with opts, then makes version calls that fail + * and one that succeeds. The client offers only a version that opts disables. + */ +static int test_proto_version_fail_hs(method_provider method_c, long opts) +{ + 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; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + method_c, wolfSSLv23_server_method), 0); + wolfSSL_CTX_set_options(ctx_s, opts); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_s, 0x9999), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx_s, 0x9999), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_s, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + method_c, wolfSSLv23_server_method), 0); + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + + return EXPECT_RESULT(); +} +#endif + +/* Failing min and max version calls must not change the ctx. */ +static int test_wolfSSL_CTX_set_minmax_proto_version_fail(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_TLS) + /* How the ctx limits versions before the failing calls */ + static const struct { + int minVer; /* -1: not set */ + int maxVer; /* -1: not set */ + long opts; + } states[] = { + { -1, -1, 0 }, + { -1, -1, WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | + WOLFSSL_OP_NO_TLSv1_2 }, + { TLS1_2_VERSION, -1, WOLFSSL_OP_NO_TLSv1_3 }, + #ifndef WOLFSSL_NO_TLS12 + { TLS1_2_VERSION, TLS1_2_VERSION, 0 }, + #endif + { 0, 0, 0 }, + }; + /* Calls that fail in all of the states */ + static const struct { + int max; /* 1: max setter, 0: min setter */ + int ver; + } calls[] = { + { 0, 0x9999 }, + { 1, 0x9999 }, + { 0, SSL2_VERSION }, + { 1, SSL2_VERSION }, + { 0, DTLS1_2_VERSION }, + { 1, DTLS1_2_VERSION }, + #ifndef WOLFSSL_ALLOW_SSLV3 + { 1, SSL3_VERSION }, + #endif + }; + WOLFSSL_CTX* ctx = NULL; + size_t i; + size_t j; + + for (i = 0; i < XELEM_CNT(states); i++) { + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + if (states[i].minVer >= 0) { + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, + states[i].minVer), WOLFSSL_SUCCESS); + } + if (states[i].maxVer >= 0) { + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, + states[i].maxVer), WOLFSSL_SUCCESS); + } + wolfSSL_CTX_set_options(ctx, states[i].opts); + for (j = 0; j < XELEM_CNT(calls); j++) { + ExpectIntEQ(test_proto_version_fail(ctx, calls[j].max, + calls[j].ver), TEST_SUCCESS); + } + wolfSSL_CTX_free(ctx); + ctx = NULL; + } + + /* No version left: the min setter fails and leaves the ctx unchanged */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_SSLv3 | WOLFSSL_OP_NO_TLSv1 | + WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_proto_version_fail(ctx, 0, TLS1_3_VERSION), TEST_SUCCESS); + ExpectIntEQ(test_proto_version_fail(ctx, 0, TLS1_2_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* A min that leaves only versions disabled with options fails */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_proto_version_fail(ctx, 0, TLS1_3_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* Versions below the min are not left either */ +#if !defined(WOLFSSL_LEANPSK) && !defined(WOLFSSL_NO_TLS12) + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_2), + WOLFSSL_SUCCESS); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); + ExpectIntEQ(test_proto_version_fail(ctx, 1, TLS1_2_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif +#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_TLS13) + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3), + WOLFSSL_SUCCESS); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_proto_version_fail(ctx, 1, TLS1_3_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif +#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_ALLOW_TLSV10) + /* Without TLS 1.0 a TLS 1.0 min is TLS 1.1 */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1 | + WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_proto_version_fail(ctx, 0, TLS1_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + +#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_LEANPSK) + /* A failing max keeps a min raised over an auto min */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_proto_version_fail(ctx, 1, 0x9999), TEST_SUCCESS); +#ifndef WOLFSSL_NO_TLS12 + /* A max below that min fails */ + ExpectIntEQ(test_proto_version_fail(ctx, 1, TLS1_2_VERSION), TEST_SUCCESS); +#endif + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(OPENSSL_COMPATIBLE_DEFAULTS) + /* A max below the default min fails */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(test_proto_version_fail(ctx, 1, SSL3_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + +#ifdef WOLFSSL_DTLS + /* A DTLS ctx keeps its DTLS min when a call fails */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_method())); + ExpectIntEQ(test_proto_version_fail(ctx, 1, 0x9999), TEST_SUCCESS); + ExpectIntEQ(test_proto_version_fail(ctx, 0, 0x9999), TEST_SUCCESS); + ExpectIntEQ(test_proto_version_fail(ctx, 1, TLS1_2_VERSION), TEST_SUCCESS); + wolfSSL_CTX_free(ctx); +#endif +#endif +#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) + /* TLS 1.3 only server still rejects TLS 1.2 */ + ExpectIntEQ(test_proto_version_fail_hs(wolfTLSv1_2_client_method, + WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2), + TEST_SUCCESS); + /* Server without TLS 1.3 still rejects TLS 1.3 */ + ExpectIntEQ(test_proto_version_fail_hs(wolfTLSv1_3_client_method, + WOLFSSL_OP_NO_TLSv1_3), TEST_SUCCESS); +#endif + + return EXPECT_RESULT(); +} + +/* Failing SSL min and max version calls must not change the ssl. */ +static int test_wolfSSL_set_minmax_proto_version_fail(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_TLS) + /* Calls that fail on a TLS ssl */ + static const struct { + int max; /* 1: max setter, 0: min setter */ + int ver; + } calls[] = { + { 0, 0x9999 }, + { 1, 0x9999 }, + { 0, SSL2_VERSION }, + { 1, SSL2_VERSION }, + { 0, DTLS1_2_VERSION }, + { 1, DTLS1_2_VERSION }, + #ifndef WOLFSSL_ALLOW_SSLV3 + { 1, SSL3_VERSION }, + #endif + }; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + size_t i; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + for (i = 0; i < XELEM_CNT(calls); i++) { + ExpectIntEQ(test_ssl_proto_version_fail(ssl, calls[i].max, + calls[i].ver), TEST_SUCCESS); + } + wolfSSL_free(ssl); + ssl = NULL; + + /* No version left */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_set_options(ssl, WOLFSSL_OP_NO_SSLv3 | WOLFSSL_OP_NO_TLSv1 | + WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 0, TLS1_3_VERSION), + TEST_SUCCESS); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 0, TLS1_2_VERSION), + TEST_SUCCESS); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 0, 0), TEST_SUCCESS); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 1, 0), TEST_SUCCESS); + wolfSSL_free(ssl); + ssl = NULL; + + /* A min that leaves only versions disabled with options fails */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 0, TLS1_3_VERSION), + TEST_SUCCESS); + wolfSSL_free(ssl); + ssl = NULL; + +#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_ALLOW_TLSV10) + /* Without TLS 1.0 a TLS 1.0 min is TLS 1.1 */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 0, TLS1_VERSION), + TEST_SUCCESS); + wolfSSL_free(ssl); + ssl = NULL; +#endif + +#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_TLS12) + /* A max below the min fails */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl, WOLFSSL_TLSV1_3), WOLFSSL_SUCCESS); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 1, TLS1_2_VERSION), + TEST_SUCCESS); + /* So does an automatic max with only versions below the min on */ + wolfSSL_set_options(ssl, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 1, 0), TEST_SUCCESS); + wolfSSL_free(ssl); + ssl = NULL; +#endif +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(OPENSSL_COMPATIBLE_DEFAULTS) + /* A max below the default min fails */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 1, SSL3_VERSION), + TEST_SUCCESS); + wolfSSL_free(ssl); + ssl = NULL; +#endif + wolfSSL_CTX_free(ctx); + ctx = NULL; + +#ifdef WOLFSSL_DTLS + /* A DTLS ssl takes no TLS max */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 1, TLS1_2_VERSION), + TEST_SUCCESS); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 1, 0x9999), TEST_SUCCESS); + ExpectIntEQ(test_ssl_proto_version_fail(ssl, 0, 0x9999), TEST_SUCCESS); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +#endif +#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) + ExpectIntEQ(test_ssl_proto_version_fail_hs(0), TEST_SUCCESS); +#ifndef WOLFSSL_ALLOW_SSLV3 + ExpectIntEQ(test_ssl_proto_version_fail_hs(1), TEST_SUCCESS); +#endif +#endif + + return EXPECT_RESULT(); +} + +/* The version setters only replace the limits they set themselves. */ +static int test_wolfSSL_CTX_set_minmax_proto_version_opts(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_TLS) && defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; +#ifdef WOLFSSL_DTLS + byte minDowngrade = 0; +#endif +#ifndef NO_OLD_TLS + /* Setter calls that end with TLS 1.2 disabled */ + static const struct { + int max[4]; /* 1: max setter, 0: min setter */ + int ver[4]; + } seqs[] = { + { { 1, 1, 0, 1 }, + { TLS1_1_VERSION, TLS1_3_VERSION, TLS1_3_VERSION, TLS1_3_VERSION } }, + { { 0, 0, 1, 0 }, + { TLS1_3_VERSION, TLS1_1_VERSION, TLS1_1_VERSION, TLS1_1_VERSION } }, + { { 1, 0, 0, 1 }, + { TLS1_1_VERSION, TLS1_2_VERSION, TLS1_3_VERSION, TLS1_3_VERSION } }, + }; + size_t i; + size_t j; +#endif + + /* Options set by the application are kept */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_2) != 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* A new max or min replaces the previous one */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_3) == 0); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_2) == 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* A version also disabled with options stays disabled, whichever came + * first */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_3) != 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_3) != 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_2) != 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; + +#ifndef NO_OLD_TLS + /* Both setters can disable TLS 1.2. Each drops only its own record. */ + for (i = 0; i < XELEM_CNT(seqs); i++) { + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + for (j = 0; j < XELEM_CNT(seqs[i].ver); j++) { + if (seqs[i].max[j]) { + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, + seqs[i].ver[j]), WOLFSSL_SUCCESS); + } + else { + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, + seqs[i].ver[j]), WOLFSSL_SUCCESS); + } + } + ExpectTrue((wolfSSL_CTX_get_options(ctx) & + WOLFSSL_OP_NO_TLSv1_2) != 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; + } + + /* Options cleared by the application are no longer the max's */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION), + WOLFSSL_SUCCESS); + wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_TLSv1_2 | + WOLFSSL_OP_NO_TLSv1_3); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_2) != 0); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + +#ifndef WOLFSSL_LEANPSK + /* wolfSSL_CTX_SetMinVersion() replaces the min of the min setter */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_2), + WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_CTX_get_options(ctx) & WOLFSSL_OP_NO_TLSv1_2) == 0); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* The max setter does not change the min */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_3_VERSION); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(ctx->minDowngrade, TLSv1_3_MINOR); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + +#if !defined(NO_OLD_TLS) && !defined(WOLFSSL_ALLOW_TLSV10) && \ + !(defined(WOLFSSL_ALLOW_SSLV3) && defined(OPENSSL_COMPATIBLE_DEFAULTS)) + /* Nor the default min, which is TLS 1.1 when TLS 1.0 is not allowed */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_1_VERSION); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get_min_proto_version(ctx), TLS1_1_VERSION); + wolfSSL_CTX_free(ctx); + ctx = NULL; +#endif + +#ifdef WOLFSSL_DTLS + /* Nor a DTLS min */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_method())); + if (EXPECT_SUCCESS()) { + minDowngrade = ctx->minDowngrade; + } + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(ctx->minDowngrade, minDowngrade); + wolfSSL_CTX_free(ctx); +#endif +#endif + + return EXPECT_RESULT(); +} + #if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) && \ defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) static int test_wolfSSL_CTX_set_max_proto_version_on_result(WOLFSSL* ssl) @@ -6458,6 +7049,150 @@ static int test_wolfSSL_CTX_set_max_proto_version(void) } #endif +/* Raising the max after the suites were derived offers the new suites. */ +static int test_wolfSSL_CTX_set_max_proto_version_suites(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12) + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + /* Derive the suites of both with a TLS 1.2 max */ + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_s, TLS1_2_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_s, TLS1_3_VERSION), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, NULL, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + /* No SetDH() on the server, which would rebuild the suites of the ssl */ + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectStrEQ(wolfSSL_get_version(ssl_c), "TLSv1.3"); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && \ + defined(BUILD_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256) +static unsigned int test_suites_psk_client_cb(WOLFSSL* ssl, const char* hint, + char* identity, unsigned int id_max_len, unsigned char* key, + unsigned int key_max_len) +{ + (void)ssl; + (void)hint; + (void)key_max_len; + XSTRNCPY(identity, "Client_identity", id_max_len); + XMEMSET(key, 0x11, 32); + return 32; +} + +static unsigned int test_suites_psk_server_cb(WOLFSSL* ssl, const char* id, + unsigned char* key, unsigned int key_max_len) +{ + (void)ssl; + (void)id; + (void)key_max_len; + XMEMSET(key, 0x11, 32); + return 32; +} +#endif + +/* A PSK callback set after the suites were derived adds the PSK suites. */ +static int test_wolfSSL_CTX_set_psk_client_callback_suites(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && \ + defined(BUILD_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256) + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfSSLv23_client_method, wolfTLSv1_2_server_method), 0); +#ifdef OPENSSL_EXTRA + /* A max sets no options, so new SSLs share the suites of the ctx */ + ExpectIntEQ(wolfSSL_CTX_set_max_proto_version(ctx_c, 0), WOLFSSL_SUCCESS); +#endif + /* The first ssl derives the suites */ + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_CTX_set_psk_client_callback(ctx_c, test_suites_psk_client_cb); + wolfSSL_CTX_set_psk_server_callback(ctx_s, test_suites_psk_server_cb); + ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx_s, + "ECDHE-PSK-AES128-GCM-SHA256"), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* Allowing anon ciphers after the suites were derived adds the anon suites. */ +static int test_wolfSSL_CTX_allow_anon_cipher_suites(void) +{ + EXPECT_DECLS; +#if defined(BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(OPENSSL_COMPATIBLE_DEFAULTS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + word16 i; + int found = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + /* The first ssl derives the suites */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_free(ssl); + ExpectIntEQ(wolfSSL_CTX_allow_anon_cipher(ctx), WOLFSSL_SUCCESS); + ExpectNotNull(ctx->suites); + for (i = 0; (ctx != NULL) && (ctx->suites != NULL) && + (i + 1 < ctx->suites->suiteSz); i += 2) { + if ((ctx->suites->suites[i] == CIPHER_BYTE) && + (ctx->suites->suites[i + 1] == + TLS_DH_anon_WITH_AES_256_GCM_SHA384)) { + found = 1; + } + } + ExpectIntEQ(found, 1); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + /*----------------------------------------------------------------------------* | SSL *----------------------------------------------------------------------------*/ @@ -7076,8 +7811,7 @@ static int test_wolfSSL_SetVersion_auto_min(void) ctx = NULL; #endif - /* setting a maximum reapplies the minimum internally, which must not - * disturb the flag */ + /* setting a maximum must not disturb the flag */ ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); ExpectIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION), WOLFSSL_SUCCESS); @@ -20747,6 +21481,243 @@ static int test_wolfSSL_set1_sigalgs_list(void) return EXPECT_RESULT(); } +#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) && \ + defined(HAVE_ECC) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) +/* The server takes only P-384 and then makes a failing call that would add + * P-256, on the ctx or on the ssl. The client offers only P-256. */ +static int test_set_groups_fail_hs(int onSsl) +{ + 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; + int p256 = WOLFSSL_ECC_SECP256R1; + int p384 = WOLFSSL_ECC_SECP384R1; + /* P-256 is added before the invalid group is found */ + int bad[] = { WOLFSSL_ECC_SECP256R1, 0x1234 }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + if (!onSsl) { + ExpectIntEQ(wolfSSL_CTX_set_groups(ctx_s, &p384, 1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CTX_set_groups(ctx_s, bad, 2), WOLFSSL_SUCCESS); + ExpectIntEQ(ctx_s->numGroups, 1); + ExpectIntEQ(ctx_s->group[0], WOLFSSL_ECC_SECP384R1); + ExpectNotNull(ext = TLSX_Find(ctx_s->extensions, + TLSX_SUPPORTED_GROUPS)); + } + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + if (onSsl) { + ExpectIntEQ(wolfSSL_set_groups(ssl_s, &p384, 1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_set_groups(ssl_s, bad, 2), WOLFSSL_SUCCESS); + ExpectIntEQ(ssl_s->numGroups, 1); + ExpectIntEQ(ssl_s->group[0], WOLFSSL_ECC_SECP384R1); + ExpectNotNull(ext = TLSX_Find(ssl_s->extensions, + TLSX_SUPPORTED_GROUPS)); + } + ExpectIntEQ(((SupportedCurve*)ext->data)->name, WOLFSSL_ECC_SECP384R1); + ExpectNull(((SupportedCurve*)ext->data)->next); + + ExpectIntEQ(wolfSSL_set_groups(ssl_c, &p256, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP256R1), + WOLFSSL_SUCCESS); + /* No group in common */ + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + + return EXPECT_RESULT(); +} + +/* A valid group that is not built in */ +#if !defined(HAVE_CURVE448) + #define TEST_UNBUILT_GROUP WOLFSSL_ECC_X448 +#elif ECC_MIN_KEY_SZ > 160 || \ + (!defined(HAVE_ECC160) && !defined(HAVE_ALL_CURVES)) + #define TEST_UNBUILT_GROUP WOLFSSL_ECC_SECP160R1 +#endif + +/* Failing group calls on a new client ctx and ssl keep the default groups. */ +static int test_set_groups_fail_fresh(void) +{ + 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; + int bad[] = { WOLFSSL_ECC_SECP256R1, 0x1234 }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntNE(wolfSSL_CTX_set_groups(ctx_c, bad, 2), WOLFSSL_SUCCESS); +#ifdef TEST_UNBUILT_GROUP + ExpectIntNE(wolfSSL_CTX_UseSupportedCurve(ctx_c, TEST_UNBUILT_GROUP), + WOLFSSL_SUCCESS); +#endif + ExpectIntEQ(ctx_c->userCurves, 0); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntNE(wolfSSL_set_groups(ssl_c, bad, 2), WOLFSSL_SUCCESS); +#ifdef TEST_UNBUILT_GROUP + ExpectIntNE(wolfSSL_UseSupportedCurve(ssl_c, TEST_UNBUILT_GROUP), + WOLFSSL_SUCCESS); +#endif + ExpectIntEQ(ssl_c->options.userCurves, 0); + /* The client still offers the default groups */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + + return EXPECT_RESULT(); +} +#endif + +/* A failing group setter keeps the groups set before. */ +static int test_wolfSSL_set_groups_fail(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) && \ + defined(HAVE_ECC) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) + ExpectIntEQ(test_set_groups_fail_hs(0), TEST_SUCCESS); + ExpectIntEQ(test_set_groups_fail_hs(1), TEST_SUCCESS); + ExpectIntEQ(test_set_groups_fail_fresh(), TEST_SUCCESS); +#endif + return EXPECT_RESULT(); +} + +#if defined(OPENSSL_EXTRA) && !defined(NO_TLS) && defined(HAVE_ECC) && \ + !defined(NO_SHA256) && defined(WOLFSSL_SHA384) +/* Makes failing calls and checks the list in suites is unchanged. */ +static int test_sigalgs_list_fail(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + EXPECT_DECLS; + /* An unknown name after a good entry, a bad digest, no digest */ + static const char* bad[] = { + "ECDSA+SHA384:BOGUS+SHA256", "ECDSA+BOGUS", "ECDSA" + }; + Suites* suites = NULL; + byte saved[WOLFSSL_MAX_SIGALGO]; + word16 savedSz = 0; + size_t i; + + if (ssl != NULL) { + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "ECDSA+SHA256"), + WOLFSSL_SUCCESS); + suites = ssl->suites; + } + else { + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, "ECDSA+SHA256"), + WOLFSSL_SUCCESS); + suites = ctx->suites; + } + ExpectNotNull(suites); + if (EXPECT_SUCCESS()) { + savedSz = suites->hashSigAlgoSz; + XMEMCPY(saved, suites->hashSigAlgo, savedSz); + } + for (i = 0; i < XELEM_CNT(bad); i++) { + if (ssl != NULL) { + ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, bad[i]), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + } + else { + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, bad[i]), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + } + ExpectIntEQ(suites->hashSigAlgoSz, savedSz); + ExpectBufEQ(suites->hashSigAlgo, saved, savedSz); + } + + return EXPECT_RESULT(); +} +#endif + +/* A failing sigalgs list call keeps the list set before. */ +static int test_wolfSSL_set1_sigalgs_list_fail(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_TLS) && defined(HAVE_ECC) && \ + !defined(NO_SHA256) && defined(WOLFSSL_SHA384) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; +#ifdef HAVE_SSL_MEMIO_TESTS_DEPENDENCIES + struct test_memio_ctx test_ctx; + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; +#endif + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_method())); + ExpectIntEQ(test_sigalgs_list_fail(ctx, NULL), TEST_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(test_sigalgs_list_fail(ctx, ssl), TEST_SUCCESS); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + +#ifdef HAVE_SSL_MEMIO_TESTS_DEPENDENCIES + /* A client that takes only ECDSA rejects the RSA server. The options make + * wolfSSL_new() fill an empty list with the defaults. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + wolfSSL_CTX_set_options(ctx_c, WOLFSSL_OP_NO_COMPRESSION); + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx_c, "ECDSA+SHA256"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx_c, "ECDSA+BOGUS"), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + +#ifdef WC_RSA_PSS + /* A new client ctx without options keeps its cipher suites */ + ctx_c = NULL; + ctx_s = NULL; + ssl_c = NULL; + ssl_s = NULL; + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx_c, "ECDSA+BOGUS"), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectNull(ctx_c->suites); + ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx_c, + "RSA-PSS+SHA256:RSA+SHA256"), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfSSLv23_client_method, wolfSSLv23_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif +#endif +#endif + return EXPECT_RESULT(); +} + /* Testing wolfSSL_set_tlsext_status_type function. * PRE: OPENSSL and HAVE_CERTIFICATE_STATUS_REQUEST defined. */ @@ -35385,6 +36356,26 @@ static int test_wolfSSL_crypto_policy_ciphers(void) return EXPECT_RESULT(); } +/* Without a policy, a new TLS ctx keeps the default minimum version. */ +static int test_wolfSSL_crypto_policy_default_min(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) && !defined(NO_TLS) && \ + !defined(OPENSSL_COMPATIBLE_DEFAULTS) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_crypto_policy_is_enabled(), 0); +#ifndef NO_WOLFSSL_CLIENT + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); +#else + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#endif + ExpectIntEQ(ctx->minDowngrade, WOLFSSL_MIN_DOWNGRADE); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + static int test_wolfSSL_SSL_in_init(void) { EXPECT_DECLS; @@ -45630,6 +46621,8 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_set1_curves_list), TEST_DECL(test_wolfSSL_curves_mismatch), TEST_DECL(test_wolfSSL_set1_sigalgs_list), + TEST_DECL(test_wolfSSL_set_groups_fail), + TEST_DECL(test_wolfSSL_set1_sigalgs_list_fail), TEST_DECL(test_wolfSSL_OtherName), TEST_DECL(test_wolfSSL_FPKI), @@ -45897,6 +46890,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_crypto_policy_certs_and_keys), TEST_DECL(test_wolfSSL_crypto_policy_tls_methods), TEST_DECL(test_wolfSSL_crypto_policy_ciphers), + TEST_DECL(test_wolfSSL_crypto_policy_default_min), TEST_DECL(test_wolfSSL_SSL_in_init), TEST_DECL(test_wolfSSL_CTX_set_timeout), TEST_DECL(test_wolfSSL_session_cache_api_direct), @@ -46046,7 +47040,13 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_set_ecdh_auto), TEST_DECL(test_wolfSSL_CTX_set_ecdh_auto), TEST_DECL(test_wolfSSL_set_minmax_proto_version), + TEST_DECL(test_wolfSSL_CTX_set_minmax_proto_version_fail), + TEST_DECL(test_wolfSSL_set_minmax_proto_version_fail), + TEST_DECL(test_wolfSSL_CTX_set_minmax_proto_version_opts), TEST_DECL(test_wolfSSL_CTX_set_max_proto_version), + TEST_DECL(test_wolfSSL_CTX_set_max_proto_version_suites), + TEST_DECL(test_wolfSSL_CTX_set_psk_client_callback_suites), + TEST_DECL(test_wolfSSL_CTX_allow_anon_cipher_suites), TEST_DECL(test_wolfSSL_THREADID_hash), /* TLS extensions tests */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a7446e72f7e..62ee295ca97 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2020,8 +2020,10 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); /* minimum Downgrade Minor version */ #ifndef WOLFSSL_MIN_DOWNGRADE - #ifndef NO_OLD_TLS + #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) #define WOLFSSL_MIN_DOWNGRADE TLSv1_MINOR + #elif !defined(NO_OLD_TLS) + #define WOLFSSL_MIN_DOWNGRADE TLSv1_1_MINOR #else #define WOLFSSL_MIN_DOWNGRADE TLSv1_2_MINOR #endif @@ -4622,6 +4624,10 @@ struct WOLFSSL_CTX { short minMlDsaKeySz; /* minimum ML-DSA key size */ #endif unsigned long mask; /* store SSL_OP_ flags */ +#ifdef OPENSSL_EXTRA + unsigned long minProtoMask; /* SSL_OP_NO_* set by min version */ + unsigned long maxProtoMask; /* SSL_OP_NO_* set by max version */ +#endif #if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) word32 disabledCurves; /* curves disabled by user */ #endif