diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 6fe45a084..4c207fda6 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -14854,3 +14854,73 @@ available size need to be provided in bufferSz. */ int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer, unsigned int bufferSz); + +/*! + \ingroup TLS + + \brief This function returns the raw list of ciphersuites and signature + algorithms offered by the client. The lists are only stored and returned + inside a callback setup with wolfSSL_CTX_set_cert_cb(). This is useful to + be able to dynamically load certificates and keys based on the available + ciphersuites and signature algorithms. + + \param [in] ssl The WOLFSSL object to extract the lists from. + \param [out] suites Raw and unfiltered list of client ciphersuites + \param [out] suiteSz Size of suites in bytes + \param [out] hashSigAlgo Raw and unfiltered list of client signature algorithms + \param [out] hashSigAlgoSz Size of hashSigAlgo in bytes + + _Example_ + \code + int certCB(WOLFSSL* ssl, void* arg) + { + const byte* suites = NULL; + word16 suiteSz = 0; + const byte* hashSigAlgo = NULL; + word16 hashSigAlgoSz = 0; + + wolfSSL_get_client_suites_sigalgs(ssl, &suites, &suiteSz, &hashSigAlgo, + &hashSigAlgoSz); + + // Choose certificate to load based on ciphersuites + } + + WOLFSSL* ctx; + ctx = wolfSSL_CTX_new(wolfTLSv1_3_method_ex(NULL)); + wolfSSL_CTX_set_cert_cb(ctx, certCB, NULL); + \endcode + + \sa wolfSSL_new + \sa wolfSSL_free +*/ +void wolfSSL_get_client_suites_sigalgs(const WOLFSSL* ssl, + const byte** suites, word16* suiteSz, + const byte** hashSigAlgo, word16* hashSigAlgoSz); + +/*! + \ingroup TLS + + \brief This returns information about the ciphersuite directly from the + raw ciphersuite bytes. + + \param [in] first First byte of the ciphersuite + \param [in] second Second byte of the ciphersuite + + \return WOLFSSL_CIPHERSUITE_INFO A struct containing information about the + type of authentication used in the ciphersuite. + + _Example_ + \code + WOLFSSL_CIPHERSUITE_INFO info = + wolfSSL_get_ciphersuite_info(suites[0], suites[1]); + if (info.rsaAuth) + haveRSA = 1; + else if (info.eccAuth) + haveECC = 1; + \endcode + + \sa wolfSSL_new + \sa wolfSSL_free +*/ +WOLFSSL_CIPHERSUITE_INFO wolfSSL_get_ciphersuite_info(byte first, + byte second); diff --git a/src/internal.c b/src/internal.c index fadeb10a3..8db5e7b8b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -11222,23 +11222,11 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) #endif /* WOLFSSL_NO_TLS12 */ #if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT) -/* cipher requirements */ -enum { - REQUIRES_RSA, - REQUIRES_DHE, - REQUIRES_ECC, - REQUIRES_ECC_STATIC, - REQUIRES_PSK, - REQUIRES_RSA_SIG, - REQUIRES_AEAD -}; - - /* Does this cipher suite (first, second) have the requirement an ephemeral key exchange will still require the key for signing the key exchange so ECDHE_RSA requires an rsa key thus rsa_kea */ -static int CipherRequires(byte first, byte second, int requirement) +int CipherRequires(byte first, byte second, int requirement) { (void)requirement; diff --git a/src/ssl.c b/src/ssl.c index cd1104fa0..22782e9f4 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -16322,6 +16322,21 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } } } + WOLFSSL_CIPHERSUITE_INFO wolfSSL_get_ciphersuite_info(byte first, + byte second) + { + WOLFSSL_CIPHERSUITE_INFO info; + info.rsaAuth = (byte)(CipherRequires(first, second, REQUIRES_RSA) || + CipherRequires(first, second, REQUIRES_RSA_SIG)); + info.eccAuth = (byte)(CipherRequires(first, second, REQUIRES_ECC) || + /* Static ECC ciphers may require RSA for authentication */ + (CipherRequires(first, second, REQUIRES_ECC_STATIC) && + !CipherRequires(first, second, REQUIRES_RSA_SIG))); + info.eccStatic = + (byte)CipherRequires(first, second, REQUIRES_ECC_STATIC); + info.psk = (byte)CipherRequires(first, second, REQUIRES_PSK); + return info; + } /** * Internal wrapper for calling certSetupCb diff --git a/tests/api.c b/tests/api.c index e89c2fb04..18781eb94 100644 --- a/tests/api.c +++ b/tests/api.c @@ -370,7 +370,7 @@ defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)) || \ defined(WOLFSSL_TEST_STATIC_BUILD) || defined(WOLFSSL_DTLS) || \ defined(HAVE_ECH) || defined(HAVE_EX_DATA) || !defined(NO_SESSION_CACHE) \ - || !defined(WOLFSSL_NO_TLS12) + || !defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13) /* for testing SSL_get_peer_cert_chain, or SESSION_TICKET_HINT_DEFAULT, * for setting authKeyIdSrc in WOLFSSL_X509, or testing DTLS sequence * number tracking */ @@ -44849,20 +44849,14 @@ static int test_wolfSSL_cert_cb_dyn_ciphers_certCB(WOLFSSL* ssl, void* arg) hashSigAlgoSz == 0) return 0; - if (wolfSSL_GetVersion(ssl) != TLSv1_3_MINOR) { - for (idx = 0; idx < suiteSz; idx += 2) { - const char* cipherName = wolfSSL_get_cipher_name_from_suite( - suites[idx], suites[idx+1]); - if (cipherName == NULL) - return 0; - /* TLS 1.3 suites tell us nothing about the sigalg */ - if (XSTRSTR(cipherName, "TLS13-") != NULL) - continue; - if (XSTRSTR(cipherName, "-RSA-") != NULL) - haveRSA = 1; - if (XSTRSTR(cipherName, "-ECDSA-") != NULL) - haveECC = 1; - } + for (idx = 0; idx < suiteSz; idx += 2) { + WOLFSSL_CIPHERSUITE_INFO info = + wolfSSL_get_ciphersuite_info(suites[idx], suites[idx+1]); + + if (info.rsaAuth) + haveRSA = 1; + else if (info.eccAuth) + haveECC = 1; } if (hashSigAlgoSz > 0) { @@ -44998,6 +44992,96 @@ static int test_wolfSSL_cert_cb_dyn_ciphers(void) return EXPECT_RESULT(); } +static int test_wolfSSL_ciphersuite_auth(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) + WOLFSSL_CIPHERSUITE_INFO info; + + (void)info; + +#ifndef WOLFSSL_NO_TLS12 +#ifdef HAVE_CHACHA + info = wolfSSL_get_ciphersuite_info(CHACHA_BYTE, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); + ExpectIntEQ(info.rsaAuth, 1); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 0); + + info = wolfSSL_get_ciphersuite_info(CHACHA_BYTE, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); + ExpectIntEQ(info.rsaAuth, 0); + ExpectIntEQ(info.eccAuth, 1); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 0); + + info = wolfSSL_get_ciphersuite_info(CHACHA_BYTE, + TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256); + ExpectIntEQ(info.rsaAuth, 0); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 1); +#endif +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) +#ifndef NO_RSA + info = wolfSSL_get_ciphersuite_info(ECC_BYTE, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); + ExpectIntEQ(info.rsaAuth, 1); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 0); + + info = wolfSSL_get_ciphersuite_info(ECC_BYTE, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA); + ExpectIntEQ(info.rsaAuth, 1); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 1); + ExpectIntEQ(info.psk, 0); + + info = wolfSSL_get_ciphersuite_info(ECC_BYTE, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA); + ExpectIntEQ(info.rsaAuth, 1); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 1); + ExpectIntEQ(info.psk, 0); +#endif + info = wolfSSL_get_ciphersuite_info(ECC_BYTE, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA); + ExpectIntEQ(info.rsaAuth, 0); + ExpectIntEQ(info.eccAuth, 1); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 0); + + info = wolfSSL_get_ciphersuite_info(ECC_BYTE, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA); + ExpectIntEQ(info.rsaAuth, 0); + ExpectIntEQ(info.eccAuth, 1); + ExpectIntEQ(info.eccStatic, 1); + ExpectIntEQ(info.psk, 0); + + info = wolfSSL_get_ciphersuite_info(ECDHE_PSK_BYTE, + TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256); + ExpectIntEQ(info.rsaAuth, 0); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 1); +#endif +#endif + +#ifdef WOLFSSL_TLS13 + info = wolfSSL_get_ciphersuite_info(TLS13_BYTE, + TLS_AES_128_GCM_SHA256); + ExpectIntEQ(info.rsaAuth, 0); + ExpectIntEQ(info.eccAuth, 0); + ExpectIntEQ(info.eccStatic, 0); + ExpectIntEQ(info.psk, 0); +#endif + +#endif + return EXPECT_RESULT(); +} + static int test_wolfSSL_SESSION(void) { EXPECT_DECLS; @@ -69183,6 +69267,7 @@ TEST_CASE testCases[] = { #endif TEST_DECL(test_wolfSSL_cert_cb), TEST_DECL(test_wolfSSL_cert_cb_dyn_ciphers), + TEST_DECL(test_wolfSSL_ciphersuite_auth), /* Can't memory test as tcp_connect aborts. */ TEST_DECL(test_wolfSSL_SESSION), TEST_DECL(test_wolfSSL_SESSION_expire_downgrade), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 2f9b912cb..071261cb7 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -6014,6 +6014,16 @@ enum ProvisionSide { PROVISION_CLIENT_SERVER = 3 }; +/* cipher requirements */ +enum { + REQUIRES_RSA, + REQUIRES_DHE, + REQUIRES_ECC, + REQUIRES_ECC_STATIC, + REQUIRES_PSK, + REQUIRES_RSA_SIG, + REQUIRES_AEAD +}; static const byte kTlsClientStr[SIZEOF_SENDER+1] = { 0x43, 0x4C, 0x4E, 0x54, 0x00 }; /* CLNT */ static const byte kTlsServerStr[SIZEOF_SENDER+1] = { 0x53, 0x52, 0x56, 0x52, 0x00 }; /* SRVR */ @@ -6105,6 +6115,7 @@ WOLFSSL_LOCAL void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree); WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl); WOLFSSL_LOCAL byte* GetOutputBuffer(WOLFSSL* ssl); +WOLFSSL_LOCAL int CipherRequires(byte first, byte second, int requirement); WOLFSSL_LOCAL int VerifyClientSuite(word16 havePSK, byte cipherSuite0, byte cipherSuite); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 2b18d2b30..5bc473063 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2124,6 +2124,14 @@ WOLFSSL_API void wolfSSL_CTX_set_cert_cb(WOLFSSL_CTX* ctx, WOLFSSL_API void wolfSSL_get_client_suites_sigalgs(const WOLFSSL* ssl, const byte** suites, word16* suiteSz, const byte** hashSigAlgo, word16* hashSigAlgoSz); +typedef struct WOLFSSL_CIPHERSUITE_INFO { + byte rsaAuth:1; + byte eccAuth:1; + byte eccStatic:1; + byte psk:1; +} WOLFSSL_CIPHERSUITE_INFO; +WOLFSSL_API WOLFSSL_CIPHERSUITE_INFO wolfSSL_get_ciphersuite_info(byte first, + byte second); WOLFSSL_LOCAL int CertSetupCbWrapper(WOLFSSL* ssl); WOLFSSL_API void* wolfSSL_X509_STORE_CTX_get_ex_data(