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 */