diff --git a/src/internal.c b/src/internal.c index 9b66eceb8..3cd0659c0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5844,6 +5844,8 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->version = ctx->method->version; #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) ssl->options.mask = ctx->mask; + ssl->options.minProto = ctx->minProto; + ssl->options.maxProto = ctx->maxProto; #endif #ifdef OPENSSL_EXTRA #ifdef WOLFSSL_TLS13 diff --git a/src/ssl.c b/src/ssl.c index aba4ea5c4..8cdbbd401 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17901,14 +17901,35 @@ static int CheckSslMethodVersion(byte major, unsigned long options) } /** - * This function 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. CheckSslMethodVersion() is called to check if any - * remaining protocol versions are enabled. + * protoVerTbl holds (D)TLS version numbers in ascending order. + * Except DTLS versions, the newer version is located in the latter part of + * the table. This table is referred by wolfSSL_CTX_set_min_proto_version and + * wolfSSL_CTX_set_max_proto_version. + */ +static const int protoVerTbl[] = { + SSL3_VERSION, + TLS1_VERSION, + TLS1_1_VERSION, + TLS1_2_VERSION, + TLS1_3_VERSION, + DTLS1_VERSION, + DTLS1_2_VERSION +}; +/* 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 * @param version Any of the following + * * 0 * * SSL3_VERSION * * TLS1_VERSION * * TLS1_1_VERSION @@ -17919,9 +17940,9 @@ static int CheckSslMethodVersion(byte major, unsigned long options) * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ -int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) +static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) { - WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version"); + WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version_ex"); if (ctx == NULL) { return WOLFSSL_FAILURE; @@ -18002,15 +18023,73 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) return CheckSslMethodVersion(ctx->method->version.major, ctx->mask); } +/* Sets the min protocol version allowed with WOLFSSL_CTX + * returns WOLFSSL_SUCCESS on success */ +int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) +{ + int ret; + int proto = 0; + int maxProto = 0; + int i; + int idx = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version"); + + if (ctx == NULL) { + return WOLFSSL_FAILURE; + } + 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; + } + } + } + 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]); + 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); + 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); + } + + ret = Set_CTX_min_proto_version(ctx, proto); + return ret; +} + /** - * This function 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. CheckSslMethodVersion() is called to check if any - * remaining protocol versions are enabled. + * 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 * @param version Any of the following + * * 0 * * SSL3_VERSION * * TLS1_VERSION * * TLS1_1_VERSION @@ -18021,9 +18100,9 @@ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ -int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int ver) +static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) { - WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version"); + WOLFSSL_ENTER("Set_CTX_max_proto_version"); if (!ctx || !ctx->method) { WOLFSSL_MSG("Bad parameter"); @@ -18064,9 +18143,50 @@ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int ver) return CheckSslMethodVersion(ctx->method->version.major, ctx->mask); } -int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int ver) + +/* Sets the max protocol version allowed with WOLFSSL_CTX + * returns WOLFSSL_SUCCESS on success */ +int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) { - WOLFSSL_ENTER("wolfSSL_set_min_proto_version"); + int i; + int ret; + int minProto; + + WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version"); + + if (ctx == NULL) { + return WOLFSSL_FAILURE; + } + + /* 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); + wolfSSL_CTX_set_min_proto_version(ctx, minProto); + if (version != 0) { + ctx->maxProto = 0; /* turn max proto flag off */ + return Set_CTX_max_proto_version(ctx, 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; + } + } + + 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; @@ -18147,10 +18267,34 @@ int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int ver) return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); } -int wolfSSL_set_max_proto_version(WOLFSSL* ssl, int ver) +int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int version) +{ + int i; + int ret = WOLFSSL_FAILURE;; + + WOLFSSL_ENTER("wolfSSL_set_min_proto_version"); + + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + if (version != 0) { + return Set_SSL_min_proto_version(ssl, version); + } + + /* 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]); + if (ret == WOLFSSL_SUCCESS) + break; + } + + return ret; +} + +static int Set_SSL_max_proto_version(WOLFSSL* ssl, int ver) { - WOLFSSL_ENTER("wolfSSL_set_max_proto_version"); + WOLFSSL_ENTER("Set_SSL_max_proto_version"); if (!ssl) { WOLFSSL_MSG("Bad parameter"); @@ -18191,6 +18335,32 @@ int wolfSSL_set_max_proto_version(WOLFSSL* ssl, int ver) return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); } +int wolfSSL_set_max_proto_version(WOLFSSL* ssl, int version) +{ + int i; + int ret = WOLFSSL_FAILURE;; + + WOLFSSL_ENTER("wolfSSL_set_max_proto_version"); + + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } + if (version != 0) { + return Set_SSL_max_proto_version(ssl, 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_SSL_max_proto_version(ssl, protoVerTbl[i]); + if (ret == WOLFSSL_SUCCESS) + break; + } + + return ret; +} + static int GetMinProtoVersion(int minDowngrade) { int ret; @@ -18236,9 +18406,14 @@ WOLFSSL_API int wolfSSL_CTX_get_min_proto_version(WOLFSSL_CTX* ctx) WOLFSSL_ENTER("wolfSSL_CTX_get_min_proto_version"); if (ctx != NULL) { - ret = GetMinProtoVersion(ctx->minDowngrade); + if (ctx->minProto) { + ret = 0; + } + else { + ret = GetMinProtoVersion(ctx->minDowngrade); + } } - if (ret == 0) { + else { ret = GetMinProtoVersion(WOLFSSL_MIN_DOWNGRADE); } @@ -18247,6 +18422,63 @@ WOLFSSL_API int wolfSSL_CTX_get_min_proto_version(WOLFSSL_CTX* ctx) return ret; } + +/* returns the maximum allowed protocol version given the 'options' used + * returns WOLFSSL_FATAL_ERROR on no match */ +static int GetMaxProtoVersion(long options) +{ +#ifdef WOLFSSL_TLS13 + if (!(options & WOLFSSL_OP_NO_TLSv1_3)) + return TLS1_3_VERSION; +#endif +#ifndef WOLFSSL_NO_TLS12 + if (!(options & WOLFSSL_OP_NO_TLSv1_2)) + return TLS1_2_VERSION; +#endif +#ifndef NO_OLD_TLS + if (!(options & WOLFSSL_OP_NO_TLSv1_1)) + return TLS1_1_VERSION; + #ifdef WOLFSSL_ALLOW_TLSV10 + if (!(options & WOLFSSL_OP_NO_TLSv1)) + return TLS1_VERSION; + #endif + #ifdef WOLFSSL_ALLOW_SSLV3 + if (!(options & WOLFSSL_OP_NO_SSLv3)) + return SSL3_VERSION; + #endif +#endif + + return WOLFSSL_FATAL_ERROR; +} + + +/* 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 */ + + WOLFSSL_ENTER("wolfSSL_CTX_get_max_proto_version"); + + if (ctx != NULL) { + options = wolfSSL_CTX_get_options(ctx); + } + + if (ctx->maxProto) { + ret = 0; + } + else { + ret = GetMaxProtoVersion(options); + } + + WOLFSSL_LEAVE("wolfSSL_CTX_get_max_proto_version", ret); + + if (ret == WOLFSSL_FATAL_ERROR) { + WOLFSSL_MSG("Error getting max proto version"); + ret = 0; /* setting ret to 0 to match compat return */ + } + return ret; +} #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ @@ -46403,18 +46635,16 @@ long wolfSSL_CTX_ctrl(WOLFSSL_CTX* ctx, int cmd, long opt, void* pt) break; case SSL_CTRL_SET_MIN_PROTO_VERSION: WOLFSSL_MSG("set min proto version"); - if (opt == 0) { - /* do nothing */ - return WOLFSSL_SUCCESS; - } return wolfSSL_CTX_set_min_proto_version(ctx, (int)opt); case SSL_CTRL_SET_MAX_PROTO_VERSION: WOLFSSL_MSG("set max proto version"); - if (opt == 0) { - /* do nothing */ - return WOLFSSL_SUCCESS; - } return wolfSSL_CTX_set_max_proto_version(ctx, (int)opt); + case SSL_CTRL_GET_MIN_PROTO_VERSION: + WOLFSSL_MSG("get min proto version"); + return wolfSSL_CTX_get_min_proto_version(ctx); + case SSL_CTRL_GET_MAX_PROTO_VERSION: + WOLFSSL_MSG("get max proto version"); + return wolfSSL_CTX_get_max_proto_version(ctx); default: WOLFSSL_MSG("CTX_ctrl cmd not implemented"); ret = WOLFSSL_FAILURE; diff --git a/tests/api.c b/tests/api.c index 81aa480b1..9361abb3f 100644 --- a/tests/api.c +++ b/tests/api.c @@ -2671,6 +2671,47 @@ static void test_wolfSSL_CTX_ticket_API(void) #endif /* HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER */ } +static void test_wolfSSL_set_minmax_proto_version(void) +{ +#ifdef OPENSSL_EXTRA +WOLFSSL_CTX *ctx; +WOLFSSL *ssl; +int ret; +(void)ret; +(void)ssl; +printf(testingFmt, "test_wolfSSL_set_minmax_proto_version"); + +#ifndef NO_WOLFSSL_CLIENT + AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + AssertNotNull(ssl = wolfSSL_new(ctx)); + + AssertIntEQ(wolfSSL_CTX_set_min_proto_version(NULL, 0), SSL_FAILURE); + AssertIntEQ(wolfSSL_CTX_set_max_proto_version(NULL, 0), SSL_FAILURE); + AssertIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, 0), SSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, 0), SSL_SUCCESS); + + AssertIntEQ(wolfSSL_set_min_proto_version(NULL, 0), SSL_FAILURE); + AssertIntEQ(wolfSSL_set_min_proto_version(ssl, 0), SSL_SUCCESS); + AssertIntEQ(wolfSSL_set_max_proto_version(NULL, 0), SSL_FAILURE); + AssertIntEQ(wolfSSL_set_max_proto_version(ssl, 0), SSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + +#else + AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + AssertIntEQ(wolfSSL_CTX_set_min_proto_version(NULL, 0), SSL_FAILURE); + AssertIntEQ(wolfSSL_CTX_set_max_proto_version(NULL, 0), SSL_FAILURE); + AssertIntEQ(wolfSSL_CTX_set_min_proto_version(ctx, 0), SSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_set_max_proto_version(ctx, 0), SSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + + printf(resultFmt, passed); +#endif +} /*----------------------------------------------------------------------------* | SSL @@ -19217,7 +19258,7 @@ static int test_wc_RsaPublicEncryptDecrypt (void) if (in == NULL || plain == NULL || cipher == NULL) { printf("test_wc_RsaPublicEncryptDecrypt malloc failed\n"); return MEMORY_E; - } +} #endif XMEMCPY(in, inStr, inLen); @@ -42597,6 +42638,12 @@ static void test_wolfSSL_CTX_ctrl(void) AssertIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, TLS1_3_VERSION, NULL), SSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), TLS1_3_VERSION); + #ifndef WOLFSSL_NO_TLS12 + AssertIntEQ((int)wolfSSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, + TLS1_2_VERSION, NULL), SSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_get_max_proto_version(ctx), TLS1_2_VERSION); + #endif #endif /* Cleanup and Pass */ #if !defined(NO_DH) && !defined(NO_DSA) @@ -51607,6 +51654,7 @@ void ApiTest(void) test_wolfSSL_Tls13_Key_Logging_test(); test_wolfSSL_Tls13_postauth(); test_wolfSSL_CTX_set_ecdh_auto(); + test_wolfSSL_set_minmax_proto_version(); test_wolfSSL_THREADID_hash(); test_wolfSSL_RAND_set_rand_method(); test_wolfSSL_RAND_bytes(); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 28d45e804..744cf5037 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2871,6 +2871,8 @@ struct WOLFSSL_CTX { short minFalconKeySz; /* minimum Falcon key size */ #endif unsigned long mask; /* store SSL_OP_ flags */ + word16 minProto:1; /* sets min to min available */ + word16 maxProto:1; /* sets max to max available */ #ifdef OPENSSL_EXTRA byte sessionCtx[ID_LEN]; /* app session context ID */ word32 disabledCurves; /* curves disabled by user */ @@ -3565,6 +3567,8 @@ typedef struct Options { #endif /* NO_PSK */ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(WOLFSSL_WPAS_SMALL) unsigned long mask; /* store SSL_OP_ flags */ + word16 minProto:1; /* sets min to min available */ + word16 maxProto:1; /* sets max to max available */ #endif #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) unsigned int maxTicketTls13; /* maximum number of tickets to send */ diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 5137415b9..114e8a7fb 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -1184,6 +1184,7 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define SSL_set_min_proto_version wolfSSL_set_min_proto_version #define SSL_set_max_proto_version wolfSSL_set_max_proto_version #define SSL_CTX_get_min_proto_version wolfSSL_CTX_get_min_proto_version +#define SSL_CTX_get_max_proto_version wolfSSL_CTX_get_max_proto_version #define SSL_get_tlsext_status_exts wolfSSL_get_tlsext_status_exts @@ -1213,6 +1214,8 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define SSL_CTRL_GET_SERVER_TMP_KEY SSL_CTRL_GET_PEER_TMP_KEY #define SSL_CTRL_SET_MIN_PROTO_VERSION 123 #define SSL_CTRL_SET_MAX_PROTO_VERSION 124 +#define SSL_CTRL_GET_MIN_PROTO_VERSION 125 +#define SSL_CTRL_GET_MAX_PROTO_VERSION 126 #define SSL_CTRL_SET_CURVES SSL_CTRL_SET_GROUPS #define SSL_CTRL_EXTRA_CHAIN_CERT 14 diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index dbbbc4329..cd99c5252 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -4024,6 +4024,7 @@ WOLFSSL_API int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX*, int); WOLFSSL_API int wolfSSL_set_min_proto_version(WOLFSSL*, int); WOLFSSL_API int wolfSSL_set_max_proto_version(WOLFSSL*, int); WOLFSSL_API int wolfSSL_CTX_get_min_proto_version(WOLFSSL_CTX*); +WOLFSSL_API int wolfSSL_CTX_get_max_proto_version(WOLFSSL_CTX*); WOLFSSL_API int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey);