From 5d5ff56336b4379936a4486be5b3fc0b5e504373 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 7 Jun 2017 08:29:08 +1000 Subject: [PATCH] External PSK working in TLS13 --- examples/client/client.c | 15 ++- examples/server/server.c | 17 +-- src/ssl.c | 6 +- src/tls.c | 82 +++++++++++---- src/tls13.c | 216 ++++++++++++++++++++++++++++---------- tests/test-psk-no-id.conf | 10 ++ wolfssl/internal.h | 23 ++-- 7 files changed, 268 insertions(+), 101 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index a86b5681e..6b81d3430 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1280,13 +1280,18 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb); if (cipherList == NULL) { const char *defaultCipherList; - #if defined(HAVE_AESGCM) && !defined(NO_DH) - defaultCipherList = "DHE-PSK-AES128-GCM-SHA256"; - #elif defined(HAVE_NULL_CIPHER) - defaultCipherList = "PSK-NULL-SHA256"; + #if defined(HAVE_AESGCM) && !defined(NO_DH) + #ifdef WOLFSSL_TLS13 + defaultCipherList = "DHE-PSK-AES128-GCM-SHA256:" + "TLS13-AES128-GCM-SHA256"; #else - defaultCipherList = "PSK-AES128-CBC-SHA256"; + defaultCipherList = "DHE-PSK-AES128-GCM-SHA256"; #endif + #elif defined(HAVE_NULL_CIPHER) + defaultCipherList = "PSK-NULL-SHA256"; + #else + defaultCipherList = "PSK-AES128-CBC-SHA256"; + #endif if (wolfSSL_CTX_set_cipher_list(ctx,defaultCipherList) !=SSL_SUCCESS) { wolfSSL_CTX_free(ctx); diff --git a/examples/server/server.c b/examples/server/server.c index 7eb1bb287..766f1ea2f 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -866,14 +866,19 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) if (cipherList == NULL && !usePskPlus) { const char *defaultCipherList; - #if defined(HAVE_AESGCM) && !defined(NO_DH) - defaultCipherList = "DHE-PSK-AES128-GCM-SHA256"; - needDH = 1; - #elif defined(HAVE_NULL_CIPHER) - defaultCipherList = "PSK-NULL-SHA256"; + #if defined(HAVE_AESGCM) && !defined(NO_DH) + #ifdef WOLFSSL_TLS13 + defaultCipherList = "DHE-PSK-AES128-GCM-SHA256:" + "TLS13-AES128-GCM-SHA256"; #else - defaultCipherList = "PSK-AES128-CBC-SHA256"; + defaultCipherList = "DHE-PSK-AES128-GCM-SHA256"; #endif + needDH = 1; + #elif defined(HAVE_NULL_CIPHER) + defaultCipherList = "PSK-NULL-SHA256"; + #else + defaultCipherList = "PSK-AES128-CBC-SHA256"; + #endif if (SSL_CTX_set_cipher_list(ctx, defaultCipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 2"); } diff --git a/src/ssl.c b/src/ssl.c index 5f3da6c8b..eceafd442 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -9128,7 +9128,7 @@ int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) ssl->options.resuming = 1; #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)) + defined(HAVE_SESSION_TICKET)) ssl->version = session->version; ssl->options.cipherSuite0 = session->cipherSuite0; ssl->options.cipherSuite = session->cipherSuite; @@ -9278,13 +9278,13 @@ int AddSession(WOLFSSL* ssl) } #endif /* SESSION_CERTS */ #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET) && !defined(NO_PSK)) + defined(HAVE_SESSION_TICKET)) if (error == 0) { session->version = ssl->version; session->cipherSuite0 = ssl->options.cipherSuite0; session->cipherSuite = ssl->options.cipherSuite; } -#endif /* SESSION_CERTS || (WOLFSSL_TLS13 & !NO_PSK) */ +#endif /* SESSION_CERTS || (WOLFSSL_TLS13 & HAVE_SESSION_TICKET) */ #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) if (error == 0) { session->namedGroup = ssl->session.namedGroup; diff --git a/src/tls.c b/src/tls.c index 6399bb808..5e5c47148 100755 --- a/src/tls.c +++ b/src/tls.c @@ -673,7 +673,7 @@ static INLINE void c24to32(const word24 u24, word32* u32) } #endif -#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) /* Convert opaque data to a 32-bit unsigned integer. * * c The opaque data holding a 32-bit integer. @@ -5207,7 +5207,7 @@ static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) { int ret; -#ifdef HAVE_SESSION_TICKET +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) ssl->session.namedGroup = keyShareEntry->group; #endif /* Use Key Share Data from server. */ @@ -5434,6 +5434,7 @@ int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, byte* data, if (extension == NULL) return MEMORY_E; } + extension->resp = 0; /* Try to find the key share entry with this group. */ keyShareEntry = (KeyShareEntry*)extension->data; @@ -5620,6 +5621,9 @@ int TLSX_KeyShare_Establish(WOLFSSL *ssl) if (extension != NULL) list = (KeyShareEntry*)extension->data; + if (extension && extension->resp == 1) + return 0; + /* TODO: [TLS13] Server's preference and sending back SupportedGroups */ /* Use client's preference. */ for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) { @@ -5695,7 +5699,7 @@ int TLSX_KeyShare_Establish(WOLFSSL *ssl) /* Pre-Shared Key */ /******************************************************************************/ -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) /* Free the pre-shared key dynamic data. * * list The linked list of key share entry objects. @@ -5922,8 +5926,8 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, ato32(input + idx, &age); idx += OPAQUE32_LEN; - ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, 0, 1, - NULL); + ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, no_mac, + 1, NULL); if (ret != 0) return ret; @@ -5990,6 +5994,7 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, return PSK_KEY_ERROR; list->chosen = 1; + #ifdef HAVE_SESSION_TICKET if (list->resumption) { /* Check that the session's details are the same as the server's. */ if (ssl->options.cipherSuite0 != ssl->session.cipherSuite0 || @@ -5999,6 +6004,7 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length, return PSK_KEY_ERROR; } } + #endif /* TODO: [TLS13] More checks of consistency. * the "key_share", and "signature_algorithms" extensions are * consistent with the indicated ke_modes and auth_modes values @@ -6147,7 +6153,7 @@ int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age, /* PSK Key Exchange Modes */ /******************************************************************************/ -#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) /* Get the size of the encoded PSK KE modes extension. * Only in ClientHello. * @@ -6368,7 +6374,7 @@ void TLSX_FreeAll(TLSX* list, void* heap) KS_FREE_ALL((KeyShareEntry*)extension->data, heap); break; - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: PSK_FREE_ALL((PreSharedKey*)extension->data, heap); break; @@ -6475,7 +6481,7 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType); break; - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: length += PSK_GET_SIZE((PreSharedKey*)extension->data, msgType); break; @@ -6602,7 +6608,7 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, output + offset, msgType); break; - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: WOLFSSL_MSG("Pre-Shared Key extension to write"); offset += PSK_WRITE((PreSharedKey*)extension->data, @@ -6826,6 +6832,9 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) int ret = 0; byte* public_key = NULL; word16 public_key_len = 0; +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) + int usingPSK = 0; +#endif #ifdef HAVE_QSH TLSX* extension; QSHScheme* qsh; @@ -7084,11 +7093,10 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return ret; } - #if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) + #if defined(HAVE_SESSION_TICKET) if (ssl->options.resuming) { WOLFSSL_SESSION* sess = &ssl->session; word32 milli; - byte modes; /* Determine the MAC algorithm for the cipher suite used. */ ssl->options.cipherSuite0 = sess->cipherSuite0; @@ -7103,6 +7111,37 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) if (ret != 0) return ret; + usingPSK = 1; + } + #endif + #ifndef NO_PSK + if (ssl->options.client_psk_cb != NULL) { + byte mac = sha256_mac; + + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays->server_hint, ssl->arrays->client_identity, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + return PSK_KEY_ERROR; + } + ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0'; + /* Hash algorithm defaults to SHA-256 unless cb specifies. */ + + ret = TLSX_PreSharedKey_Use(ssl, + (byte*)ssl->arrays->client_identity, + XSTRLEN(ssl->arrays->client_identity), + 0, mac, 0, NULL); + if (ret != 0) + return ret; + + usingPSK = 1; + } + #endif + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + if (usingPSK) { + byte modes; + /* Pre-shared key modes: mandatory extension for resumption. */ modes = 1 << PSK_KE; #if !defined(NO_DH) || defined(HAVE_ECC) @@ -7114,7 +7153,6 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return ret; } #endif - /* TODO: [TLS13] Add PSKs */ } #endif @@ -7152,7 +7190,7 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) if (!IsAtLeastTLSv1_3(ssl->version)) { TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); #endif @@ -7200,11 +7238,11 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) if (!IsAtLeastTLSv1_3(ssl->version)) { TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); #endif } - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif #endif @@ -7227,8 +7265,8 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) #endif #ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version) && ssl->options.resuming) { - #ifndef NO_PSK + if (IsAtLeastTLSv1_3(ssl->version)) { + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif offset += TLSX_Write(ssl->extensions, output + offset, semaphore, @@ -7260,7 +7298,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) if (ssl->options.tls1_3) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif } @@ -7268,7 +7306,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType) case encrypted_extensions: TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif break; @@ -7321,7 +7359,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) if (ssl->options.tls1_3) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif } @@ -7329,7 +7367,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType) case encrypted_extensions: TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif break; @@ -7574,7 +7612,7 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = KS_PARSE(ssl, input + offset, size, msgType); break; - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: WOLFSSL_MSG("Pre-Shared Key extension received"); diff --git a/src/tls13.c b/src/tls13.c index b5beff8d7..852b30f80 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -26,8 +26,8 @@ #endif #ifdef WOLFSSL_TLS13 -#if defined(HAVE_SESSION_TICKET) -#include +#ifdef HAVE_SESSION_TICKET + #include #endif #include @@ -462,7 +462,7 @@ static int DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, } -#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +#ifndef NO_PSK #ifdef WOLFSSL_TLS13_DRAFT_18 /* The length of the binder key label. */ #define BINDER_KEY_LABEL_SZ 23 @@ -489,7 +489,9 @@ static int DeriveBinderKey(WOLFSSL* ssl, byte* key) binderKeyLabel, BINDER_KEY_LABEL_SZ, NULL, 0, ssl->specs.mac_algorithm); } +#endif /* !NO_PSK */ +#ifdef HAVE_SESSION_TICKET #ifdef WOLFSSL_TLS13_DRAFT_18 /* The length of the binder key resume label. */ #define BINDER_KEY_RESUME_LABEL_SZ 25 @@ -516,7 +518,7 @@ static int DeriveBinderKeyResume(WOLFSSL* ssl, byte* key) binderKeyResumeLabel, BINDER_KEY_RESUME_LABEL_SZ, NULL, 0, ssl->specs.mac_algorithm); } -#endif +#endif /* HAVE_SESSION_TICKET */ #ifdef TLS13_SUPPORTS_0RTT #ifdef WOLFSSL_TLS13_DRAFT_18 @@ -713,7 +715,7 @@ static int DeriveExporterSecret(WOLFSSL* ssl, byte* key) } #endif -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13_DRAFT_18 /* The length of the resumption master secret label. */ #define RESUME_MASTER_LABEL_SZ 24 @@ -794,7 +796,7 @@ static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret) static int DeriveEarlySecret(WOLFSSL* ssl) { WOLFSSL_MSG("Derive Early Secret"); -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, ssl->arrays->psk_key, ssl->arrays->psk_keySz, ssl->specs.mac_algorithm); @@ -1073,7 +1075,7 @@ end: return ret; } -#if defined(HAVE_SESSION_TICKET) +#ifdef HAVE_SESSION_TICKET #if defined(USER_TICKS) #if 0 word32 TimeNowInMilliseconds(void) @@ -1274,10 +1276,10 @@ end: return (word32)(now.tv_sec * 1000 + now.tv_usec / 1000); } #endif -#endif /* HAVE_SESSION_TICKET */ +#endif /* HAVE_SESSION_TICKET || !NO_PSK */ -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) && \ +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_SESSION_TICKET) || \ !defined(NO_PSK)) /* Add input to all handshake hashes. * @@ -1323,6 +1325,55 @@ static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) } #endif +/* Restart the Hanshake hash with a hash of the previous messages. + * + * ssl The SSL/TLS object. + * returns 0 on success, otherwise failure. + */ +static int RestartHandshakeHash(WOLFSSL* ssl) +{ + int ret; + Hashes hashes; + byte header[] = { message_hash, 0, 0, 0 }; + byte* hash = NULL; + + ret = BuildCertHashes(ssl, &hashes); + if (ret != 0) + return ret; + ret = InitHandshakeHashes(ssl); + if (ret != 0) + return ret; + switch (ssl->specs.mac_algorithm) { + #ifndef NO_SHA256 + case sha256_mac: + header[3] = SHA256_DIGEST_SIZE; + hash = hashes.sha256; + break; + #endif + #ifdef WOLFSSL_SHA384 + case sha384_mac: + header[3] = SHA384_DIGEST_SIZE; + hash = hashes.sha384; + break; + #endif + #ifdef WOLFSSL_SHA512 + case sha512_mac: + header[3] = SHA512_DIGEST_SIZE; + hash = hashes.sha512; + break; + #endif + } + + WOLFSSL_MSG("Restart Hash"); + WOLFSSL_BUFFER(hash, header[3]); + + ret = HashOutputRaw(ssl, header, sizeof(header)); + if (ret != 0) + return ret; + return HashOutputRaw(ssl, hash, header[3]); +} + + /* Extract the handshake header information. * * ssl The SSL/TLS object. @@ -1335,9 +1386,9 @@ static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) * returns BUFFER_E if there is not enough input data and 0 on success. */ static int GetHandshakeHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, - byte *type, word32 *size, word32 totalSz) + byte* type, word32* size, word32 totalSz) { - const byte *ptr = input + *inOutIdx; + const byte* ptr = input + *inOutIdx; (void)ssl; *inOutIdx += HANDSHAKE_HEADER_SZ; @@ -1471,7 +1522,7 @@ static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) * iv The derived IV. * order The side on which the message is to be or was sent. */ -static INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte *nonce, const byte* iv, +static INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte* nonce, const byte* iv, int order) { int i; @@ -1612,7 +1663,7 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, * tagIn The authentication tag data from packet. * returns 0 on success, otherwise failure. */ -static int ChaCha20Poly1305_Decrypt(WOLFSSL *ssl, byte* output, +static int ChaCha20Poly1305_Decrypt(WOLFSSL* ssl, byte* output, const byte* input, word16 sz, byte* nonce, const byte* tagIn) { @@ -1821,13 +1872,13 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, } #ifndef NO_WOLFSSL_CLIENT -#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +#ifdef HAVE_SESSION_TICKET /* Get the size of the message hash. * * ssl The SSL/TLS object. * returns the length of the hash. */ -static int GetMsgHashSize(WOLFSSL *ssl) +static int GetMsgHashSize(WOLFSSL* ssl) { switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 @@ -1845,7 +1896,9 @@ static int GetMsgHashSize(WOLFSSL *ssl) } return 0; } +#endif +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* Derive and write the binders into the ClientHello in space left when * writing the Pre-Shared Key extension. * @@ -1879,6 +1932,7 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) /* Calculate the binder for each identity based on previous handshake data. */ while (current != NULL) { + #ifdef HAVE_SESSION_TICKET if (current->resumption) { /* Set the HMAC to use based on the one for the session (set into * the extension data at the start of this function based on the @@ -1899,12 +1953,17 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) if (ret != 0) return ret; } - else { - /* TODO: [TLS13] Support non-ticket PSK. */ + else + #endif + #ifndef NO_PSK + if (!current->resumption) { /* Get the pre-shared key. */ ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, (char *)current->identity, ssl->arrays->client_identity, MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + /* TODO: Forcing cipher suite to use SHA256 with PSK. */ + /* Default to SHA-256 if cb doesn't specify. */ + ssl->specs.mac_algorithm = sha256_mac; /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); if (ret != 0) @@ -1914,6 +1973,12 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx) if (ret != 0) return ret; } + else + #endif + { + current = current->next; + continue; + } /* Derive the Finished message secret. */ ret = DeriveFinishedSecret(ssl, binderKey, ssl->keys.client_write_MAC_secret); @@ -1954,7 +2019,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) int sendSz; int ret; -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) if (ssl->options.resuming && (ssl->session.version.major != ssl->version.major || ssl->session.version.minor != ssl->version.minor)) { @@ -2031,11 +2096,11 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* Write out extensions for a request. */ idx += TLSX_WriteRequest(ssl, output + idx); -#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* Resumption has a specific set of extensions and binder is calculated * for each identity. */ - if (ssl->options.resuming) + if (TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY)) ret = WritePSKBinders(ssl, output, idx); else #endif @@ -2083,7 +2148,7 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, #endif /* Version info and length field of extension data. */ - if (totalSz < i - begin + OPAQUE16_LEN + OPAQUE16_LEN) + if (totalSz < i - begin + OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN) return BUFFER_ERROR; /* Protocol version. */ @@ -2093,6 +2158,14 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, if (ret != 0) return ret; + /* Set the cipher suite from the message. */ + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + + ret = SetCipherSpecs(ssl); + if (ret != 0) + return ret; + /* Length of extension data. */ ato16(&input[i], &totalExtSz); i += OPAQUE16_LEN; @@ -2115,7 +2188,7 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, ssl->options.tls1_3 = 1; ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST; - return 0; + return RestartHandshakeHash(ssl); } /* Handle the ServerHello message from the server. @@ -2199,9 +2272,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) return ret; -#ifndef NO_PSK +#ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { - PreSharedKey *psk = NULL; + PreSharedKey* psk = NULL; TLSX* ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (ext != NULL) psk = (PreSharedKey*)ext->data; @@ -2336,7 +2409,7 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, #endif /* !NO_WOLFSSL_CLIENT */ #ifndef NO_WOLFSSL_SERVER -#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* 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. @@ -2347,7 +2420,7 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, * 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, +static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, int* usingPSK) { int ret; @@ -2384,13 +2457,15 @@ static int DoPreSharedKeys(WOLFSSL *ssl, const byte* input, word32 helloSz, /* Look through all client's pre-shared keys for a match. */ current = (PreSharedKey*)ext->data; while (current != NULL) { - /* TODO: [TLS13] Support non-ticket PSK. */ - /* Decode the identity. */ - ret = DoClientTicket(ssl, current->identity, current->identityLen); - if (ret != WOLFSSL_TICKET_RET_OK) - continue; + #ifndef NO_PSK + XMEMCPY(ssl->arrays->client_identity, current->identity, + current->identityLen); + ssl->arrays->client_identity[current->identityLen] = '\0'; + #endif - if (current->resumption) { + #ifdef HAVE_SESSION_TICKET + /* Decode the identity. */ + if ((ret = DoClientTicket(ssl, current->identity, current->identityLen)) == WOLFSSL_TICKET_RET_OK) { /* Check the ticket isn't too old or new. */ int diff = TimeNowInMilliseconds() - ssl->session.ticketSeen; diff -= current->ticketAge - ssl->session.ticketAdd; @@ -2421,15 +2496,25 @@ static int DoPreSharedKeys(WOLFSSL *ssl, const byte* input, word32 helloSz, if (ret != 0) return ret; } - else { + else + #endif + #ifndef NO_PSK + if ((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; + + ssl->options.resuming = 0; + /* PSK age is always zero. */ if (current->ticketAge != ssl->session.ticketAdd) return PSK_KEY_ERROR; - /* Get the pre-shared key. */ - ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, - (char*)current->identity, ssl->arrays->client_identity, - MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + /* TODO: Forcing cipher suite to use SHA256 with PSK. */ + /* Default to SHA-256 if cb doesn't specify. */ + ssl->specs.mac_algorithm = sha256_mac; + /* Derive the early secret using the PSK. */ ret = DeriveEarlySecret(ssl); if (ret != 0) @@ -2439,6 +2524,14 @@ static int DoPreSharedKeys(WOLFSSL *ssl, const byte* input, word32 helloSz, if (ret != 0) return ret; } + else + #endif + { + current = current->next; + continue; + } + + ssl->options.sendVerify = 0; /* Derive the Finished message secret. */ ret = DeriveFinishedSecret(ssl, binderKey, @@ -2627,21 +2720,25 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) ssl->version.minor = pv.minor; -#if defined(HAVE_SESSION_TICKET) && !defined(NO_PSK) + ssl->options.sendVerify = SEND_CERT; + +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* Process the Pre-Shared Key extension if present. */ ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); if (ret != 0) return ret; #endif - if (!usingPSK) { + if (!usingPSK || !ssl->options.resuming) { ret = MatchSuite(ssl, &clSuites); if (ret < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); return ret; } + } -#ifndef NO_PSK + if (!usingPSK) { +#ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { ssl->options.resuming = 0; XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); @@ -2655,6 +2752,10 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ret = HashInput(ssl, input + begin, helloSz); if (ret != 0) return ret; + + /* Derive early secret for handshake secret. */ + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; } i += totalExtSz; @@ -2672,7 +2773,7 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13HelloRetryRequest(WOLFSSL *ssl) +int SendTls13HelloRetryRequest(WOLFSSL* ssl) { int ret; byte* output; @@ -2687,8 +2788,8 @@ int SendTls13HelloRetryRequest(WOLFSSL *ssl) if (len == 0) return MISSING_HANDSHAKE_DATA; - /* Protocol version + Extensions */ - length = OPAQUE16_LEN + len; + /* Protocol version + CipherSuite + Extensions */ + length = OPAQUE16_LEN + OPAQUE16_LEN + len; sendSz = idx + length; /* Check buffers are big enough and grow if needed. */ @@ -2713,6 +2814,10 @@ int SendTls13HelloRetryRequest(WOLFSSL *ssl) output[idx++] = TLS_DRAFT_MAJOR; output[idx++] = TLS_DRAFT_MINOR; + /* Chosen cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + /* Add TLS extensions. */ TLSX_WriteResponse(ssl, output + idx, hello_retry_request); idx += len; @@ -2725,6 +2830,10 @@ int SendTls13HelloRetryRequest(WOLFSSL *ssl) ssl->heap); #endif + ret = RestartHandshakeHash(ssl); + if (ret < 0) + return ret; + ret = HashOutput(ssl, output, idx, 0); if (ret != 0) return ret; @@ -2827,7 +2936,7 @@ int SendTls13ServerHello(WOLFSSL* ssl) * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. */ -int SendTls13EncryptedExtensions(WOLFSSL *ssl) +int SendTls13EncryptedExtensions(WOLFSSL* ssl) { int ret; byte* output; @@ -2837,9 +2946,6 @@ int SendTls13EncryptedExtensions(WOLFSSL *ssl) ssl->keys.encryptionOn = 1; - /* Derive early secret for handshake secret. */ - if ((ret = DeriveEarlySecret(ssl)) != 0) - return ret; /* Derive the handshake secret now that we are at first message to be * encrypted under the keys. */ @@ -2907,7 +3013,7 @@ int SendTls13EncryptedExtensions(WOLFSSL *ssl) */ int SendTls13CertificateRequest(WOLFSSL* ssl) { - byte *output; + byte* output; int ret; int sendSz; int reqCtxLen = 0; @@ -3033,7 +3139,7 @@ static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) * hash The buffer to write the hash to. * returns the length of the hash. */ -static INLINE int GetMsgHash(WOLFSSL *ssl, byte* hash) +static INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash) { switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 @@ -3279,7 +3385,7 @@ static int CheckRSASignature(WOLFSSL* ssl, int sigAlgo, int hashAlgo, CreateSigData(ssl, sigData, &sigDataSz, 1); #ifdef WC_RSA_PSS if (sigAlgo == rsa_pss_sa_algo) { - int hashType = WC_HASH_TYPE_NONE; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; switch (hashAlgo) { case sha512_mac: @@ -4392,7 +4498,7 @@ int SendTls13Finished(WOLFSSL* ssl) if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) ret = DeriveResumptionSecret(ssl, ssl->session.masterSecret); #endif } @@ -5011,7 +5117,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, return ret; } -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (type == finished && ssl->options.side == WOLFSSL_SERVER_END) DeriveResumptionSecret(ssl, ssl->session.masterSecret); #endif @@ -5464,7 +5570,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) errno = 0; #endif -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) havePSK = ssl->options.havePSK; #endif (void)havePSK; @@ -5594,7 +5700,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case CERT_REQ_SENT : ssl->options.acceptState = KEY_EXCHANGE_SENT; #ifndef NO_CERTS - if (!ssl->options.resuming) { + if (!ssl->options.resuming && ssl->options.sendVerify) { if ((ssl->error = SendTls13Certificate(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -5607,7 +5713,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) case CERT_SENT : #ifndef NO_CERTS - if (!ssl->options.resuming) { + if (!ssl->options.resuming && ssl->options.sendVerify) { if ((ssl->error = SendTls13CertificateVerify(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; diff --git a/tests/test-psk-no-id.conf b/tests/test-psk-no-id.conf index 40f63af36..f3a997e25 100644 --- a/tests/test-psk-no-id.conf +++ b/tests/test-psk-no-id.conf @@ -251,3 +251,13 @@ -v 3 -l PSK-AES256-GCM-SHA384 +# server TLSv1.3 AES128-GCM-SHA256 +-s +-v 4 +-l TLS13-AES128-GCM-SHA256 + +# client TLSv1.3 AES128-GCM-SHA256 +-s +-v 4 +-l TLS13-AES128-GCM-SHA256 + diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 493870135..9487a7947 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1771,11 +1771,11 @@ typedef enum { TLSX_SESSION_TICKET = 0x0023, #ifdef WOLFSSL_TLS13 TLSX_KEY_SHARE = 0x0028, - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX_PRE_SHARED_KEY = 0x0029, #endif TLSX_SUPPORTED_VERSIONS = 0x002b, - #ifndef NO_PSK + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d, #endif #endif @@ -2063,7 +2063,7 @@ WOLFSSL_LOCAL int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, WOLFSSL_LOCAL int TLSX_KeyShare_Empty(WOLFSSL* ssl); WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl); -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* The PreSharedKey extension information - entry in a linked list. */ typedef struct PreSharedKey { word16 identityLen; /* Length of identity */ @@ -2092,7 +2092,7 @@ enum PskKeyExchangeMode { }; WOLFSSL_LOCAL int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes); -#endif /* NO_PSK */ +#endif /* HAVE_SESSION_TICKET || !NO_PSK */ /* The types of keys to derive for. */ enum DeriveKeyType { @@ -2203,12 +2203,12 @@ struct WOLFSSL_CTX { word32 ecdhCurveOID; /* curve Ecc_Sum */ word32 pkCurveOID; /* curve Ecc_Sum */ #endif -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) byte havePSK; /* psk key set by user */ wc_psk_client_callback client_psk_cb; /* client callback */ wc_psk_server_callback server_psk_cb; /* server callback */ char server_hint[MAX_PSK_ID_LEN + NULL_TERM_LEN]; -#endif /* NO_PSK */ +#endif /* HAVE_SESSION_TICKET || !NO_PSK */ #ifdef HAVE_ANON byte haveAnon; /* User wants to allow Anon suites */ #endif /* HAVE_ANON */ @@ -2527,7 +2527,7 @@ struct WOLFSSL_SESSION { word16 idLen; /* serverID length */ byte serverID[SERVER_ID_LEN]; /* for easier client lookup */ #endif -#ifdef HAVE_SESSION_TICKET +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13 byte namedGroup; word32 ticketSeen; /* Time ticket seen (ms) */ @@ -2657,8 +2657,10 @@ typedef struct Options { #ifndef NO_PSK wc_psk_client_callback client_psk_cb; wc_psk_server_callback server_psk_cb; - word16 havePSK:1; /* psk key set by user */ #endif /* NO_PSK */ +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + word16 havePSK:1; /* psk key set by user */ +#endif /* HAVE_SESSION_TICKET || !NO_PSK */ #ifdef OPENSSL_EXTRA unsigned long mask; /* store SSL_OP_ flags */ #endif @@ -2767,7 +2769,7 @@ typedef struct Arrays { word32 preMasterSz; /* differs for DH, actual size */ word32 pendingMsgSz; /* defrag buffer size */ word32 pendingMsgOffset; /* current offset into defrag buffer */ -#ifndef NO_PSK +#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) word32 psk_keySz; /* actual size */ char client_identity[MAX_PSK_ID_LEN + NULL_TERM_LEN]; char server_hint[MAX_PSK_ID_LEN + NULL_TERM_LEN]; @@ -3380,6 +3382,7 @@ enum HandShakeType { change_cipher_hs = 55, /* simulate unique handshake type for sanity checks. record layer change_cipher conflicts with handshake finished */ + message_hash = 254, /* synthetic message type for TLS v1.3 */ no_shake = 255 /* used to initialize the DtlsMsg record */ }; @@ -3543,7 +3546,7 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); #endif /* NO_TLS */ -#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) +#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) WOLFSSL_LOCAL word32 TimeNowInMilliseconds(void); #endif WOLFSSL_LOCAL word32 LowResTimer(void);