From 7e0c372e4c1f237d73f8abf89bc22e21657d940d Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 1 Mar 2021 16:39:17 +1000 Subject: [PATCH] TLS 1.3 PSK: use the hash algorithm to choose cipher suite See RFC 8446: 4.2.11 With TLS 1.3 PSK callback, If the returned cipher suite isn't available, use the hash from the cipher suite and choose from available list. Require exact match when: WOLFSSL_TLS13_PSK_NO_MATCH_HASH Alternative callback for client added that is passed a cipher suite string. Called for each cipher suite that is to be negotiated. If cipher suite to be used with PSK then return client identity. Returning an identity based on cipher suite hash will result in only one PSK extension being added per hash. --- examples/client/client.c | 8 +- examples/server/server.c | 2 +- src/internal.c | 6 +- src/tls.c | 49 ++- src/tls13.c | 843 +++++++++++++++++++++++++++----------- tests/test-tls13-psk.conf | 54 ++- wolfssl/internal.h | 14 +- wolfssl/ssl.h | 32 +- wolfssl/test.h | 31 +- 9 files changed, 780 insertions(+), 259 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 87c7fa32a..db2c29661 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -2530,9 +2530,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) const char *defaultCipherList = cipherList; wolfSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb); - #ifdef WOLFSSL_TLS13 +#ifdef WOLFSSL_TLS13 + #if !defined(WOLFSSL_PSK_TLS13_CB) && !defined(WOLFSSL_PSK_ONE_ID) + wolfSSL_CTX_set_psk_client_cs_callback(ctx, my_psk_client_cs_cb); + #else wolfSSL_CTX_set_psk_client_tls13_callback(ctx, my_psk_client_tls13_cb); #endif +#endif if (defaultCipherList == NULL) { #if defined(HAVE_AESGCM) && !defined(NO_DH) #ifdef WOLFSSL_TLS13 @@ -3268,7 +3272,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) * cipher name, or the requested cipher name is marked as an alias * that matches the established cipher. */ - if (cipherList && (! XSTRSTR(cipherList, ":"))) { + if (cipherList && !useDefCipherList && (! XSTRSTR(cipherList, ":"))) { WOLFSSL_CIPHER* established_cipher = wolfSSL_get_current_cipher(ssl); byte requested_cipherSuite0, requested_cipherSuite; int requested_cipherFlags; diff --git a/examples/server/server.c b/examples/server/server.c index 410f72a14..e99b76277 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -2879,7 +2879,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) * cipher name, or the requested cipher name is marked as an alias * that matches the established cipher. */ - if (cipherList && (! XSTRSTR(cipherList, ":"))) { + if (cipherList && !useDefCipherList && (! XSTRSTR(cipherList, ":"))) { WOLFSSL_CIPHER* established_cipher = wolfSSL_get_current_cipher(ssl); byte requested_cipherSuite0, requested_cipherSuite; int requested_cipherFlags; diff --git a/src/internal.c b/src/internal.c index a4f08625f..8df8a3793 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5479,6 +5479,7 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->options.server_psk_cb = ctx->server_psk_cb; ssl->options.psk_ctx = ctx->psk_ctx; #ifdef WOLFSSL_TLS13 + ssl->options.client_psk_cs_cb = ctx->client_psk_cs_cb; ssl->options.client_psk_tls13_cb = ctx->client_psk_tls13_cb; ssl->options.server_psk_tls13_cb = ctx->server_psk_tls13_cb; #endif @@ -27625,10 +27626,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, defined(OPENSSL_ALL) /* search suites for specific one, idx on success, negative on error */ -#ifndef WOLFSSL_TLS13 - static -#endif - int FindSuite(Suites* suites, byte first, byte second) + static int FindSuite(Suites* suites, byte first, byte second) { int i; diff --git a/src/tls.c b/src/tls.c index 7e3deec15..b0b25bdcc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -10397,7 +10397,49 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) usingPSK = 1; } #endif - #ifndef NO_PSK + #ifndef NO_PSK + #ifndef WOLFSSL_PSK_ONE_ID + if (ssl->options.client_psk_cs_cb != NULL) { + int i; + ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + byte cipherSuite0 = ssl->suites->suites[i + 0]; + byte cipherSuite = ssl->suites->suites[i + 1]; + unsigned int keySz; + + #ifdef HAVE_NULL_CIPHER + if (cipherSuite0 == ECC_BYTE) { + if (cipherSuite != TLS_SHA256_SHA256 && + cipherSuite != TLS_SHA384_SHA384) { + continue; + } + } + else + #endif + if (cipherSuite0 != TLS13_BYTE) + continue; + + keySz = ssl->options.client_psk_cs_cb( + ssl, ssl->arrays->server_hint, + ssl->arrays->client_identity, MAX_PSK_ID_LEN, + ssl->arrays->psk_key, MAX_PSK_KEY_LEN, + GetCipherNameInternal(cipherSuite0, cipherSuite)); + if (keySz > 0) { + ssl->arrays->psk_keySz = keySz; + ret = TLSX_PreSharedKey_Use(ssl, + (byte*)ssl->arrays->client_identity, + (word16)XSTRLEN(ssl->arrays->client_identity), 0, + SuiteMac(ssl->suites->suites + i), + cipherSuite0, cipherSuite, 0, NULL); + if (ret != 0) + return ret; + } + } + + usingPSK = 1; + } + else + #endif if (ssl->options.client_psk_cb != NULL || ssl->options.client_psk_tls13_cb != NULL) { /* Default ciphersuite. */ @@ -10412,7 +10454,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) ssl->arrays->client_identity, MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName); if (GetCipherSuiteFromName(cipherName, &cipherSuite0, - &cipherSuite, &cipherSuiteFlags) != 0) { + &cipherSuite, &cipherSuiteFlags) != 0) { return PSK_KEY_ERROR; } } @@ -10426,6 +10468,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return PSK_KEY_ERROR; } ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; + ssl->options.cipherSuite0 = cipherSuite0; ssl->options.cipherSuite = cipherSuite; (void)cipherSuiteFlags; @@ -10444,7 +10487,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) usingPSK = 1; } - #endif + #endif /* !NO_PSK */ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (usingPSK) { byte modes; diff --git a/src/tls13.c b/src/tls13.c index 86ea1335e..4379ebdfe 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -65,6 +65,10 @@ * Allow a NewSessionTicket message to be sent by server before Client's * Finished message. * See TLS v1.3 specification, Section 4.6.1, Paragraph 4 (Note). + * WOLFSSL_PSK_ONE_ID + * When only one PSK ID is used and only one call to the PSK callback can + * be made per connect. + * You cannot use wc_psk_client_cs_callback type callback on client. */ #ifdef HAVE_CONFIG_H @@ -1088,6 +1092,13 @@ static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash, if (ret != 0) return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" Key"); + WOLFSSL_BUFFER(key, ssl->specs.hash_size); + WOLFSSL_MSG(" Msg Hash"); + WOLFSSL_BUFFER(hash, hashSz); +#endif + /* Calculate the verify data. */ ret = wc_HmacInit(&verifyHmac, ssl->heap, ssl->devId); if (ret == 0) { @@ -1099,6 +1110,11 @@ static int BuildTls13HandshakeHmac(WOLFSSL* ssl, byte* key, byte* hash, wc_HmacFree(&verifyHmac); } +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" Hash"); + WOLFSSL_BUFFER(hash, hashSz); +#endif + if (pHashSz) *pHashSz = hashSz; @@ -1533,7 +1549,7 @@ end: /* user must supply time in milliseconds function: * word32 TimeNowInMilliseconds(void); * The response is milliseconds elapsed - */ + */ #endif /* !NO_ASN_TIME */ #endif /* HAVE_SESSION_TICKET || !NO_PSK */ @@ -2466,7 +2482,8 @@ exit_buildmsg: return ret; } -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) || \ + !defined(NO_WOLFSSL_CLIENT) /* Find the cipher suite in the suites set in the SSL. * * ssl SSL/TLS object. @@ -2488,6 +2505,70 @@ static int FindSuiteSSL(WOLFSSL* ssl, byte* suite) } #endif +#ifndef NO_PSK +/* Get the MAC algorithm for the TLS 1.3 cipher suite. + * + * @param [in] suite. + * @return A value from wc_MACAlgorithm enumeration. + */ +byte SuiteMac(byte* suite) +{ + byte mac = no_mac; + + if (suite[0] == TLS13_BYTE) { + switch (suite[1]) { + #ifdef BUILD_TLS_AES_128_GCM_SHA256 + case TLS_AES_128_GCM_SHA256: + mac = sha256_mac; + break; + #endif + #ifdef BUILD_TLS_CHACHA20_POLY1305_SHA256 + case TLS_CHACHA20_POLY1305_SHA256: + mac = sha256_mac; + break; + #endif + #ifdef BUILD_TLS_AES_128_CCM_SHA256 + case TLS_AES_128_CCM_SHA256: + mac = sha256_mac; + break; + #endif + #ifdef BUILD_TLS_AES_128_CCM_8_SHA256 + case TLS_AES_128_CCM_8_SHA256: + mac = sha256_mac; + break; + #endif + #ifdef BUILD_TLS_AES_256_GCM_SHA384 + case TLS_AES_256_GCM_SHA384: + mac = sha384_mac; + break; + #endif + default: + break; + } + } +#ifdef HAVE_NULL_CIPHER + else if (suite[0] == ECC_BYTE) { + switch (suite[1]) { + #ifdef BUILD_TLS_SHA256_SHA256 + case TLS_SHA256_SHA256: + mac = sha256_mac; + break; + #endif + #ifdef BUILD_TLS_SHA384_SHA384 + case TLS_SHA384_SHA384: + mac = sha384_mac; + break; + #endif + default: + break; + } + } +#endif + + return mac; +} +#endif + #if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER) /* Create Cookie extension using the hash of the first ClientHello. * @@ -2662,31 +2743,39 @@ static const WOLFSSL_EVP_MD* ssl_handshake_md(const byte mac_alg) #endif /* Setup pre-shared key based on the details in the extension data. * - * ssl SSL/TLS object. - * psk Pre-shared key extension data. + * ssl SSL/TLS object. + * psk Pre-shared key extension data. + * clientHello Whether called from client_hello construction. * returns 0 on success, PSK_KEY_ERROR when the client PSK callback fails and * other negative value on failure. */ -static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) +static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk, int clientHello) { +#if defined(HAVE_SESSION_TICKET) || !defined(WOLFSSL_PSK_ONE_ID) int ret; +#endif byte suite[2]; if (psk == NULL) return BAD_FUNC_ARG; - suite[0] = psk->cipherSuite0; - suite[1] = psk->cipherSuite; - if (!FindSuiteSSL(ssl, suite)) - return PSK_KEY_ERROR; - - ssl->options.cipherSuite0 = psk->cipherSuite0; - ssl->options.cipherSuite = psk->cipherSuite; - if ((ret = SetCipherSpecs(ssl)) != 0) - return ret; + suite[0] = ssl->options.cipherSuite0; + suite[1] = ssl->options.cipherSuite; #ifdef HAVE_SESSION_TICKET if (psk->resumption) { + if (clientHello) { + /* Ensure cipher suite is supported or changed suite to one with + * the same MAC algorithm. */ + if (!FindSuiteSSL(ssl, suite)) + return PSK_KEY_ERROR; + + /* Setting mac for binder and keys for deriving EarlyData. */ + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + } + #ifdef WOLFSSL_EARLY_DATA if (ssl->session.maxEarlyDataSz == 0) ssl->earlyData = no_early_data; @@ -2701,80 +2790,124 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk) #endif #ifndef NO_PSK if (!psk->resumption) { - #ifndef WOLFSSL_PSK_ONE_ID + /* Get the pre-shared key. */ +#ifndef WOLFSSL_PSK_ONE_ID const char* cipherName = NULL; - byte cipherSuite0 = TLS13_BYTE, cipherSuite = WOLFSSL_DEF_PSK_CIPHER; - int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE; - #ifdef OPENSSL_EXTRA - const unsigned char* id = NULL; - size_t idlen = 0; WOLFSSL_SESSION* psksession = NULL; - const WOLFSSL_EVP_MD* handshake_md = NULL; + #endif + /* Set the client identity to use. */ + XMEMSET(ssl->arrays->client_identity, 0, + sizeof(ssl->arrays->client_identity)); + XMEMCPY(ssl->arrays->client_identity, psk->identity, psk->identityLen); + + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("PSK cipher suite:"); + WOLFSSL_MSG(GetCipherNameInternal(psk->cipherSuite0, psk->cipherSuite)); + #endif + + /* Get the pre-shared key. */ + #ifdef OPENSSL_EXTRA if (ssl->options.session_psk_cb != NULL) { + const unsigned char* id = NULL; + size_t idlen = 0; + const WOLFSSL_EVP_MD* handshake_md = NULL; if (ssl->msgsReceived.got_hello_retry_request >= 1) { handshake_md = ssl_handshake_md(ssl->specs.mac_algorithm); } - /* Get the pre-shared key. */ - if (!ssl->options.session_psk_cb(ssl, handshake_md, - &id, &idlen, &psksession)) { + /* OpenSSL compatible callback that gets cached session. */ + if (ssl->options.session_psk_cb(ssl, handshake_md, &id, &idlen, + &psksession) == 0) { wolfSSL_SESSION_free(psksession); WOLFSSL_MSG("psk session callback failed"); return PSK_KEY_ERROR; } - } + if (psksession != NULL) { + if (idlen > MAX_PSK_KEY_LEN) { + wolfSSL_SESSION_free(psksession); + WOLFSSL_MSG("psk key length is too long"); + return PSK_KEY_ERROR; + } + + ssl->arrays->psk_keySz = (word32)idlen; + XMEMCPY(ssl->arrays->psk_key, id, idlen); + suite[0] = psksession->cipherSuite0; + suite[1] = psksession->cipherSuite; + /* Not needed anymore. */ + wolfSSL_SESSION_free(psksession); + /* Leave pointer not NULL to indicate success with callback. */ + } + } + if (psksession != NULL) { + /* Don't try other callbacks - we have an answer. */ + } + else + #endif /* OPENSSL_EXTRA */ + if (ssl->options.client_psk_cs_cb != NULL) { + /* Lookup key again for next identity. */ + ssl->arrays->psk_keySz = ssl->options.client_psk_cs_cb( + ssl, ssl->arrays->server_hint, + ssl->arrays->client_identity, MAX_PSK_ID_LEN, + ssl->arrays->psk_key, MAX_PSK_KEY_LEN, + GetCipherNameInternal(psk->cipherSuite0, psk->cipherSuite)); + if (clientHello) { + /* Use PSK cipher suite. */ + ssl->options.cipherSuite0 = psk->cipherSuite0; + ssl->options.cipherSuite = psk->cipherSuite; + } + else { + byte pskCS[2] = { psk->cipherSuite0, psk->cipherSuite }; + /* Ensure PSK and negotiated cipher suites have same hash. */ + if (SuiteMac(pskCS) != SuiteMac(suite)) { + return PSK_KEY_ERROR; + } + /* Negotiated cipher suite is to be used - update PSK. */ + psk->cipherSuite0 = suite[0]; + psk->cipherSuite = suite[1]; + } + } + else if (ssl->options.client_psk_tls13_cb != NULL) { + byte cipherSuite0; + byte cipherSuite; + int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE; - if (psksession == NULL && - #else - /* Get the pre-shared key. */ - if ( - #endif - ssl->options.client_psk_tls13_cb != NULL) { ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb(ssl, - (char *)psk->identity, ssl->arrays->client_identity, + ssl->arrays->server_hint, ssl->arrays->client_identity, MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName); if (GetCipherSuiteFromName(cipherName, &cipherSuite0, &cipherSuite, &cipherSuiteFlags) != 0) { return PSK_KEY_ERROR; } + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; + (void)cipherSuiteFlags; } else { - #ifdef OPENSSL_EXTRA - if (psksession != NULL) { - if (idlen > MAX_PSK_KEY_LEN) { - WOLFSSL_MSG("psk key length is too long"); - return PSK_KEY_ERROR; - } - - ssl->arrays->psk_keySz = (word32)idlen; - XMEMCPY(ssl->arrays->psk_key, id, idlen); - cipherSuite0 = psksession->cipherSuite0; - cipherSuite = psksession->cipherSuite; - /* no need anymore */ - wolfSSL_SESSION_free(psksession); - } - else - #endif ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, - (char *)psk->identity, ssl->arrays->client_identity, + ssl->arrays->server_hint, ssl->arrays->client_identity, MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + ssl->options.cipherSuite0 = TLS13_BYTE; + ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; } if (ssl->arrays->psk_keySz == 0 || ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { return PSK_KEY_ERROR; } - if (psk->cipherSuite0 != cipherSuite0 || - psk->cipherSuite != cipherSuite) { + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; +#else + /* PSK information loaded during setting of default TLS extensions. */ +#endif /* !WOLFSSL_PSK_ONE_ID */ + + if (!clientHello && (psk->cipherSuite0 != suite[0] || + psk->cipherSuite != suite[1])) { return PSK_KEY_ERROR; } - (void)cipherSuiteFlags; - #else - /* PSK information loaded during setting of default TLS extensions. */ - #endif } #endif @@ -2824,7 +2957,7 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) /* Calculate the binder for each identity based on previous handshake data. */ while (current != NULL) { - if ((ret = SetupPskKey(ssl, current)) != 0) + if ((ret = SetupPskKey(ssl, current, 1)) != 0) return ret; #ifdef HAVE_SESSION_TICKET @@ -2866,7 +2999,7 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) #ifdef WOLFSSL_EARLY_DATA if (ssl->earlyData != no_early_data) { - if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data)) != 0) + if ((ret = SetupPskKey(ssl, (PreSharedKey*)ext->data, 1)) != 0) return ret; /* Derive early data encryption key. */ @@ -3019,6 +3152,16 @@ int SendTls13ClientHello(WOLFSSL* ssl) idx += OPAQUE16_LEN; XMEMCPY(output + idx, &ssl->suites->suites, ssl->suites->suiteSz); idx += ssl->suites->suiteSz; +#ifdef WOLFSSL_DEBUG_TLS + { + int ii; + WOLFSSL_MSG("Ciphers:"); + for (ii = 0 ; ii < ssl->suites->suiteSz; ii += 2) { + WOLFSSL_MSG(GetCipherNameInternal(ssl->suites->suites[ii+0], + ssl->suites->suites[ii+1])); + } + } +#endif /* Compression not supported in TLS v1.3. */ output[idx++] = COMP_LEN; @@ -3090,6 +3233,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, byte b; int foundVersion; word16 totalExtSz; + byte suite[2]; #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX* ext; PreSharedKey* psk = NULL; @@ -3167,6 +3311,11 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Set the cipher suite from the message. */ ssl->options.cipherSuite0 = input[i++]; ssl->options.cipherSuite = input[i++]; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Chosen cipher suite:"); + WOLFSSL_MSG(GetCipherNameInternal(ssl->options.cipherSuite0, + ssl->options.cipherSuite)); +#endif /* Compression */ b = input[i++]; @@ -3302,6 +3451,13 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return INVALID_PARAMETER; } + suite[0] = ssl->options.cipherSuite0; + suite[1] = ssl->options.cipherSuite; + if (!FindSuiteSSL(ssl, suite)) { + WOLFSSL_MSG("Cipher suite not supported on client"); + return PSK_KEY_ERROR; + } + if (*extMsgType == server_hello) { #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); @@ -3314,7 +3470,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->arrays->psk_keySz = 0; XMEMSET(ssl->arrays->psk_key, 0, MAX_PSK_KEY_LEN); } - else if ((ret = SetupPskKey(ssl, psk)) != 0) + else if ((ret = SetupPskKey(ssl, psk, 0)) != 0) return ret; #endif @@ -3545,77 +3701,124 @@ static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites) ssl->suites->suiteSz = suiteSz; XMEMCPY(ssl->suites->suites, &suites, sizeof(suites)); +#ifdef WOLFSSL_DEBUG_TLS + { + int ii; + WOLFSSL_MSG("Refined Ciphers:"); + for (ii = 0 ; ii < ssl->suites->suiteSz; ii += 2) { + WOLFSSL_MSG(GetCipherNameInternal(ssl->suites->suites[ii+0], + ssl->suites->suites[ii+1])); + } + } +#endif } -/* Handle any Pre-Shared Key (PSK) extension. - * Must do this in ClientHello as it requires a hash of the truncated message. - * Don't know size of binders until Pre-Shared Key extension has been parsed. +#ifndef NO_PSK +/* Attempt to find the PSK (not session ticket) that matches. * - * ssl The SSL/TLS object. - * input The ClientHello message. - * helloSz The size of the ClientHello message (including binders if present). - * usingPSK Indicates handshake is using Pre-Shared Keys. + * @param [in, out] ssl The SSL/TLS object. + * @param [in] psk A pre-shared key from the extension. + * @param [out] suite Cipher suite to use with PSK. + * @param [out] err Error code. + * PSK_KEY_ERROR when key is too big or ticket age is + * invalid, + * UNSUPPORTED_SUITE on invalid suite. + * Other error when attempting to derive early secret. + * @return 1 when a match found - but check error code. + * @return 0 when no match found. + */ +static int FindPsk(WOLFSSL* ssl, PreSharedKey* psk, byte* suite, int* err) +{ + int ret = 0; + int found = 0; + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE; + byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + Arrays* sa = ssl->arrays; + + if (ssl->options.server_psk_tls13_cb != NULL) { + sa->psk_keySz = ssl->options.server_psk_tls13_cb(ssl, + sa->client_identity, sa->psk_key, MAX_PSK_KEY_LEN, &cipherName); + if (sa->psk_keySz != 0) { + int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE; + found = (GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite, &cipherSuiteFlags) == 0); + (void)cipherSuiteFlags; + } + } + if (!found && (ssl->options.server_psk_cb != NULL)) { + sa->psk_keySz = ssl->options.server_psk_cb(ssl, + sa->client_identity, sa->psk_key, + MAX_PSK_KEY_LEN); + found = (sa->psk_keySz != 0); + } + if (found) { + if (sa->psk_keySz > MAX_PSK_KEY_LEN) { + ret = PSK_KEY_ERROR; + } + if (ret == 0) { + #ifndef WOLFSSL_PSK_ONE_ID + /* Check whether PSK ciphersuite is in SSL. */ + found = (suite[0] == cipherSuite0) && (suite[1] == cipherSuite); + #else + /* Check whether PSK ciphersuite is in SSL. */ + suite[0] = cipherSuite0; + suite[1] = cipherSuite; + found = FindSuiteSSL(ssl, suite); + #endif + } + if ((ret == 0) && found) { + /* Default to ciphersuite if cb doesn't specify. */ + ssl->options.resuming = 0; + /* Don't send certificate request when using PSK. */ + ssl->options.verifyPeer = 0; + + /* PSK age is always zero. */ + if (psk->ticketAge != ssl->session.ticketAdd) { + ret = PSK_KEY_ERROR; + } + } + if ((ret == 0) && found) { + /* Set PSK ciphersuite into SSL. */ + ssl->options.cipherSuite0 = suite[0]; + ssl->options.cipherSuite = suite[1]; + ret = SetCipherSpecs(ssl); + } + if ((ret == 0) && found) { + /* Derive the early secret using the PSK. */ + ret = DeriveEarlySecret(ssl); + } + } + + *err = ret; + return found; +} +#endif + +/* Handle any Pre-Shared Key (PSK) extension. + * Find a PSK that supports the cipher suite passed in. + * + * ssl SSL/TLS object. + * suite Cipher suite to find PSK for. + * usingPSK Indicates handshake is using Pre-Shared Keys. * returns 0 on success and otherwise failure. */ -static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, - int* usingPSK) +static int DoPreSharedKeys(WOLFSSL* ssl, byte* suite, int* usingPSK, int* first) { int ret; TLSX* ext; - word16 bindersLen; PreSharedKey* current; byte binderKey[WC_MAX_DIGEST_SIZE]; byte binder[WC_MAX_DIGEST_SIZE]; word32 binderLen; - word16 modes; - byte suite[2]; -#ifdef WOLFSSL_EARLY_DATA - int pskCnt = 0; - TLSX* extEarlyData; -#endif -#ifndef NO_PSK - const char* cipherName = NULL; - byte cipherSuite0 = TLS13_BYTE; - byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; - int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE; -#endif WOLFSSL_ENTER("DoPreSharedKeys"); ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); - if (ext == NULL) { - /* Hash data up to binders for deriving binders in PSK extension. */ - ret = HashInput(ssl, input, helloSz); - return ret; - } - - /* Extensions pushed on stack/list and PSK must be last. */ - if (ssl->extensions != ext) - return PSK_KEY_ERROR; - - /* Assume we are going to resume with a pre-shared key. */ - ssl->options.resuming = 1; - - /* Find the pre-shared key extension and calculate hash of truncated - * ClientHello for binders. - */ - ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, - client_hello, &bindersLen); - if (ret < 0) - return ret; - - /* Hash data up to binders for deriving binders in PSK extension. */ - ret = HashInput(ssl, input, helloSz - bindersLen); - if (ret != 0) - return ret; /* Look through all client's pre-shared keys for a match. */ current = (PreSharedKey*)ext->data; while (current != NULL) { - #ifdef WOLFSSL_EARLY_DATA - pskCnt++; - #endif - #ifndef NO_PSK if (current->identityLen > MAX_PSK_ID_LEN) { return BUFFER_ERROR; @@ -3647,19 +3850,25 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, diff - MAX_TICKET_AGE_SECS * 1000 > 1000) { /* Invalid difference, fallback to full handshake. */ ssl->options.resuming = 0; - /* Hash the rest of the ClientHello. */ - return HashRaw(ssl, input + helloSz - bindersLen, bindersLen); } + #ifndef WOLFSSL_PSK_ONE_ID /* Check whether resumption is possible based on suites in SSL and * ciphersuite in ticket. */ + if ((suite[0] != ssl->session.cipherSuite0) || + (suite[1] != ssl->session.cipherSuite)) { + current = current->next; + continue; + } + #else suite[0] = ssl->session.cipherSuite0; suite[1] = ssl->session.cipherSuite; if (!FindSuiteSSL(ssl, suite)) { current = current->next; continue; } + #endif #ifdef WOLFSSL_EARLY_DATA ssl->options.maxEarlyDataSz = ssl->session.maxEarlyDataSz; @@ -3682,7 +3891,7 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, ret = DeriveEarlySecret(ssl); if (ret != 0) return ret; - /* Derive the binder key to use to with HMAC. */ + /* Derive the binder key to use with HMAC. */ ret = DeriveBinderKeyResume(ssl, binderKey); if (ret != 0) return ret; @@ -3690,49 +3899,11 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, else #endif #ifndef NO_PSK - if ((ssl->options.server_psk_tls13_cb != NULL && - (ssl->arrays->psk_keySz = ssl->options.server_psk_tls13_cb(ssl, - ssl->arrays->client_identity, ssl->arrays->psk_key, - MAX_PSK_KEY_LEN, &cipherName)) != 0 && - GetCipherSuiteFromName(cipherName, &cipherSuite0, - &cipherSuite, &cipherSuiteFlags) == 0) || - (ssl->options.server_psk_cb != NULL && - (ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, - ssl->arrays->client_identity, ssl->arrays->psk_key, - MAX_PSK_KEY_LEN)) != 0)) { - if (ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) - return PSK_KEY_ERROR; - - /* Check whether PSK ciphersuite is in SSL. */ - suite[0] = cipherSuite0; - suite[1] = cipherSuite; - (void)cipherSuiteFlags; - if (!FindSuiteSSL(ssl, suite)) { - current = current->next; - continue; - } - - /* Default to ciphersuite if cb doesn't specify. */ - ssl->options.resuming = 0; - /* Don't send certificate request when using PSK. */ - ssl->options.verifyPeer = 0; - - /* PSK age is always zero. */ - if (current->ticketAge != ssl->session.ticketAdd) - return PSK_KEY_ERROR; - - /* Set PSK ciphersuite into SSL. */ - ssl->options.cipherSuite0 = cipherSuite0; - ssl->options.cipherSuite = cipherSuite; - ret = SetCipherSpecs(ssl); + if (FindPsk(ssl, current, suite, &ret)) { if (ret != 0) return ret; - /* Derive the early secret using the PSK. */ - ret = DeriveEarlySecret(ssl); - if (ret != 0) - return ret; - /* Derive the binder key to use to with HMAC. */ + /* Derive the binder key to use with HMAC. */ ret = DeriveBinderKey(ssl, binderKey); if (ret != 0) return ret; @@ -3770,11 +3941,6 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, #endif } - /* Hash the rest of the ClientHello. */ - ret = HashRaw(ssl, input + helloSz - bindersLen, bindersLen); - if (ret != 0) - return ret; - #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (current == NULL) #endif @@ -3790,67 +3956,180 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, #endif } -#ifdef WOLFSSL_EARLY_DATA - extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); - if (extEarlyData != NULL) { - if (ssl->earlyData != no_early_data && current == ext->data) { - extEarlyData->resp = 1; - - /* Derive early data decryption key. */ - ret = DeriveTls13Keys(ssl, early_data_key, DECRYPT_SIDE_ONLY, 1); - if (ret != 0) - return ret; - if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) - return ret; - - ssl->earlyData = process_early_data; - } - else - extEarlyData->resp = 0; - } -#endif - - /* Get the PSK key exchange modes the client wants to negotiate. */ - ext = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); - if (ext == NULL) - return MISSING_HANDSHAKE_DATA; - modes = (word16)ext->val; - -#ifdef HAVE_SUPPORTED_CURVES - ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); - /* Use (EC)DHE for forward-security if possible. */ - if ((modes & (1 << PSK_DHE_KE)) != 0 && !ssl->options.noPskDheKe && - ext != NULL) { - /* Only use named group used in last session. */ - ssl->namedGroup = ssl->session.namedGroup; - - /* Pick key share and Generate a new key if not present. */ - ret = TLSX_KeyShare_Establish(ssl); - if (ret == KEY_SHARE_ERROR) { - ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; - ret = 0; - } - else if (ret < 0) - return ret; - - /* Send new public key to client. */ - ext->resp = 1; - } - else -#endif - { - if ((modes & (1 << PSK_KE)) == 0) - return PSK_KEY_ERROR; - ssl->options.noPskDheKe = 1; - ssl->arrays->preMasterSz = 0; - } - + *first = (current == ext->data); *usingPSK = 1; WOLFSSL_LEAVE("DoPreSharedKeys", ret); return ret; } + +/* Handle any Pre-Shared Key (PSK) extension. + * Must do this in ClientHello as it requires a hash of the truncated message. + * Don't know size of binders until Pre-Shared Key extension has been parsed. + * + * ssl SSL/TLS object. + * input ClientHello message. + * helloSz Size of the ClientHello message (including binders if present). + * clSuites Client's cipher suite list. + * usingPSK Indicates handshake is using Pre-Shared Keys. + */ +static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, + Suites* clSuites, int* usingPSK) +{ + int ret; + TLSX* ext; + word16 bindersLen; + int first = 0; +#ifndef WOLFSSL_PSK_ONE_ID + int i; + int j; +#else + byte suite[2]; +#endif + + WOLFSSL_ENTER("CheckPreSharedKeys"); + + ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (ext == NULL) { +#ifdef WOLFSSL_EARLY_DATA + ssl->earlyData = no_early_data; +#endif + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz); + return ret; + } + + /* Extensions pushed on stack/list and PSK must be last. */ + if (ssl->extensions != ext) + return PSK_KEY_ERROR; + + /* Assume we are going to resume with a pre-shared key. */ + ssl->options.resuming = 1; + + /* Find the pre-shared key extension and calculate hash of truncated + * ClientHello for binders. + */ + ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, + client_hello, &bindersLen); + if (ret < 0) + return ret; + + /* Hash data up to binders for deriving binders in PSK extension. */ + ret = HashInput(ssl, input, helloSz - bindersLen); + if (ret < 0) + return ret; + + /* Refine list for PSK processing. */ + RefineSuites(ssl, clSuites); + +#ifndef WOLFSSL_PSK_ONE_ID + if (!ssl->options.useClientOrder) { + /* Server order - server list has only common suites from refining. */ + for (i = 0; !*usingPSK && i < ssl->suites->suiteSz; i += 2) { + ret = DoPreSharedKeys(ssl, ssl->suites->suites + i, usingPSK, + &first); + if (ret != 0) { + return ret; + } + } + } + else { + /* Client order */ + for (j = 0; !*usingPSK && j < clSuites->suiteSz; j += 2) { + for (i = 0; !*usingPSK && i < ssl->suites->suiteSz; i += 2) { + ret = DoPreSharedKeys(ssl, ssl->suites->suites + i, usingPSK, + &first); + if (ret != 0) + return ret; + } + } + } +#else + ret = DoPreSharedKeys(ssl, suite, usingPSK, &first); + if (ret != 0) + return ret; +#endif + + /* Hash the rest of the ClientHello. */ + ret = HashRaw(ssl, input + helloSz - bindersLen, bindersLen); + if (ret != 0) + return ret; + + if (usingPSK) { + word16 modes; + #ifdef WOLFSSL_EARLY_DATA + TLSX* extEarlyData; + + extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); + if (extEarlyData != NULL) { + /* Check if accepting early data and first PSK. */ + if (ssl->earlyData != no_early_data && first) { + extEarlyData->resp = 1; + + /* Derive early data decryption key. */ + ret = DeriveTls13Keys(ssl, early_data_key, DECRYPT_SIDE_ONLY, + 1); + if (ret != 0) + return ret; + if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) + return ret; + + ssl->earlyData = process_early_data; + } + else + extEarlyData->resp = 0; + } + #endif + + /* Get the PSK key exchange modes the client wants to negotiate. */ + ext = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES); + if (ext == NULL) + return MISSING_HANDSHAKE_DATA; + modes = ext->val; + + #ifdef HAVE_SUPPORTED_CURVES + ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE); + /* Use (EC)DHE for forward-security if possible. */ + if ((modes & (1 << PSK_DHE_KE)) != 0 && !ssl->options.noPskDheKe && + ext != NULL) { + /* Only use named group used in last session. */ + ssl->namedGroup = ssl->session.namedGroup; + + /* Pick key share and Generate a new key if not present. */ + ret = TLSX_KeyShare_Establish(ssl); + if (ret == KEY_SHARE_ERROR) { + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; + } + else if (ret < 0) + return ret; + + /* Send new public key to client. */ + ext->resp = 1; + } + else + #endif + { + if ((modes & (1 << PSK_KE)) == 0) + return PSK_KEY_ERROR; + ssl->options.noPskDheKe = 1; + ssl->arrays->preMasterSz = 0; + } + } +#ifdef WOLFSSL_PSK_ID_PROTECTION + else { + #ifndef NO_CERTS + if (ssl->buffers.certChainCnt != 0) + return 0; + #endif + return BAD_BINDER; + } +#endif + + WOLFSSL_LEAVE("CheckPreSharedKeys", ret); + + return 0; +} #endif #if defined(WOLFSSL_SEND_HRR_COOKIE) @@ -4297,25 +4576,13 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ defined(HAVE_TLS_EXTENSIONS) - if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY) != NULL) { - /* Refine list for PSK processing. */ - RefineSuites(ssl, &clSuites); - - /* Process the Pre-Shared Key extension if present. */ - ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); - if (ret != 0) - return ret; - } - else + ret = CheckPreSharedKeys(ssl, input + begin, helloSz, &clSuites, &usingPSK); + if (ret != 0) + return ret; +#else + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; #endif - { -#ifdef WOLFSSL_EARLY_DATA - ssl->earlyData = no_early_data; -#endif - if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) - return ret; - - } #if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ defined(HAVE_TLS_EXTENSIONS) @@ -4457,6 +4724,11 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType) /* Chosen cipher suite */ output[idx++] = ssl->options.cipherSuite0; output[idx++] = ssl->options.cipherSuite; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Chosen cipher suite:"); + WOLFSSL_MSG(GetCipherNameInternal(ssl->options.cipherSuite0, + ssl->options.cipherSuite)); +#endif /* Compression not supported in TLS v1.3. */ output[idx++] = 0; @@ -8359,6 +8631,63 @@ int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) #endif /* HAVE_SUPPORTED_CURVES */ #ifndef NO_PSK +/* Set the PSK callback, that is passed the cipher suite, for a client to use + * against context object. + * + * @param [in, out] ctx SSL/TLS context object. + * @param [in] cb Client PSK callback passed a cipher suite. + */ +void wolfSSL_CTX_set_psk_client_cs_callback(WOLFSSL_CTX* ctx, + wc_psk_client_cs_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_client_cs_callback"); + + if (ctx == NULL) + return; + + ctx->havePSK = 1; + ctx->client_psk_cs_cb = cb; +} + +/* Set the PSK callback, that is passed the cipher suite, for a client to use + * against SSL object. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] cb Client PSK callback passed a cipher suite. + */ +void wolfSSL_set_psk_client_cs_callback(WOLFSSL* ssl, + wc_psk_client_cs_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_client_cs_callback"); + + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.client_psk_cs_cb = cb; + + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, + ssl->options.haveDH, ssl->options.haveNTRU, + ssl->options.haveECDSAsig, ssl->options.haveECC, + ssl->options.haveStaticECC, ssl->options.haveAnon, + ssl->options.side); +} + +/* Set the PSK callback that returns the cipher suite for a client to use + * against context object. + * + * @param [in, out] ctx SSL/TLS context object. + * @param [in] cb Client PSK callback returning cipher suite. + */ void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx, wc_psk_client_tls13_callback cb) { @@ -8371,7 +8700,12 @@ void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx, ctx->client_psk_tls13_cb = cb; } - +/* Set the PSK callback that returns the cipher suite for a client to use + * against SSL object. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] cb Client PSK callback returning cipher suite. + */ void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl, wc_psk_client_tls13_callback cb) { @@ -8399,7 +8733,12 @@ void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl, ssl->options.side); } - +/* Set the PSK callback that returns the cipher suite for a server to use + * against context object. + * + * @param [in, out] ctx SSL/TLS context object. + * @param [in] cb Server PSK callback returning cipher suite. + */ void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx, wc_psk_server_tls13_callback cb) { @@ -8410,7 +8749,12 @@ void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx, ctx->server_psk_tls13_cb = cb; } - +/* Set the PSK callback that returns the cipher suite for a server to use + * against SSL object. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] cb Server PSK callback returning cipher suite. + */ void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl, wc_psk_server_tls13_callback cb) { @@ -8436,7 +8780,38 @@ void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl, ssl->options.haveStaticECC, ssl->options.haveAnon, ssl->options.side); } -#endif + +/* Get name of first supported cipher suite that uses the hash indicated. + * + * @param [in] ssl SSL/TLS object. + * @param [in] hash Name of hash algorithm. e.g. "SHA256", "SHA384" + * @return Name of cipher suite. + * @return NULL on failure. + */ +const char* wolfSSL_get_cipher_name_by_hash(WOLFSSL* ssl, const char* hash) +{ + const char* name = NULL; + byte mac = no_mac; + int i; + + if (XSTRNCMP(hash, "SHA256", 6) == 0) { + mac = sha256_mac; + } + else if (XSTRNCMP(hash, "SHA384", 6) == 0) { + mac = sha384_mac; + } + if (mac != no_mac) { + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + if (SuiteMac(ssl->suites->suites + i) == mac) { + name = GetCipherNameInternal(ssl->suites->suites[i + 0], + ssl->suites->suites[i + 1]); + break; + } + } + } + return name; +} +#endif /* !NO_PSK */ #ifndef NO_WOLFSSL_SERVER diff --git a/tests/test-tls13-psk.conf b/tests/test-tls13-psk.conf index b8b7e2607..31ca902bc 100644 --- a/tests/test-tls13-psk.conf +++ b/tests/test-tls13-psk.conf @@ -1,15 +1,17 @@ # server TLSv1.3 PSK +# Use AES128-GCM and SHA256 -v 4 -s -l TLS13-AES128-GCM-SHA256 -d # client TLSv1.3 PSK +# Use AES128-GCM and SHA256 -v 4 -s -l TLS13-AES128-GCM-SHA256 -# server TLSv1.3 PSK +# server TLSv1.3 PSK plus -v 4 -j -l TLS13-AES128-GCM-SHA256 @@ -29,3 +31,53 @@ # client TLSv1.3 not-PSK -v 4 -l TLS13-AES128-GCM-SHA256 + +# server TLSv1.3 PSK +# AES256-GCM and SHA384 +-v 4 +-s +-l TLS13-AES256-GCM-SHA384 +-d + +# client TLSv1.3 PSK +# AES256-GCM and SHA384 +-v 4 +-s +-l TLS13-AES256-GCM-SHA384 + +# Disabling ChaCha20 results in failures. +# server TLSv1.3 PSK +# CHACHA20 only supported +#-v 4 +#-s +#-l TLS13-CHACHA20-POLY1305-SHA256 + +# client TLSv1.3 PSK +# AESGCM-SHA256 is first but CHACHA20 is negotiated as it is also SHA-256 +#-v 4 +#-s +#-l TLS13-AES128-GCM-SHA256:TLS13-CHACHA20-POLY1305-SHA256 + +# server TLSv1.3 PSK +# AESGCM-SHA256 is first but CHACHA20 is negotiated as it is also SHA-256 +#-v 4 +#-s +#-l TLS13-AES128-GCM-SHA256:TLS13-CHACHA20-POLY1305-SHA256 + +# client TLSv1.3 PSK +# CHACHA20 only supported +#-v 4 +#-s +#-l TLS13-CHACHA20-POLY1305-SHA256 + +# server TLSv1.3 PSK +# AESGCM-SHA256 is first but CHACHA20 is negotiated as it is also SHA-256 +#-v 4 +#-s +#-l TLS13-AES128-GCM-SHA256:TLS13-CHACHA20-POLY1305-SHA256 + +# client TLSv1.3 PSK +# CHACHA20 only supported +#-v 4 +#-s +#-l TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES128-GCM-SHA256 diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 8c06ceb27..1a456b65f 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1732,7 +1732,7 @@ WOLFSSL_LOCAL int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) WOLFSSL_LOCAL int HandleTlsResumption(WOLFSSL* ssl, int bogusID, Suites* clSuites); #ifdef WOLFSSL_TLS13 -WOLFSSL_LOCAL int FindSuite(Suites* suites, byte first, byte second); +WOLFSSL_LOCAL byte SuiteMac(byte* suite); #endif WOLFSSL_LOCAL int DoClientHello(WOLFSSL* ssl, const byte* input, word32*, word32); @@ -1899,11 +1899,15 @@ WOLFSSL_LOCAL int SetCipherList(WOLFSSL_CTX*, Suites*, const char* list); typedef unsigned int (*wc_psk_server_callback)(WOLFSSL*, const char*, unsigned char*, unsigned int); #ifdef WOLFSSL_TLS13 + typedef unsigned int (*wc_psk_client_cs_callback)(WOLFSSL*, const char*, + char*, unsigned int, unsigned char*, unsigned int, + const char* cipherName); typedef unsigned int (*wc_psk_client_tls13_callback)(WOLFSSL*, const char*, char*, unsigned int, unsigned char*, unsigned int, - const char**); + const char** cipherName); typedef unsigned int (*wc_psk_server_tls13_callback)(WOLFSSL*, const char*, - unsigned char*, unsigned int, const char**); + unsigned char*, unsigned int, + const char** cipherName); #endif #endif /* PSK_TYPES_DEFINED */ #if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \ @@ -2894,6 +2898,7 @@ struct WOLFSSL_CTX { wc_psk_client_callback client_psk_cb; /* client callback */ wc_psk_server_callback server_psk_cb; /* server callback */ #ifdef WOLFSSL_TLS13 + wc_psk_client_cs_callback client_psk_cs_cb; /* client callback */ wc_psk_client_tls13_callback client_psk_tls13_cb; /* client callback */ wc_psk_server_tls13_callback server_psk_tls13_cb; /* server callback */ #endif @@ -3510,6 +3515,7 @@ typedef struct Options { wc_psk_use_session_cb_func session_psk_cb; #endif #ifdef WOLFSSL_TLS13 + wc_psk_client_cs_callback client_psk_cs_cb; /* client callback */ wc_psk_client_tls13_callback client_psk_tls13_cb; /* client callback */ wc_psk_server_tls13_callback server_psk_tls13_cb; /* server callback */ #endif @@ -4735,6 +4741,8 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); #if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) WOLFSSL_LOCAL word32 TimeNowInMilliseconds(void); + + WOLFSSL_LOCAL int FindSuiteMac(WOLFSSL* ssl, byte* suite); #endif WOLFSSL_LOCAL word32 LowResTimer(void); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index e5bcf772c..f61cd9e43 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2178,9 +2178,9 @@ enum { /* ssl Constants */ typedef unsigned int (*wc_psk_client_callback)(WOLFSSL*, const char*, char*, unsigned int, unsigned char*, unsigned int); WOLFSSL_API void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX*, - wc_psk_client_callback); + wc_psk_client_callback); WOLFSSL_API void wolfSSL_set_psk_client_callback(WOLFSSL*, - wc_psk_client_callback); + wc_psk_client_callback); #ifdef OPENSSL_EXTRA typedef int (*wc_psk_use_session_cb_func)(WOLFSSL* ssl, const WOLFSSL_EVP_MD* md, const unsigned char **id, @@ -2189,12 +2189,19 @@ enum { /* ssl Constants */ wc_psk_use_session_cb_func cb); #endif #ifdef WOLFSSL_TLS13 + typedef unsigned int (*wc_psk_client_cs_callback)(WOLFSSL*, const char*, + char*, unsigned int, unsigned char*, unsigned int, const char*); + WOLFSSL_API void wolfSSL_CTX_set_psk_client_cs_callback(WOLFSSL_CTX*, + wc_psk_client_cs_callback); + WOLFSSL_API void wolfSSL_set_psk_client_cs_callback(WOLFSSL*, + wc_psk_client_cs_callback); + typedef unsigned int (*wc_psk_client_tls13_callback)(WOLFSSL*, const char*, - char*, unsigned int, unsigned char*, unsigned int, const char**); + char*, unsigned int, unsigned char*, unsigned int, const char**); WOLFSSL_API void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX*, - wc_psk_client_tls13_callback); + wc_psk_client_tls13_callback); WOLFSSL_API void wolfSSL_set_psk_client_tls13_callback(WOLFSSL*, - wc_psk_client_tls13_callback); + wc_psk_client_tls13_callback); #endif WOLFSSL_API const char* wolfSSL_get_psk_identity_hint(const WOLFSSL*); @@ -2206,16 +2213,16 @@ enum { /* ssl Constants */ typedef unsigned int (*wc_psk_server_callback)(WOLFSSL*, const char*, unsigned char*, unsigned int); WOLFSSL_API void wolfSSL_CTX_set_psk_server_callback(WOLFSSL_CTX*, - wc_psk_server_callback); + wc_psk_server_callback); WOLFSSL_API void wolfSSL_set_psk_server_callback(WOLFSSL*, - wc_psk_server_callback); + wc_psk_server_callback); #ifdef WOLFSSL_TLS13 typedef unsigned int (*wc_psk_server_tls13_callback)(WOLFSSL*, const char*, - unsigned char*, unsigned int, const char**); + unsigned char*, unsigned int, const char**); WOLFSSL_API void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX*, - wc_psk_server_tls13_callback); + wc_psk_server_tls13_callback); WOLFSSL_API void wolfSSL_set_psk_server_tls13_callback(WOLFSSL*, - wc_psk_server_tls13_callback); + wc_psk_server_tls13_callback); #endif WOLFSSL_API void* wolfSSL_get_psk_callback_ctx(WOLFSSL*); WOLFSSL_API int wolfSSL_set_psk_callback_ctx(WOLFSSL*, void*); @@ -2224,6 +2231,11 @@ enum { /* ssl Constants */ WOLFSSL_API int wolfSSL_CTX_set_psk_callback_ctx(WOLFSSL_CTX*, void*); #define PSK_TYPES_DEFINED + +#ifdef WOLFSSL_TLS13 + WOLFSSL_API const char* wolfSSL_get_cipher_name_by_hash(WOLFSSL* ssl, + const char* hash); +#endif #endif /* NO_PSK */ diff --git a/wolfssl/test.h b/wolfssl/test.h index d8e5adce6..5126e709b 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1499,14 +1499,18 @@ static WC_INLINE unsigned int my_psk_server_tls13_cb(WOLFSSL* ssl, { int i; int b = 0x01; + int kIdLen = (int)XSTRLEN(kIdentityStr); const char* userCipher = (const char*)wolfSSL_get_psk_callback_ctx(ssl); (void)ssl; (void)key_max_len; /* see internal.h MAX_PSK_ID_LEN for PSK identity limit */ - if (XSTRNCMP(identity, kIdentityStr, XSTRLEN(kIdentityStr)) != 0) + if (XSTRNCMP(identity, kIdentityStr, kIdLen) != 0) return 0; + if (identity[kIdLen] != '\0') { + userCipher = wolfSSL_get_cipher_name_by_hash(ssl, identity + kIdLen); + } for (i = 0; i < 32; i++, b += 0x22) { if (b >= 0x100) @@ -1590,6 +1594,31 @@ static WC_INLINE int my_psk_use_session_cb(WOLFSSL* ssl, return 0; #endif } + +static WC_INLINE unsigned int my_psk_client_cs_cb(WOLFSSL* ssl, + const char* hint, char* identity, unsigned int id_max_len, + unsigned char* key, unsigned int key_max_len, const char* ciphersuite) +{ + int i; + int b = 0x01; + + (void)ssl; + (void)hint; + (void)key_max_len; + + /* see internal.h MAX_PSK_ID_LEN for PSK identity limit */ + XSTRNCPY(identity, kIdentityStr, id_max_len); + XSTRNCAT(identity, ciphersuite + XSTRLEN(ciphersuite) - 6, id_max_len); + + for (i = 0; i < 32; i++, b += 0x22) { + if (b >= 0x100) + b = 0x01; + key[i] = b; + } + + return 32; /* length of key in octets or 0 for error */ +} + #endif /* !NO_PSK */