wolfSSL SSL/TLS library, support up to TLS1.3
Dependents: CyaSSL-Twitter-OAuth4Tw Example-client-tls-cert TwitterReader TweetTest ... more
Diff: src/tls13.c
- Revision:
- 16:8e0d178b1d1e
- Parent:
- 15:117db924cf7c
--- a/src/tls13.c Sat Aug 18 22:20:43 2018 +0000 +++ b/src/tls13.c Thu Jun 04 23:57:22 2020 +0000 @@ -1,6 +1,6 @@ /* tls13.c * - * Copyright (C) 2006-2017 wolfSSL Inc. + * Copyright (C) 2006-2020 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -30,18 +30,20 @@ * NO_PSK * Do not enable Pre-Shared Keys. * TLS13_SUPPORTS_EXPORTERS - * Gaurd to compile out any code for exporter keys. + * Guard to compile out any code for exporter keys. * Feature not supported yet. * WOLFSSL_ASYNC_CRYPT - * Enables the use of asynchornous cryptographic operations. + * Enables the use of asynchronous cryptographic operations. * This is available for ciphers and certificates. * HAVE_CHACHA && HAVE_POLY1305 * Enables use of CHACHA20-POLY1305 ciphersuites. * WOLFSSL_DEBUG_TLS - * Writes out details of TLS 1.3 protocol including hanshake message buffers + * Writes out details of TLS 1.3 protocol including handshake message buffers * and key generation input and output. * WOLFSSL_EARLY_DATA * Allow 0-RTT Handshake using Early Data extensions and handshake message + * WOLFSSL_EARLY_DATA_GROUP + * Group EarlyData message with ClientHello when sending * WOLFSSL_NO_SERVER_GROUPS_EXT * Do not send the server's groups in an extension when the server's top * preference is not in client's list. @@ -60,7 +62,7 @@ * WOLFSSL_TLS13_DRAFT_23 * Conform with Draft 23 of the TLS v1.3 specification. * WOLFSSL_TLS13_MIDDLEBOX_COMPAT - * Enable middlebox compatability in the TLS 1.3 handshake. + * Enable middlebox compatibility in the TLS 1.3 handshake. * This includes sending ChangeCipherSpec before encrypted messages and * including a session id. * WOLFSSL_TLS13_SHA512 @@ -104,19 +106,6 @@ #include "libntruencrypt/ntru_crypto.h" #endif -#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG) || \ - defined(CHACHA_AEAD_TEST) || defined(WOLFSSL_SESSION_EXPORT_DEBUG) - #if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) - #if MQX_USE_IO_OLD - #include <fio.h> - #else - #include <nio.h> - #endif - #else - #include <stdio.h> - #endif -#endif - #ifdef __sun #include <sys/filio.h> #endif @@ -132,6 +121,14 @@ #error The build option HAVE_HKDF is required for TLS 1.3 #endif +#ifndef HAVE_TLS_EXTENSIONS + #ifndef _MSC_VER + #error "The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3" + #else + #pragma message("error: The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3") + #endif +#endif + /* Set ret to error value and jump to label. * @@ -443,7 +440,6 @@ hash, hashOutSz, digestAlg); } - #ifndef NO_PSK #ifdef WOLFSSL_TLS13_DRAFT_18 /* The length of the binder key label. */ @@ -524,10 +520,21 @@ */ static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Early Traffic Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->secret, - earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_EARLY_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #ifdef TLS13_SUPPORTS_EXPORTERS @@ -552,24 +559,35 @@ */ static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Early Exporter Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->secret, - earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->secret, + earlyExporterLabel, EARLY_EXPORTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, EARLY_EXPORTER_SECRET, key + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #endif #endif #ifdef WOLFSSL_TLS13_DRAFT_18 -/* The length of the client hanshake label. */ +/* The length of the client handshake label. */ #define CLIENT_HANDSHAKE_LABEL_SZ 31 -/* The client hanshake label. */ +/* The client handshake label. */ static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = "client handshake traffic secret"; #else -/* The length of the client hanshake label. */ +/* The length of the client handshake label. */ #define CLIENT_HANDSHAKE_LABEL_SZ 12 -/* The client hanshake label. */ +/* The client handshake label. */ static const byte clientHandshakeLabel[CLIENT_HANDSHAKE_LABEL_SZ + 1] = "c hs traffic"; #endif @@ -581,10 +599,21 @@ */ static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Client Handshake Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, - clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_HANDSHAKE_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #ifdef WOLFSSL_TLS13_DRAFT_18 @@ -608,10 +637,21 @@ */ static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Server Handshake Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, - serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret, + serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, SERVER_HANDSHAKE_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #ifdef WOLFSSL_TLS13_DRAFT_18 @@ -635,10 +675,21 @@ */ static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Client Traffic Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, - clientAppLabel, CLIENT_APP_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + clientAppLabel, CLIENT_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, CLIENT_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #ifdef WOLFSSL_TLS13_DRAFT_18 @@ -662,10 +713,21 @@ */ static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Server Traffic Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, - serverAppLabel, SERVER_APP_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + serverAppLabel, SERVER_APP_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, SERVER_TRAFFIC_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #ifdef TLS13_SUPPORTS_EXPORTERS @@ -690,10 +752,21 @@ */ static int DeriveExporterSecret(WOLFSSL* ssl, byte* key) { + int ret; WOLFSSL_MSG("Derive Exporter Secret"); - return DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, - exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ, - ssl->specs.mac_algorithm, 1); + ret = DeriveKey(ssl, key, -1, ssl->arrays->masterSecret, + exporterMasterLabel, EXPORTER_MASTER_LABEL_SZ, + ssl->specs.mac_algorithm, 1); +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, EXPORTER_SECRET, key, + ssl->specs.hash_size, ssl->tls13SecretCtx); + if (ret != 0) { + return TLS13_SECRET_CB_E; + } + } +#endif /* HAVE_SECRET_CALLBACK */ + return ret; } #endif @@ -859,9 +932,9 @@ #if defined(HAVE_SESSION_TICKET) /* Length of the resumption label. */ #define RESUMPTION_LABEL_SZ 10 -/* Resumption label for generating PSK assocated with the ticket. */ +/* Resumption label for generating PSK associated with the ticket. */ static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption"; -/* Derive the PSK assocated with the ticket. +/* Derive the PSK associated with the ticket. * * ssl The SSL/TLS object. * nonce The nonce to derive with. @@ -1027,7 +1100,7 @@ switch (secret) { #ifdef WOLFSSL_EARLY_DATA case early_data_key: - ret = DeriveEarlyTrafficSecret(ssl, ssl->arrays->clientSecret); + ret = DeriveEarlyTrafficSecret(ssl, ssl->clientSecret); if (ret != 0) goto end; break; @@ -1036,13 +1109,13 @@ case handshake_key: if (provision & PROVISION_CLIENT) { ret = DeriveClientHandshakeSecret(ssl, - ssl->arrays->clientSecret); + ssl->clientSecret); if (ret != 0) goto end; } if (provision & PROVISION_SERVER) { ret = DeriveServerHandshakeSecret(ssl, - ssl->arrays->serverSecret); + ssl->serverSecret); if (ret != 0) goto end; } @@ -1050,12 +1123,12 @@ case traffic_key: if (provision & PROVISION_CLIENT) { - ret = DeriveClientTrafficSecret(ssl, ssl->arrays->clientSecret); + ret = DeriveClientTrafficSecret(ssl, ssl->clientSecret); if (ret != 0) goto end; } if (provision & PROVISION_SERVER) { - ret = DeriveServerTrafficSecret(ssl, ssl->arrays->serverSecret); + ret = DeriveServerTrafficSecret(ssl, ssl->serverSecret); if (ret != 0) goto end; } @@ -1063,12 +1136,12 @@ case update_traffic_key: if (provision & PROVISION_CLIENT) { - ret = DeriveTrafficSecret(ssl, ssl->arrays->clientSecret); + ret = DeriveTrafficSecret(ssl, ssl->clientSecret); if (ret != 0) goto end; } if (provision & PROVISION_SERVER) { - ret = DeriveTrafficSecret(ssl, ssl->arrays->serverSecret); + ret = DeriveTrafficSecret(ssl, ssl->serverSecret); if (ret != 0) goto end; } @@ -1084,7 +1157,7 @@ /* Derive the client key. */ WOLFSSL_MSG("Derive Client Key"); ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, - ssl->arrays->clientSecret, writeKeyLabel, + ssl->clientSecret, writeKeyLabel, WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); if (ret != 0) goto end; @@ -1095,7 +1168,7 @@ /* Derive the server key. */ WOLFSSL_MSG("Derive Server Key"); ret = DeriveKey(ssl, &key_dig[i], ssl->specs.key_size, - ssl->arrays->serverSecret, writeKeyLabel, + ssl->serverSecret, writeKeyLabel, WRITE_KEY_LABEL_SZ, ssl->specs.mac_algorithm, 0); if (ret != 0) goto end; @@ -1106,7 +1179,7 @@ /* Derive the client IV. */ WOLFSSL_MSG("Derive Client IV"); ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, - ssl->arrays->clientSecret, writeIVLabel, + ssl->clientSecret, writeIVLabel, WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); if (ret != 0) goto end; @@ -1117,7 +1190,7 @@ /* Derive the server IV. */ WOLFSSL_MSG("Derive Server IV"); ret = DeriveKey(ssl, &key_dig[i], ssl->specs.iv_size, - ssl->arrays->serverSecret, writeIVLabel, + ssl->serverSecret, writeIVLabel, WRITE_IV_LABEL_SZ, ssl->specs.mac_algorithm, 0); if (ret != 0) goto end; @@ -1162,6 +1235,13 @@ { return (word32) XTIME(0) * 1000; } + +#elif defined(XTIME_MS) + word32 TimeNowInMilliseconds(void) + { + return (word32)XTIME_MS(0); + } + #elif defined(USE_WINDOWS_API) /* The time in milliseconds. * Used for tickets to represent difference between when first seen and when @@ -1198,6 +1278,14 @@ { return (word32)rtp_get_system_sec() * 1000; } +#elif defined(WOLFSSL_DEOS) + word32 TimeNowInMilliseconds(void) + { + const uint32_t systemTickTimeInHz = 1000000 / systemTickInMicroseconds(); + uint32_t *systemTickPtr = systemTickPointer(); + + return (word32) (*systemTickPtr/systemTickTimeInHz) * 1000; + } #elif defined(MICRIUM) /* The time in milliseconds. * Used for tickets to represent difference between when first seen and when @@ -1376,7 +1464,7 @@ * ssl The SSL/TLS object. * input The buffer holding the message data. * inOutIdx On entry, the index into the buffer of the handshake data. - * On exit, the start of the hanshake data. + * On exit, the start of the handshake data. * type Type of handshake message. * size The length of the handshake message data. * totalSz The total size of data in the buffer. @@ -1416,6 +1504,7 @@ #ifdef WOLFSSL_TLS13_DRAFT_18 rl->pvMinor = TLSv1_MINOR; #else + /* NOTE: May be TLSv1_MINOR when sending first ClientHello. */ rl->pvMinor = TLSv1_2_MINOR; #endif c16toa((word16)length, rl->length); @@ -1423,7 +1512,7 @@ /* Add handshake header to message. * - * output The buffer to write the hanshake header into. + * output The buffer to write the handshake header into. * length The length of the handshake data. * fragOffset The offset of the fragment data. (DTLS) * fragLength The length of the fragment data. (DTLS) @@ -1465,7 +1554,7 @@ #ifndef NO_CERTS -/* Add both record layer and fragement handshake header to message. +/* Add both record layer and fragment handshake header to message. * * output The buffer to write the headers into. * fragOffset The offset of the fragment data. (DTLS) @@ -1569,6 +1658,9 @@ ret = wc_Chacha_Process(ssl->encrypt.chacha, poly, poly, sizeof(poly)); if (ret != 0) return ret; + ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 1); + if (ret != 0) + return ret; /* Encrypt the plain text. */ ret = wc_Chacha_Process(ssl->encrypt.chacha, output, input, sz); if (ret != 0) { @@ -1589,6 +1681,43 @@ } #endif +#ifdef HAVE_NULL_CIPHER +/* Create authenication tag and copy data over input. + * + * ssl The SSL/TLS object. + * output The buffer to copy data into. + * May be the same pointer as input. + * input The data. + * sz The number of bytes of data. + * nonce The nonce to use with authentication. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tag The authentication tag buffer. + * returns 0 on success, otherwise failure. + */ +static int Tls13IntegrityOnly_Encrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, + const byte* nonce, + const byte* aad, word16 aadSz, byte* tag) +{ + int ret; + + /* HMAC: nonce | aad | input */ + ret = wc_HmacUpdate(ssl->encrypt.hmac, nonce, HMAC_NONCE_SZ); + if (ret == 0) + ret = wc_HmacUpdate(ssl->encrypt.hmac, aad, aadSz); + if (ret == 0) + ret = wc_HmacUpdate(ssl->encrypt.hmac, input, sz); + if (ret == 0) + ret = wc_HmacFinal(ssl->encrypt.hmac, tag); + /* Copy the input to output if not the same buffer */ + if (ret == 0 && output != input) + XMEMCPY(output, input, sz); + + return ret; +} +#endif + /* Encrypt data for TLS v1.3. * * ssl The SSL/TLS object. @@ -1642,6 +1771,7 @@ #endif #endif + #ifdef CIPHER_NONCE if (ssl->encrypt.nonce == NULL) ssl->encrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, ssl->heap, DYNAMIC_TYPE_AES_BUFFER); @@ -1650,6 +1780,7 @@ BuildTls13Nonce(ssl, ssl->encrypt.nonce, ssl->keys.aead_enc_imp_IV, CUR_ORDER); + #endif /* Advance state and proceed */ ssl->encrypt.state = CIPHER_STATE_DO; @@ -1670,9 +1801,20 @@ #endif nonceSz = AESGCM_NONCE_SZ; + #if ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, dataSz, ssl->encrypt.nonce, nonceSz, output + dataSz, macSz, aad, aadSz); + #else + ret = wc_AesGcmSetExtIV(ssl->encrypt.aes, + ssl->encrypt.nonce, nonceSz); + if (ret == 0) { + ret = wc_AesGcmEncrypt_ex(ssl->encrypt.aes, output, + input, dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + } + #endif break; #endif @@ -1687,9 +1829,20 @@ #endif nonceSz = AESCCM_NONCE_SZ; + #if ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, dataSz, ssl->encrypt.nonce, nonceSz, output + dataSz, macSz, aad, aadSz); + #else + ret = wc_AesCcmSetNonce(ssl->encrypt.aes, + ssl->encrypt.nonce, nonceSz); + if (ret == 0) { + ret = wc_AesCcmEncrypt_ex(ssl->encrypt.aes, output, + input, dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, aad, aadSz); + } + #endif break; #endif @@ -1700,6 +1853,13 @@ break; #endif + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + ret = Tls13IntegrityOnly_Encrypt(ssl, output, input, dataSz, + ssl->encrypt.nonce, aad, aadSz, output + dataSz); + break; + #endif + default: WOLFSSL_MSG("wolfSSL Encrypt programming error"); return ENCRYPT_ERROR; @@ -1725,16 +1885,20 @@ case CIPHER_STATE_END: { - #ifdef WOLFSSL_DEBUG_TLS + #ifdef WOLFSSL_DEBUG_TLS + #ifdef CIPHER_NONCE WOLFSSL_MSG("Nonce"); WOLFSSL_BUFFER(ssl->encrypt.nonce, ssl->specs.iv_size); + #endif WOLFSSL_MSG("Encrypted data"); WOLFSSL_BUFFER(output, dataSz); WOLFSSL_MSG("Authentication Tag"); WOLFSSL_BUFFER(output + dataSz, macSz); - #endif - + #endif + + #ifdef CIPHER_NONCE ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); + #endif break; } @@ -1780,6 +1944,9 @@ ret = wc_Chacha_Process(ssl->decrypt.chacha, poly, poly, sizeof(poly)); if (ret != 0) return ret; + ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 1); + if (ret != 0) + return ret; /* Set key for Poly1305. */ ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, sizeof(poly)); @@ -1805,6 +1972,48 @@ } #endif +#ifdef HAVE_NULL_CIPHER +/* Check HMAC tag and copy over input. + * + * ssl The SSL/TLS object. + * output The buffer to copy data into. + * May be the same pointer as input. + * input The data. + * sz The number of bytes of data. + * nonce The nonce to use with authentication. + * aad The additional authentication data. + * aadSz The size of the addition authentication data. + * tagIn The authentication tag data from packet. + * returns 0 on success, otherwise failure. + */ +static int Tls13IntegrityOnly_Decrypt(WOLFSSL* ssl, byte* output, + const byte* input, word16 sz, + const byte* nonce, + const byte* aad, word16 aadSz, + const byte* tagIn) +{ + int ret; + byte hmac[WC_MAX_DIGEST_SIZE]; + + /* HMAC: nonce | aad | input */ + ret = wc_HmacUpdate(ssl->decrypt.hmac, nonce, HMAC_NONCE_SZ); + if (ret == 0) + ret = wc_HmacUpdate(ssl->decrypt.hmac, aad, aadSz); + if (ret == 0) + ret = wc_HmacUpdate(ssl->decrypt.hmac, input, sz); + if (ret == 0) + ret = wc_HmacFinal(ssl->decrypt.hmac, hmac); + /* Check authentication tag matches */ + if (ret == 0 && ConstantCompare(tagIn, hmac, ssl->specs.hash_size) != 0) + ret = DECRYPT_ERROR; + /* Copy the input to output if not the same buffer */ + if (ret == 0 && output != input) + XMEMCPY(output, input, sz); + + return ret; +} +#endif + /* Decrypt data for TLS v1.3. * * ssl The SSL/TLS object. @@ -1867,6 +2076,7 @@ WOLFSSL_BUFFER(input + dataSz, macSz); #endif + #ifdef CIPHER_NONCE if (ssl->decrypt.nonce == NULL) ssl->decrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, ssl->heap, DYNAMIC_TYPE_AES_BUFFER); @@ -1875,6 +2085,7 @@ BuildTls13Nonce(ssl, ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV, PEER_ORDER); + #endif /* Advance state and proceed */ ssl->decrypt.state = CIPHER_STATE_DO; @@ -1937,6 +2148,12 @@ break; #endif + #ifdef HAVE_NULL_CIPHER + case wolfssl_cipher_null: + ret = Tls13IntegrityOnly_Decrypt(ssl, output, input, dataSz, + ssl->decrypt.nonce, aad, aadSz, input + dataSz); + break; + #endif default: WOLFSSL_MSG("wolfSSL Decrypt programming error"); return DECRYPT_ERROR; @@ -1957,13 +2174,17 @@ case CIPHER_STATE_END: { #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(ssl->decrypt.nonce, ssl->specs.iv_size); - WOLFSSL_MSG("Decrypted data"); - WOLFSSL_BUFFER(output, dataSz); + #ifdef CIPHER_NONCE + WOLFSSL_MSG("Nonce"); + WOLFSSL_BUFFER(ssl->decrypt.nonce, ssl->specs.iv_size); + #endif + WOLFSSL_MSG("Decrypted data"); + WOLFSSL_BUFFER(output, dataSz); #endif + #ifdef CIPHER_NONCE ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); + #endif break; } @@ -2108,15 +2329,15 @@ goto exit_buildmsg; } + /* The real record content type goes at the end of the data. */ + output[args->idx++] = (byte)type; + ssl->options.buildMsgState = BUILD_MSG_ENCRYPT; } FALL_THROUGH; case BUILD_MSG_ENCRYPT: { - /* The real record content type goes at the end of the data. */ - output[args->idx++] = (byte)type; - #ifdef ATOMIC_USER if (ssl->ctx->MacEncryptCb) { /* User Record Layer Callback handling */ @@ -2164,6 +2385,9 @@ /* Final cleanup */ FreeBuildMsg13Args(ssl, args); +#ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = NULL; +#endif return ret; } @@ -2175,9 +2399,9 @@ * suite Cipher suite to look for. * returns 1 when suite is found in SSL/TLS object's list and 0 otherwise. */ -static int FindSuite(WOLFSSL* ssl, byte* suite) +static int FindSuiteSSL(WOLFSSL* ssl, byte* suite) { - int i; + word16 i; for (i = 0; i < ssl->suites->suiteSz; i += 2) { if (ssl->suites->suites[i+0] == suite[0] && @@ -2202,10 +2426,10 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz) { int ret; - byte mac[WC_MAX_DIGEST_SIZE]; + byte mac[WC_MAX_DIGEST_SIZE] = {0}; Hmac cookieHmac; - byte cookieType; - byte macSz; + byte cookieType = 0; + byte macSz = 0; #if !defined(NO_SHA) && defined(NO_SHA256) cookieType = SHA; @@ -2215,6 +2439,7 @@ cookieType = WC_SHA256; macSz = WC_SHA256_DIGEST_SIZE; #endif /* NO_SHA256 */ + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); ret = wc_HmacSetKey(&cookieHmac, cookieType, ssl->buffers.tls13CookieSecret.buffer, @@ -2231,7 +2456,7 @@ } #endif -/* Restart the Hanshake hash with a hash of the previous messages. +/* Restart the handshake hash with a hash of the previous messages. * * ssl The SSL/TLS object. * returns 0 on success, otherwise failure. @@ -2240,7 +2465,7 @@ { int ret; Hashes hashes; - byte header[HANDSHAKE_HEADER_SZ]; + byte header[HANDSHAKE_HEADER_SZ] = {0}; byte* hash = NULL; byte hashSz = 0; @@ -2265,6 +2490,11 @@ #endif } hashSz = ssl->specs.hash_size; + + /* check hash */ + if (hash == NULL && hashSz > 0) + return BAD_FUNC_ARG; + AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl); WOLFSSL_MSG("Restart Hash"); @@ -2278,7 +2508,8 @@ /* Cookie Data = Hash Len | Hash | CS | KeyShare Group */ cookie[idx++] = hashSz; - XMEMCPY(cookie + idx, hash, hashSz); + if (hash) + XMEMCPY(cookie + idx, hash, hashSz); idx += hashSz; cookie[idx++] = ssl->options.cipherSuite0; cookie[idx++] = ssl->options.cipherSuite; @@ -2325,12 +2556,12 @@ int ret; byte suite[2]; - if (ssl->options.noPskDheKe && ssl->arrays->preMasterSz != 0) - return PSK_KEY_ERROR; + if (psk == NULL) + return BAD_FUNC_ARG; suite[0] = psk->cipherSuite0; suite[1] = psk->cipherSuite; - if (!FindSuite(ssl, suite)) + if (!FindSuiteSSL(ssl, suite)) return PSK_KEY_ERROR; ssl->options.cipherSuite0 = psk->cipherSuite0; @@ -2359,22 +2590,43 @@ #endif #ifndef NO_PSK if (!psk->resumption) { + #ifndef WOLFSSL_PSK_ONE_ID + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE, cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + /* Get the pre-shared key. */ - ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, - (char *)psk->identity, ssl->arrays->client_identity, - MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (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, + MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, + &cipherName); + if (GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) != 0) { + return PSK_KEY_ERROR; + } + } + else { + ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl, + (char *)psk->identity, 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) { + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { return PSK_KEY_ERROR; } - /* TODO: Callback should be able to specify ciphersuite. */ - - if (psk->cipherSuite0 != TLS13_BYTE || - psk->cipherSuite != WOLFSSL_DEF_PSK_CIPHER) { + + if (psk->cipherSuite0 != cipherSuite0 || + psk->cipherSuite != cipherSuite) { return PSK_KEY_ERROR; } - } -#endif + #else + /* PSK information loaded during setting of default TLS extensions. */ + #endif + } +#endif + + if (ssl->options.noPskDheKe) + ssl->arrays->preMasterSz = 0; /* Derive the early secret using the PSK. */ return DeriveEarlySecret(ssl); @@ -2403,8 +2655,11 @@ return SANITY_MSG_E; /* Get the size of the binders to determine where to write binders. */ - idx -= TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, - client_hello); + ret = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, + client_hello, &len); + if (ret < 0) + return ret; + idx -= len; /* Hash truncated ClientHello - up to binders. */ ret = HashOutput(ssl, output, idx, 0); @@ -2445,8 +2700,10 @@ } /* Data entered into extension, now write to message. */ - len = TLSX_PreSharedKey_WriteBinders((PreSharedKey*)ext->data, output + idx, - client_hello); + ret = TLSX_PreSharedKey_WriteBinders((PreSharedKey*)ext->data, output + idx, + client_hello, &len); + if (ret < 0) + return ret; /* Hash binders to complete the hash of the ClientHello. */ ret = HashOutputRaw(ssl, output + idx, len); @@ -2534,7 +2791,9 @@ return ret; #ifdef WOLFSSL_EARLY_DATA #ifndef NO_PSK - if (!ssl->options.resuming && ssl->options.client_psk_cb == NULL) + if (!ssl->options.resuming && + ssl->options.client_psk_tls13_cb == NULL && + ssl->options.client_psk_cb == NULL) #else if (!ssl->options.resuming) #endif @@ -2548,10 +2807,6 @@ return ret; } #endif -#ifdef HAVE_QSH - if (QSH_Init(ssl) != 0) - return MEMORY_E; -#endif /* Include length of TLS extensions. */ ret = TLSX_GetRequestSize(ssl, client_hello, &length); if (ret != 0) @@ -2653,7 +2908,11 @@ ssl->buffers.outputBuffer.length += sendSz; - ret = SendBuffered(ssl); +#ifdef WOLFSSL_EARLY_DATA_GROUP + if (ssl->earlyData == no_early_data) +#endif + ret = SendBuffered(ssl); + WOLFSSL_LEAVE("SendTls13ClientHello", ret); WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND); @@ -2752,6 +3011,7 @@ byte sessIdSz; const byte* sessId; byte b; + int foundVersion; #endif word16 totalExtSz; #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -2874,9 +3134,24 @@ return BUFFER_ERROR; #ifndef WOLFSSL_TLS13_DRAFT_18 - if (ssl->options.downgrade) - ssl->version.minor = TLSv1_2_MINOR; -#endif + /* Need to negotiate version first. */ + if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz, + *extMsgType, &foundVersion))) { + return ret; + } + if (!foundVersion) { + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Server trying to downgrade to version less than " + "TLS v1.3"); + return VERSION_ERROR; + } + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + ssl->version.minor = pv.minor; + } +#endif + /* Parse and handle extensions. */ ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, *extMsgType, NULL); @@ -2894,8 +3169,9 @@ int secretSz = SECRET_LEN; ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, &secretSz, ssl->sessionSecretCtx); - if (ret != 0 || secretSz != SECRET_LEN) + if (ret != 0 || secretSz != SECRET_LEN) { return SESSION_SECRET_CB_E; + } } #endif /* HAVE_SECRET_CALLBACK */ @@ -2954,6 +3230,19 @@ ret = SetCipherSpecs(ssl); if (ret != 0) return ret; +#ifdef HAVE_NULL_CIPHER + if (ssl->options.cipherSuite0 == ECC_BYTE && + (ssl->options.cipherSuite == TLS_SHA256_SHA256 || + ssl->options.cipherSuite == TLS_SHA384_SHA384)) { + ; + } + else +#endif + /* Check that the negotiated ciphersuite matches protocol version. */ + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + WOLFSSL_MSG("Server sent non-TLS13 cipher suite in TLS 1.3 packet"); + return INVALID_PARAMETER; + } #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifndef WOLFSSL_TLS13_DRAFT_18 @@ -3096,6 +3385,9 @@ WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_DO); WOLFSSL_ENTER("DoTls13CertificateRequest"); +#ifndef WOLFSSL_TLS13_DRAFT_18 + XMEMSET(&peerSuites, 0, sizeof(Suites)); +#endif #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName(ssl, "CertificateRequest"); if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); @@ -3135,7 +3427,11 @@ *inOutIdx += OPAQUE16_LEN; if ((*inOutIdx - begin) + len > size) return BUFFER_ERROR; - PickHashSigAlgo(ssl, input + *inOutIdx, len); + if (PickHashSigAlgo(ssl, input + *inOutIdx, len) != 0 && + ssl->buffers.certificate && ssl->buffers.certificate->buffer && + ssl->buffers.key && ssl->buffers.key->buffer) { + return INVALID_PARAMETER; + } *inOutIdx += len; /* Length of certificate authority data. */ @@ -3189,15 +3485,25 @@ return ret; } *inOutIdx += len; - - PickHashSigAlgo(ssl, peerSuites.hashSigAlgo, peerSuites.hashSigAlgoSz); #endif if (ssl->buffers.certificate && ssl->buffers.certificate->buffer && - ssl->buffers.key && ssl->buffers.key->buffer) + ((ssl->buffers.key && ssl->buffers.key->buffer) + #ifdef HAVE_PK_CALLBACKS + || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) + #endif + )) { +#ifndef WOLFSSL_TLS13_DRAFT_18 + if (PickHashSigAlgo(ssl, peerSuites.hashSigAlgo, + peerSuites.hashSigAlgoSz) != 0) { + return INVALID_PARAMETER; + } +#endif ssl->options.sendVerify = SEND_CERT; - else + } + else { ssl->options.sendVerify = SEND_BLANK_CERT; + } /* This message is always encrypted so add encryption padding. */ *inOutIdx += ssl->keys.padSz; @@ -3221,7 +3527,9 @@ { byte suites[WOLFSSL_MAX_SUITE_SZ]; int suiteSz = 0; - int i, j; + word16 i, j; + + XMEMSET(suites, 0, WOLFSSL_MAX_SUITE_SZ); for (i = 0; i < ssl->suites->suiteSz; i += 2) { for (j = 0; j < peerSuites->suiteSz; j += 2) { @@ -3263,15 +3571,19 @@ int pskCnt = 0; TLSX* extEarlyData; #endif +#ifndef NO_PSK + const char* cipherName = NULL; + byte cipherSuite0 = TLS13_BYTE; + byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER; +#endif WOLFSSL_ENTER("DoPreSharedKeys"); ext = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); if (ext == NULL) { -#ifdef WOLFSSL_EARLY_DATA - ssl->earlyData = no_early_data; -#endif - return 0; + /* 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. */ @@ -3284,8 +3596,10 @@ /* Find the pre-shared key extension and calculate hash of truncated * ClientHello for binders. */ - bindersLen = TLSX_PreSharedKey_GetSizeBinders((PreSharedKey*)ext->data, - client_hello); + 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); @@ -3300,6 +3614,9 @@ #endif #ifndef NO_PSK + if (current->identityLen > MAX_PSK_ID_LEN) { + return BUFFER_ERROR; + } XMEMCPY(ssl->arrays->client_identity, current->identity, current->identityLen); ssl->arrays->client_identity[current->identityLen] = '\0'; @@ -3332,7 +3649,7 @@ */ suite[0] = ssl->session.cipherSuite0; suite[1] = ssl->session.cipherSuite; - if (!FindSuite(ssl, suite)) { + if (!FindSuiteSSL(ssl, suite)) { current = current->next; continue; } @@ -3371,17 +3688,23 @@ else #endif #ifndef NO_PSK - if (ssl->options.server_psk_cb != NULL && - (ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + 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)) != 0) { + MAX_PSK_KEY_LEN, &cipherName)) != 0 && + GetCipherSuiteFromName(cipherName, &cipherSuite0, + &cipherSuite) == 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; - /* TODO: Callback should be able to specify ciphersuite. */ - - suite[0] = TLS13_BYTE; - suite[1] = WOLFSSL_DEF_PSK_CIPHER; - if (!FindSuite(ssl, suite)) { + + /* Check whether PSK ciphersuite is in SSL. */ + suite[0] = cipherSuite0; + suite[1] = cipherSuite; + if (!FindSuiteSSL(ssl, suite)) { current = current->next; continue; } @@ -3393,9 +3716,9 @@ if (current->ticketAge != ssl->session.ticketAdd) return PSK_KEY_ERROR; - /* Check whether PSK ciphersuite is in SSL. */ - ssl->options.cipherSuite0 = TLS13_BYTE; - ssl->options.cipherSuite = WOLFSSL_DEF_PSK_CIPHER; + /* Set PSK ciphersuite into SSL. */ + ssl->options.cipherSuite0 = cipherSuite0; + ssl->options.cipherSuite = cipherSuite; ret = SetCipherSpecs(ssl); if (ret != 0) return ret; @@ -3440,6 +3763,11 @@ break; } + /* Hash the rest of the ClientHello. */ + ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); + if (ret != 0) + return ret; + if (current == NULL) { #ifdef WOLFSSL_PSK_ID_PROTECTION #ifndef NO_CERTS @@ -3452,11 +3780,6 @@ #endif } - /* Hash the rest of the ClientHello. */ - ret = HashInputRaw(ssl, input + helloSz - bindersLen, bindersLen); - if (ret != 0) - return ret; - #ifdef WOLFSSL_EARLY_DATA extEarlyData = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA); if (extEarlyData != NULL) { @@ -3506,6 +3829,7 @@ if ((modes & (1 << PSK_KE)) == 0) return PSK_KEY_ERROR; ssl->options.noPskDheKe = 1; + ssl->arrays->preMasterSz = 0; } *usingPSK = 1; @@ -3527,10 +3851,10 @@ static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz) { int ret; - byte mac[WC_MAX_DIGEST_SIZE]; + byte mac[WC_MAX_DIGEST_SIZE] = {0}; Hmac cookieHmac; - byte cookieType; - byte macSz; + byte cookieType = 0; + byte macSz = 0; #if !defined(NO_SHA) && defined(NO_SHA256) cookieType = SHA; @@ -3544,6 +3868,7 @@ if (cookieSz < ssl->specs.hash_size + macSz) return HRR_COOKIE_ERROR; cookieSz -= macSz; + XMEMSET(&cookieHmac, 0, sizeof(Hmac)); ret = wc_HmacSetKey(&cookieHmac, cookieType, ssl->buffers.tls13CookieSecret.buffer, @@ -3586,7 +3911,7 @@ HRR_COOKIE_HDR_SZ) #endif -/* Restart the Hanshake hash from the cookie value. +/* Restart the handshake hash from the cookie value. * * ssl SSL/TLS object. * cookie Cookie data from client. @@ -3594,8 +3919,8 @@ */ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie) { - byte header[HANDSHAKE_HEADER_SZ]; - byte hrr[MAX_HRR_SZ]; + byte header[HANDSHAKE_HEADER_SZ] = {0}; + byte hrr[MAX_HRR_SZ] = {0}; int hrrIdx; word32 idx; byte hashSz; @@ -3638,13 +3963,6 @@ idx += hashSz; hrrIdx = HANDSHAKE_HEADER_SZ; - /* TODO: [TLS13] Replace existing code with code in comment. - * Use the TLS v1.3 draft version for now. - * - * Change to: - * hrr[hrrIdx++] = ssl->version.major; - * hrr[hrrIdx++] = ssl->version.minor; - */ /* The negotiated protocol version. */ hrr[hrrIdx++] = TLS_DRAFT_MAJOR; hrr[hrrIdx++] = TLS_DRAFT_MINOR; @@ -3703,13 +4021,12 @@ hrrIdx += 2; c16toa(OPAQUE16_LEN, hrr + hrrIdx); hrrIdx += 2; - /* TODO: [TLS13] Change to ssl->version.major and minor once final. */ - #ifdef WOLFSSL_TLS13_FINAL + #ifdef WOLFSSL_TLS13_DRAFT + hrr[hrrIdx++] = TLS_DRAFT_MAJOR; + hrr[hrrIdx++] = TLS_DRAFT_MINOR; + #else hrr[hrrIdx++] = ssl->version.major; hrr[hrrIdx++] = ssl->version.minor; - #else - hrr[hrrIdx++] = TLS_DRAFT_MAJOR; - hrr[hrrIdx++] = TLS_DRAFT_MINOR; #endif #endif /* Mandatory Cookie Extension */ @@ -3733,6 +4050,65 @@ } #endif +/* Do SupportedVersion extension for TLS v1.3+ otherwise it is not. + * + * ssl The SSL/TLS object. + * input The message buffer. + * i The index into the message buffer of ClientHello. + * helloSz The length of the current handshake message. + * returns 0 on success and otherwise failure. + */ +static int DoTls13SupportedVersions(WOLFSSL* ssl, const byte* input, word32 i, + word32 helloSz, int* wantDowngrade) +{ + int ret; + byte b; + word16 suiteSz; + word16 totalExtSz; + int foundVersion = 0; + + /* Client random */ + i += RAN_LEN; + /* Session id - not used in TLS v1.3 */ + b = input[i++]; + if (i + b > helloSz) { + return BUFFER_ERROR; + } + i += b; + /* Cipher suites */ + if (i + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(input + i, &suiteSz); + i += OPAQUE16_LEN; + if (i + suiteSz + 1 > helloSz) + return BUFFER_ERROR; + i += suiteSz; + /* Compression */ + b = input[i++]; + if (i + b > helloSz) + return BUFFER_ERROR; + i += b; + + /* TLS 1.3 must have extensions */ + if (i < helloSz) { + if (i + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if (totalExtSz != helloSz - i) + return BUFFER_ERROR; + + /* Need to negotiate version first. */ + if ((ret = TLSX_ParseVersion(ssl, (byte*)input + i, totalExtSz, + client_hello, &foundVersion))) { + return ret; + } + } + *wantDowngrade = !foundVersion || !IsAtLeastTLSv1_3(ssl->version); + + return 0; +} + /* Handle a ClientHello handshake message. * If the protocol version in the message is not TLS v1.3 or higher, use * DoClientHello() @@ -3750,21 +4126,22 @@ word32 helloSz) { int ret = VERSION_ERROR; - byte b; + byte b = 0; ProtocolVersion pv; Suites clSuites; word32 i = *inOutIdx; word32 begin = i; word16 totalExtSz = 0; int usingPSK = 0; - byte sessIdSz; -#ifndef WOLFSSL_NO_TLS12 - int bogusID = 0; -#endif + byte sessIdSz = 0; + int wantDowngrade = 0; WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); WOLFSSL_ENTER("DoTls13ClientHello"); + XMEMSET(&pv, 0, sizeof(ProtocolVersion)); + XMEMSET(&clSuites, 0, sizeof(Suites)); + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); @@ -3778,21 +4155,54 @@ XMEMCPY(&pv, input + i, OPAQUE16_LEN); ssl->chVersion = pv; /* store */ i += OPAQUE16_LEN; + if (pv.major < SSLv3_MAJOR) { + WOLFSSL_MSG("Legacy version field contains unsupported value"); + #ifdef WOLFSSL_MYSQL_COMPATIBLE + SendAlert(ssl, alert_fatal, wc_protocol_version); + #else + SendAlert(ssl, alert_fatal, protocol_version); + #endif + return INVALID_PARAMETER; + } /* Legacy protocol version cannot negotiate TLS 1.3 or higher. */ - if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_3_MINOR) + if (pv.major > SSLv3_MAJOR || (pv.major == SSLv3_MAJOR && + pv.minor >= TLSv1_3_MINOR)) { + pv.major = SSLv3_MAJOR; pv.minor = TLSv1_2_MINOR; - + wantDowngrade = 1; + ssl->version.minor = pv.minor; + } + /* Legacy version must be [ SSLv3_MAJOR, TLSv1_2_MINOR ] for TLS v1.3 */ + else if (pv.major == SSLv3_MAJOR && pv.minor < TLSv1_2_MINOR) { + wantDowngrade = 1; + ssl->version.minor = pv.minor; + } + else { + ret = DoTls13SupportedVersions(ssl, input + begin, i - begin, helloSz, + &wantDowngrade); + if (ret < 0) + return ret; + } + if (wantDowngrade) { #ifndef WOLFSSL_NO_TLS12 - if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor < TLSv1_3_MINOR) + if (!ssl->options.downgrade) { + WOLFSSL_MSG("Client trying to connect with lesser version than " + "TLS v1.3"); + return VERSION_ERROR; + } + + if (pv.minor < ssl->options.minDowngrade) + return VERSION_ERROR; + + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) + return ret; return DoClientHello(ssl, input, inOutIdx, helloSz); -#endif - -#ifdef HAVE_SESSION_TICKET - if (ssl->options.downgrade) { - if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) - return ret; - } -#endif +#else + WOLFSSL_MSG("Client trying to connect with lesser version than " + "TLS v1.3"); + return VERSION_ERROR; +#endif + } /* Client random */ XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); @@ -3815,17 +4225,16 @@ if (sessIdSz != ID_LEN && sessIdSz != 0) return INVALID_PARAMETER; #endif + + if (sessIdSz + i > helloSz) { + return BUFFER_ERROR; + } + ssl->session.sessionIDSz = sessIdSz; if (sessIdSz == ID_LEN) { XMEMCPY(ssl->session.sessionID, input + i, sessIdSz); i += ID_LEN; } -#ifndef WOLFSSL_NO_TLS12 - #ifdef HAVE_SESSION_TICKET - if (sessIdSz > 0 && sessIdSz < ID_LEN) - bogusID = 1; - #endif -#endif /* Cipher suites */ if ((i - begin) + OPAQUE16_LEN > helloSz) @@ -3841,6 +4250,26 @@ i += clSuites.suiteSz; clSuites.hashSigAlgoSz = 0; +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + ret = FindSuite(&clSuites, 0, TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + if (ret == SUITES_ERROR) + return BUFFER_ERROR; + if (ret >= 0) { + TLSX* extension; + + /* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */ + ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap); + if (ret != WOLFSSL_SUCCESS) + return ret; + + extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (extension) { + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; + ssl->secure_renegotiation->enabled = 1; + } + } +#endif /* HAVE_SERVER_RENEGOTIATION_INFO */ + /* Compression */ b = input[i++]; if ((i - begin) + b > helloSz) @@ -3855,27 +4284,26 @@ return INVALID_PARAMETER; } - if ((i - begin) < helloSz) { - if ((i - begin) + OPAQUE16_LEN > helloSz) - return BUFFER_ERROR; - ato16(&input[i], &totalExtSz); - i += OPAQUE16_LEN; - if ((i - begin) + totalExtSz > helloSz) - return BUFFER_ERROR; - - #ifdef HAVE_QSH - QSH_Init(ssl); - #endif - - /* Auto populate extensions supported unless user defined. */ - if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) - return ret; - - /* Parse extensions */ - if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, + /* Extensions */ + if ((i - begin) == helloSz) + return BUFFER_ERROR; + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + /* Auto populate extensions supported unless user defined. */ + if ((ret = TLSX_PopulateExtensions(ssl, 1)) != 0) + return ret; + + /* Parse extensions */ + if ((ret = TLSX_Parse(ssl, (byte*)input + i, totalExtSz, client_hello, &clSuites))) { - return ret; - } + return ret; + } #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ defined(WOLFSSL_HAPROXY) @@ -3883,53 +4311,36 @@ return ret; ssl->options.side = WOLFSSL_SERVER_END; #endif /* OPENSSL_ALL || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ - } i += totalExtSz; *inOutIdx = i; - if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) { - if (!ssl->options.downgrade) { - WOLFSSL_MSG("Client trying to connect with lesser version than " - "TLS v1.3"); - return VERSION_ERROR; - } - - if (pv.minor < ssl->options.minDowngrade) - return VERSION_ERROR; - ssl->version.minor = pv.minor; - } - ssl->options.sendVerify = SEND_CERT; ssl->options.clientState = CLIENT_HELLO_COMPLETE; ssl->options.haveSessionId = 1; - if (IsAtLeastTLSv1_3(ssl->version)) { #if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE) - if (ssl->options.sendCookie && + if (ssl->options.sendCookie && ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { - TLSX* ext; - - if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL) - return HRR_COOKIE_ERROR; - /* Ensure the cookie came from client and isn't the one in the - * response - HelloRetryRequest. - */ - if (ext->resp == 1) - return HRR_COOKIE_ERROR; - ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data); - if (ret != 0) - return ret; - } -#endif - -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - if (ssl->options.downgrade) { - if ((ret = InitHandshakeHashes(ssl)) != 0) - return ret; - } - + TLSX* ext; + + if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL) + return HRR_COOKIE_ERROR; + /* Ensure the cookie came from client and isn't the one in the + * response - HelloRetryRequest. + */ + if (ext->resp == 1) + return HRR_COOKIE_ERROR; + ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data); + if (ret != 0) + return ret; + } +#endif + +#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); @@ -3937,67 +4348,62 @@ ret = DoPreSharedKeys(ssl, input + begin, helloSz, &usingPSK); if (ret != 0) return ret; -#endif - } -#ifndef WOLFSSL_NO_TLS12 - else if (ssl->options.resuming) { - ret = HandleTlsResumption(ssl, bogusID, &clSuites); - if (ret != 0) + } + else +#endif + { +#ifdef WOLFSSL_EARLY_DATA + ssl->earlyData = no_early_data; +#endif + if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) return ret; - /* Check wheter resuming has been chosen */ - if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) { - WOLFSSL_LEAVE("DoTls13ClientHello", ret); - WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); - + + } + + if (!usingPSK) { + if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { + WOLFSSL_MSG("Client did not send a KeyShare extension"); + SendAlert(ssl, alert_fatal, missing_extension); + return INCOMPLETE_DATA; + } + if (TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS) == NULL) { + WOLFSSL_MSG("Client did not send a SignatureAlgorithms extension"); + SendAlert(ssl, alert_fatal, missing_extension); + return INCOMPLETE_DATA; + } + + if ((ret = MatchSuite(ssl, &clSuites)) < 0) { + WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); + SendAlert(ssl, alert_fatal, handshake_failure); return ret; } - } -#else - else { - WOLFSSL_MSG("Negotiated lesser version than TLS v1.3"); - return VERSION_ERROR; - } -#endif - - if (!usingPSK) { - if ((ret = MatchSuite(ssl, &clSuites)) < 0) { - WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); - return ret; + +#ifdef HAVE_NULL_CIPHER + if (ssl->options.cipherSuite0 == ECC_BYTE && + (ssl->options.cipherSuite == TLS_SHA256_SHA256 || + ssl->options.cipherSuite == TLS_SHA384_SHA384)) { + ; } - + else +#endif /* Check that the negotiated ciphersuite matches protocol version. */ - if (IsAtLeastTLSv1_3(ssl->version)) { - if (ssl->options.cipherSuite0 != TLS13_BYTE) { - WOLFSSL_MSG("Negotiated ciphersuite from lesser version than " - "TLS v1.3"); - return VERSION_ERROR; - } + if (ssl->options.cipherSuite0 != TLS13_BYTE) { + WOLFSSL_MSG("Negotiated ciphersuite from lesser version than " + "TLS v1.3"); + SendAlert(ssl, alert_fatal, handshake_failure); + return VERSION_ERROR; } - /* VerifyServerSuite handles when version is less than 1.3 */ #ifdef HAVE_SESSION_TICKET if (ssl->options.resuming) { ssl->options.resuming = 0; XMEMSET(ssl->arrays->psk_key, 0, ssl->specs.hash_size); - /* May or may not have done any hashing. */ - if ((ret = InitHandshakeHashes(ssl)) != 0) - return ret; } #endif -#ifdef HAVE_SESSION_TICKET - if (IsAtLeastTLSv1_3(ssl->version) || !ssl->options.downgrade) -#endif - { - if ((ret = HashInput(ssl, input + begin, helloSz)) != 0) - return ret; - } - - if (IsAtLeastTLSv1_3(ssl->version)) { - /* Derive early secret for handshake secret. */ - if ((ret = DeriveEarlySecret(ssl)) != 0) - return ret; - } + /* Derive early secret for handshake secret. */ + if ((ret = DeriveEarlySecret(ssl)) != 0) + return ret; } WOLFSSL_LEAVE("DoTls13ClientHello", ret); @@ -4044,16 +4450,9 @@ /* Get position in output buffer to write new message to. */ output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; - /* Add record and hanshake headers. */ + /* Add record and handshake headers. */ AddTls13Headers(output, length, hello_retry_request, ssl); - /* TODO: [TLS13] Replace existing code with code in comment. - * Use the TLS v1.3 draft version for now. - * - * Change to: - * output[idx++] = ssl->version.major; - * output[idx++] = ssl->version.minor; - */ /* The negotiated protocol version. */ output[idx++] = TLS_DRAFT_MAJOR; output[idx++] = TLS_DRAFT_MINOR; @@ -4109,6 +4508,7 @@ #ifndef WOLFSSL_TLS13_DRAFT_18 if (extMsgType == hello_retry_request) { + WOLFSSL_MSG("wolfSSL Doing HelloRetryRequest"); if ((ret = RestartHandshakeHash(ssl)) < 0) return ret; } @@ -4144,13 +4544,6 @@ AddTls13Headers(output, length, server_hello, ssl); #ifdef WOLFSSL_TLS13_DRAFT_18 - /* TODO: [TLS13] Replace existing code with code in comment. - * Use the TLS v1.3 draft version for now. - * - * Change to: - * output[idx++] = ssl->version.major; - * output[idx++] = ssl->version.minor; - */ /* The negotiated protocol version. */ output[idx++] = TLS_DRAFT_MAJOR; output[idx++] = TLS_DRAFT_MINOR; @@ -4223,7 +4616,11 @@ ssl->options.serverState = SERVER_HELLO_COMPLETE; #endif +#ifdef WOLFSSL_TLS13_DRAFT_18 if (!ssl->options.groupMessages) +#else + if (!ssl->options.groupMessages || extMsgType != server_hello) +#endif ret = SendBuffered(ssl); WOLFSSL_LEAVE("SendTls13ServerHello", ret); @@ -4473,7 +4870,8 @@ #endif /* NO_WOLFSSL_SERVER */ #ifndef NO_CERTS -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) /* Encode the signature algorithm into buffer. * * hashalgo The hash algorithm. @@ -4497,6 +4895,14 @@ (void)hashAlgo; break; #endif +#ifdef HAVE_ED448 + /* ED448: 0x0808 */ + case ed448_sa_algo: + output[0] = ED448_SA_MAJOR; + output[1] = ED448_SA_MINOR; + (void)hashAlgo; + break; +#endif #ifndef NO_RSA /* PSS signatures: 0x080[4-6] */ case rsa_pss_sa_algo: @@ -4504,7 +4910,6 @@ output[1] = hashAlgo; break; #endif - /* ED448: 0x0808 */ } } @@ -4512,32 +4917,47 @@ * * input The encoded signature algorithm. * hashalgo The hash algorithm. - * hsType The signature type. + * hsType The signature type. + * returns INVALID_PARAMETER if not recognized and 0 otherwise. */ -static WC_INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) +static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, + byte* hsType) { + int ret = 0; + switch (input[0]) { case NEW_SA_MAJOR: /* PSS signatures: 0x080[4-6] */ - if (input[1] <= sha512_mac) { + if (input[1] >= sha256_mac && input[1] <= sha512_mac) { *hsType = input[0]; *hashAlgo = input[1]; } #ifdef HAVE_ED25519 /* ED25519: 0x0807 */ - if (input[1] == ED25519_SA_MINOR) { + else if (input[1] == ED25519_SA_MINOR) { *hsType = ed25519_sa_algo; /* Hash performed as part of sign/verify operation. */ *hashAlgo = sha512_mac; } #endif + #ifdef HAVE_ED448 /* ED448: 0x0808 */ + else if (input[1] == ED448_SA_MINOR) { + *hsType = ed448_sa_algo; + /* Hash performed as part of sign/verify operation. */ + *hashAlgo = sha512_mac; + } + #endif + else + ret = INVALID_PARAMETER; break; default: *hashAlgo = input[0]; *hsType = input[1]; break; } + + return ret; } /* Get the hash of the messages so far. @@ -4937,6 +5357,7 @@ if (ret < 0) return ret; + extSz = 0; ret = TLSX_WriteResponse(ssl, ssl->buffers.certExts->buffer, certificate, &extSz); if (ret < 0) @@ -5114,9 +5535,6 @@ typedef struct Scv13Args { byte* output; /* not allocated */ -#ifndef NO_RSA - byte* verifySig; -#endif byte* verify; /* not allocated */ word32 idx; word32 sigLen; @@ -5134,12 +5552,6 @@ (void)ssl; -#ifndef NO_RSA - if (args->verifySig) { - XFREE(args->verifySig, ssl->heap, DYNAMIC_TYPE_SIGNATURE); - args->verifySig = NULL; - } -#endif if (args->sigData) { XFREE(args->sigData, ssl->heap, DYNAMIC_TYPE_SIGNATURE); args->sigData = NULL; @@ -5198,7 +5610,7 @@ return 0; /* sent blank cert, can't verify */ } - args->sendSz = MAX_CERT_VERIFY_SZ; + args->sendSz = MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA; /* Always encrypted. */ args->sendSz += MAX_MSG_EXTRA; @@ -5250,15 +5662,28 @@ else if (ssl->hsType == DYNAMIC_TYPE_ED25519) args->sigAlgo = ed25519_sa_algo; #endif + #ifdef HAVE_ED448 + else if (ssl->hsType == DYNAMIC_TYPE_ED448) + args->sigAlgo = ed448_sa_algo; + #endif EncodeSigAlg(ssl->suites->hashAlgo, args->sigAlgo, args->verify); + if (ssl->hsType == DYNAMIC_TYPE_RSA) { + int sigLen = MAX_SIG_DATA_SZ; + if (args->length > MAX_SIG_DATA_SZ) + sigLen = args->length; + args->sigData = (byte*)XMALLOC(sigLen, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + } + else { + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + } + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_scv); + } + /* Create the data to be signed. */ - args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); - if (args->sigData == NULL) { - ERROR_OUT(MEMORY_E, exit_scv); - } - ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); if (ret != 0) goto exit_scv; @@ -5266,9 +5691,9 @@ #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { /* build encoded signature buffer */ - sig->length = MAX_ENCODED_SIG_SZ; + sig->length = WC_MAX_DIGEST_SIZE; sig->buffer = (byte*)XMALLOC(sig->length, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); + DYNAMIC_TYPE_SIGNATURE); if (sig->buffer == NULL) { ERROR_OUT(MEMORY_E, exit_scv); } @@ -5304,7 +5729,16 @@ } sig->length = ED25519_SIG_SIZE; } - #endif /* HAVE_ECC */ + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ret = Ed448CheckPubKey(ssl); + if (ret < 0) { + ERROR_OUT(ret, exit_scv); + } + sig->length = ED448_SIG_SIZE; + } + #endif /* HAVE_ED448 */ /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -5315,9 +5749,10 @@ { #ifdef HAVE_ECC if (ssl->hsType == DYNAMIC_TYPE_ECC) { + ret = EccSign(ssl, args->sigData, args->sigDataSz, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - &sig->length, (ecc_key*)ssl->hsKey, + (word32*)&sig->length, (ecc_key*)ssl->hsKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.key #else @@ -5331,26 +5766,45 @@ if (ssl->hsType == DYNAMIC_TYPE_ED25519) { ret = Ed25519Sign(ssl, args->sigData, args->sigDataSz, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - &sig->length, (ed25519_key*)ssl->hsKey, + (word32*)&sig->length, (ed25519_key*)ssl->hsKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.key #else NULL #endif ); - args->length = sig->length; + args->length = (word16)sig->length; + } + #endif + #ifdef HAVE_ED448 + if (ssl->hsType == DYNAMIC_TYPE_ED448) { + ret = Ed448Sign(ssl, args->sigData, args->sigDataSz, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + (word32*)&sig->length, (ed448_key*)ssl->hsKey, + #ifdef HAVE_PK_CALLBACKS + ssl->buffers.key + #else + NULL + #endif + ); + args->length = (word16)sig->length; } #endif #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { - - ret = RsaSign(ssl, sig->buffer, sig->length, + ret = RsaSign(ssl, sig->buffer, (word32)sig->length, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigLen, args->sigAlgo, ssl->suites->hashAlgo, (RsaKey*)ssl->hsKey, ssl->buffers.key ); - args->length = (word16)args->sigLen; + if (ret == 0) { + args->length = (word16)args->sigLen; + + XMEMCPY(args->sigData, + args->verify + HASH_SIG_SIZE + VERIFY_HEADER, + args->sigLen); + } } #endif /* !NO_RSA */ @@ -5371,20 +5825,9 @@ { #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { - if (args->verifySig == NULL) { - args->verifySig = (byte*)XMALLOC(args->sigLen, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); - if (args->verifySig == NULL) { - ERROR_OUT(MEMORY_E, exit_scv); - } - XMEMCPY(args->verifySig, - args->verify + HASH_SIG_SIZE + VERIFY_HEADER, - args->sigLen); - } - /* check for signature faults */ - ret = VerifyRsaSign(ssl, args->verifySig, args->sigLen, - sig->buffer, sig->length, args->sigAlgo, + ret = VerifyRsaSign(ssl, args->sigData, args->sigLen, + sig->buffer, (word32)sig->length, args->sigAlgo, ssl->suites->hashAlgo, (RsaKey*)ssl->hsKey, ssl->buffers.key ); @@ -5511,7 +5954,8 @@ return ret; } -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) typedef struct Dcv13Args { byte* output; /* not allocated */ @@ -5610,7 +6054,10 @@ if ((args->idx - args->begin) + ENUM_LEN + ENUM_LEN > totalSz) { ERROR_OUT(BUFFER_ERROR, exit_dcv); } - DecodeSigAlg(input + args->idx, &args->hashAlgo, &args->sigAlgo); + ret = DecodeTls13SigAlg(input + args->idx, &args->hashAlgo, + &args->sigAlgo); + if (ret < 0) + goto exit_dcv; args->idx += OPAQUE16_LEN; /* Signature length. */ @@ -5633,6 +6080,11 @@ WOLFSSL_MSG("Oops, peer sent ED25519 key but not in verify"); } #endif + #ifdef HAVE_ED448 + if (args->sigAlgo == ed448_sa_algo && !ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Oops, peer sent ED448 key but not in verify"); + } + #endif #ifdef HAVE_ECC if (args->sigAlgo == ecc_dsa_sa_algo && !ssl->peerEccDsaKeyPresent) { @@ -5640,8 +6092,11 @@ } #endif #ifndef NO_RSA - if ((args->sigAlgo == rsa_sa_algo || - args->sigAlgo == rsa_pss_sa_algo) && + if (args->sigAlgo == rsa_sa_algo) { + WOLFSSL_MSG("Oops, peer sent PKCS#1.5 signature"); + ERROR_OUT(INVALID_PARAMETER, exit_dcv); + } + if (args->sigAlgo == rsa_pss_sa_algo && (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { WOLFSSL_MSG("Oops, peer sent RSA key but not in verify"); } @@ -5660,7 +6115,7 @@ WOLFSSL_MSG("Doing ECC peer cert verify"); args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); + DYNAMIC_TYPE_SIGNATURE); if (args->sigData == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); } @@ -5681,7 +6136,7 @@ WOLFSSL_MSG("Doing ED25519 peer cert verify"); args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, - DYNAMIC_TYPE_SIGNATURE); + DYNAMIC_TYPE_SIGNATURE); if (args->sigData == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); } @@ -5690,6 +6145,20 @@ ret = 0; } #endif + #ifdef HAVE_ED448 + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + + args->sigData = (byte*)XMALLOC(MAX_SIG_DATA_SZ, ssl->heap, + DYNAMIC_TYPE_SIGNATURE); + if (args->sigData == NULL) { + ERROR_OUT(MEMORY_E, exit_dcv); + } + + CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = 0; + } + #endif /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_DO; @@ -5699,11 +6168,10 @@ case TLS_ASYNC_DO: { #ifndef NO_RSA - if (args->sigAlgo == rsa_sa_algo || - args->sigAlgo == rsa_pss_sa_algo) { + if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { WOLFSSL_MSG("Doing RSA peer cert verify"); - ret = RsaVerify(ssl, sig->buffer, sig->length, &args->output, + ret = RsaVerify(ssl, sig->buffer, (word32)sig->length, &args->output, args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS &ssl->buffers.peerRsaKey @@ -5730,6 +6198,11 @@ NULL #endif ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ECC, (void**)&ssl->peerEccDsaKey); + ssl->peerEccDsaKeyPresent = 0; + } } #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 @@ -5745,6 +6218,33 @@ NULL #endif ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ED25519, + (void**)&ssl->peerEd25519Key); + ssl->peerEd25519KeyPresent = 0; + } + } + #endif + #ifdef HAVE_ED448 + if (ssl->peerEd448KeyPresent) { + WOLFSSL_MSG("Doing ED448 peer cert verify"); + + ret = Ed448Verify(ssl, input + args->idx, args->sz, + args->sigData, args->sigDataSz, + ssl->peerEd448Key, + #ifdef HAVE_PK_CALLBACKS + &ssl->buffers.peerEd448Key + #else + NULL + #endif + ); + + if (ret >= 0) { + FreeKey(ssl, DYNAMIC_TYPE_ED448, + (void**)&ssl->peerEd448Key); + ssl->peerEd448KeyPresent = 0; + } } #endif @@ -5766,6 +6266,9 @@ args->output, args->sendSz); if (ret != 0) goto exit_dcv; + + FreeKey(ssl, DYNAMIC_TYPE_RSA, (void**)&ssl->peerRsaKey); + ssl->peerRsaKeyPresent = 0; } #endif /* !NO_RSA */ @@ -5805,14 +6308,14 @@ #ifdef WOLFSSL_ASYNC_CRYPT /* Handle async operation */ if (ret == WC_PENDING_E) { - /* Mark message as not recevied so it can process again */ + /* Mark message as not received so it can process again */ ssl->msgsReceived.got_certificate_verify = 0; return ret; } else #endif /* WOLFSSL_ASYNC_CRYPT */ - if (ret != 0) + if (ret != 0 && ret != INVALID_PARAMETER) SendAlert(ssl, alert_fatal, decrypt_error); /* Final cleanup */ @@ -5850,7 +6353,7 @@ return BUFFER_E; if (ssl->options.handShakeDone) { - ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret, + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, ssl->keys.client_write_MAC_secret); if (ret != 0) return ret; @@ -5861,12 +6364,12 @@ /* All the handshake messages have been received to calculate * client and server finished keys. */ - ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret, + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, ssl->keys.client_write_MAC_secret); if (ret != 0) return ret; - ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret, + ret = DeriveFinishedSecret(ssl, ssl->serverSecret, ssl->keys.server_write_MAC_secret); if (ret != 0) return ret; @@ -5964,7 +6467,7 @@ /* make finished hashes */ if (ssl->options.handShakeDone) { - ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret, + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, ssl->keys.client_write_MAC_secret); if (ret != 0) return ret; @@ -5977,12 +6480,12 @@ /* All the handshake messages have been done to calculate client and * server finished keys. */ - ret = DeriveFinishedSecret(ssl, ssl->arrays->clientSecret, + ret = DeriveFinishedSecret(ssl, ssl->clientSecret, ssl->keys.client_write_MAC_secret); if (ret != 0) return ret; - ret = DeriveFinishedSecret(ssl, ssl->arrays->serverSecret, + ret = DeriveFinishedSecret(ssl, ssl->serverSecret, ssl->keys.server_write_MAC_secret); if (ret != 0) return ret; @@ -5999,11 +6502,12 @@ if (sendSz < 0) return BUILD_MSG_ERROR; - if (!ssl->options.resuming) { #ifndef NO_SESSION_CACHE + if (!ssl->options.resuming && (ssl->options.side == WOLFSSL_SERVER_END || + (ssl->options.side == WOLFSSL_SERVER_END && ssl->arrays != NULL))) { AddSession(ssl); /* just try */ -#endif - } + } +#endif #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); @@ -6180,7 +6684,7 @@ switch (input[i]) { case update_not_requested: - /* This message in response to any oustanding request. */ + /* This message in response to any outstanding request. */ ssl->keys.keyUpdateRespond = 0; ssl->keys.updateResponseReq = 0; break; @@ -6190,7 +6694,6 @@ break; default: return INVALID_PARAMETER; - break; } /* Move index to byte after message. */ @@ -6294,7 +6797,7 @@ return BUFFER_ERROR; if (ssl->earlyData == no_early_data) { - WOLFSSL_MSG("EndOfEarlyData recieved unexpectedly"); + WOLFSSL_MSG("EndOfEarlyData received unexpectedly"); SendAlert(ssl, alert_fatal, unexpected_message); return OUT_OF_ORDER_E; } @@ -6323,7 +6826,7 @@ * inOutIdx On entry, the index into the message buffer of Finished. * On exit, the index of byte after the Finished message and padding. * size The length of the current handshake message. - * retuns 0 on success, otherwise failure. + * returns 0 on success, otherwise failure. */ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) @@ -6454,7 +6957,7 @@ * message. * * ssl The SSL/TLS object. - * retuns 0 on success, otherwise failure. + * returns 0 on success, otherwise failure. */ static int ExpectedResumptionSecret(WOLFSSL* ssl) { @@ -6464,7 +6967,7 @@ Digest digest; static byte header[] = { 0x14, 0x00, 0x00, 0x00 }; - /* Copy the running hash so we cna restore it after. */ + /* Copy the running hash so we can restore it after. */ switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 case sha256_mac: @@ -6544,7 +7047,7 @@ * Message contains the information required to perform resumption. * * ssl The SSL/TLS object. - * retuns 0 on success, otherwise failure. + * returns 0 on success, otherwise failure. */ static int SendTls13NewSessionTicket(WOLFSSL* ssl) { @@ -7004,7 +7507,7 @@ WOLFSSL_ENTER("DoTls13HandShakeMsgType"); - /* make sure can read the message */ + /* make sure we can read the message */ if (*inOutIdx + size > totalSz) return INCOMPLETE_DATA; @@ -7051,10 +7554,10 @@ /* above checks handshake state */ switch (type) { #ifndef NO_WOLFSSL_CLIENT - /* Messages only recieved by client. */ + /* Messages only received by client. */ #ifdef WOLFSSL_TLS13_DRAFT_18 case hello_retry_request: - WOLFSSL_MSG("processing hello rety request"); + WOLFSSL_MSG("processing hello retry request"); ret = DoTls13HelloRetryRequest(ssl, input, inOutIdx, size); break; #endif @@ -7062,6 +7565,18 @@ case server_hello: WOLFSSL_MSG("processing server hello"); ret = DoTls13ServerHello(ssl, input, inOutIdx, size, &type); + #if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + if (ssl->options.resuming || !IsAtLeastTLSv1_2(ssl) || + IsAtLeastTLSv1_3(ssl->version)) { + ssl->options.cacheMessages = 0; + if (ssl->hsHashes->messages != NULL) { + XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES); + ssl->hsHashes->messages = NULL; + } + } + #endif break; case encrypted_extensions: @@ -7083,7 +7598,7 @@ #endif /* !NO_WOLFSSL_CLIENT */ #ifndef NO_WOLFSSL_SERVER - /* Messages only recieved by server. */ + /* Messages only received by server. */ case client_hello: WOLFSSL_MSG("processing client hello"); ret = DoTls13ClientHello(ssl, input, inOutIdx, size); @@ -7097,7 +7612,7 @@ #endif #endif /* !NO_WOLFSSL_SERVER */ - /* Messages recieved by both client and server. */ + /* Messages received by both client and server. */ #ifndef NO_CERTS case certificate: WOLFSSL_MSG("processing certificate"); @@ -7105,7 +7620,8 @@ break; #endif -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) case certificate_verify: WOLFSSL_MSG("processing certificate verify"); ret = DoTls13CertificateVerify(ssl, input, inOutIdx, size); @@ -7136,6 +7652,9 @@ type != key_update) { ret = HashInput(ssl, input + inIdx, size); } + if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag) { + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + } if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA) SendAlert(ssl, alert_fatal, decode_error); @@ -7145,7 +7664,7 @@ SendAlert(ssl, alert_fatal, illegal_parameter); } - if (ssl->options.tls1_3) { + if (ret == 0 && ssl->options.tls1_3) { /* Need to hash input message before deriving secrets. */ #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) { @@ -7243,8 +7762,11 @@ byte type; word32 size; - if (GetHandshakeHeader(ssl,input,inOutIdx,&type, &size, totalSz) != 0) + if (GetHandshakeHeader(ssl, input, inOutIdx, &type, &size, + totalSz) != 0) { + SendAlert(ssl, alert_fatal, unexpected_message); return PARSE_ERROR; + } return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); @@ -7354,7 +7876,13 @@ return WOLFSSL_FATAL_ERROR; } - if (ssl->buffers.outputBuffer.length > 0) { + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { if ((ssl->error = SendBuffered(ssl)) == 0) { /* fragOffset is non-zero when sending fragments. On the last * fragment, fragOffset is zero again, and the state can be @@ -7552,6 +8080,10 @@ } #endif /* NO_HANDSHAKE_DONE_CB */ + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + WOLFSSL_LEAVE("wolfSSL_connect_TLSv13()", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; @@ -7937,6 +8469,85 @@ return WOLFSSL_SUCCESS; } +#ifndef NO_PSK +void wolfSSL_CTX_set_psk_client_tls13_callback(WOLFSSL_CTX* ctx, + wc_psk_client_tls13_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_client_tls13_callback"); + + if (ctx == NULL) + return; + + ctx->havePSK = 1; + ctx->client_psk_tls13_cb = cb; +} + + +void wolfSSL_set_psk_client_tls13_callback(WOLFSSL* ssl, + wc_psk_client_tls13_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_client_tls13_callback"); + + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.client_psk_tls13_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.side); +} + + +void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx, + wc_psk_server_tls13_callback cb) +{ + WOLFSSL_ENTER("SSL_CTX_set_psk_server_tls13_callback"); + if (ctx == NULL) + return; + ctx->havePSK = 1; + ctx->server_psk_tls13_cb = cb; +} + + +void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl, + wc_psk_server_tls13_callback cb) +{ + byte haveRSA = 1; + int keySz = 0; + + WOLFSSL_ENTER("SSL_set_psk_server_tls13_callback"); + if (ssl == NULL) + return; + + ssl->options.havePSK = 1; + ssl->options.server_psk_tls13_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.side); +} +#endif + + #ifndef NO_WOLFSSL_SERVER /* The server accepting a connection from a client. * The protocol version is expecting to be TLS v1.3. @@ -7993,7 +8604,13 @@ } #endif - if (ssl->buffers.outputBuffer.length > 0) { + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_PENDING_E + #endif + ) { if ((ssl->error = SendBuffered(ssl)) == 0) { /* fragOffset is non-zero when sending fragments. On the last * fragment, fragOffset is zero again, and the state can be @@ -8016,6 +8633,9 @@ switch (ssl->options.acceptState) { +#ifdef HAVE_SECURE_RENEGOTIATION + case TLS13_ACCEPT_BEGIN_RENEG: +#endif case TLS13_ACCEPT_BEGIN : /* get client_hello */ while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { @@ -8027,6 +8647,8 @@ ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE; WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + if (!IsAtLeastTLSv1_3(ssl->version)) + return wolfSSL_accept(ssl); FALL_THROUGH; case TLS13_ACCEPT_CLIENT_HELLO_DONE : @@ -8067,6 +8689,7 @@ return WOLFSSL_FATAL_ERROR; } ssl->options.sentChangeCipher = 1; + ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE; } #endif ssl->options.acceptState = TLS13_ACCEPT_FIRST_REPLY_DONE; @@ -8077,7 +8700,7 @@ case TLS13_ACCEPT_FIRST_REPLY_DONE : if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) { - ssl->options.clientState = NULL_STATE; + ssl->options.clientState = CLIENT_HELLO_RETRY; while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { if ((ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); @@ -8191,8 +8814,8 @@ case TLS13_ACCEPT_FINISHED_SENT : #ifdef HAVE_SESSION_TICKET #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED - if (!ssl->options.resuming && !ssl->options.verifyPeer && - !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { + if (!ssl->options.verifyPeer && !ssl->options.noTicketTls13 && + ssl->ctx->ticketEncCb != NULL) { if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -8222,8 +8845,7 @@ } else #endif - if (!ssl->options.resuming && - !ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { + if (!ssl->options.noTicketTls13 && ssl->ctx->ticketEncCb != NULL) { if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; @@ -8246,6 +8868,10 @@ } #endif /* NO_HANDSHAKE_DONE_CB */ + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + WOLFSSL_LEAVE("SSL_accept()", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; @@ -8329,7 +8955,7 @@ if (ssl->options.handShakeState == NULL_STATE) { ssl->earlyData = expecting_early_data; ret = wolfSSL_connect_TLSv13(ssl); - if (ret <= 0) + if (ret != WOLFSSL_SUCCESS) return WOLFSSL_FATAL_ERROR; } if (ssl->options.handShakeState == CLIENT_HELLO_COMPLETE) { @@ -8401,6 +9027,20 @@ } #endif +#ifdef HAVE_SECRET_CALLBACK +int wolfSSL_set_tls13_secret_cb(WOLFSSL* ssl, Tls13SecretCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_set_tls13_secret_cb"); + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + ssl->tls13SecretCb = cb; + ssl->tls13SecretCtx = ctx; + + return WOLFSSL_SUCCESS; +} +#endif + #undef ERROR_OUT #endif /* !WOLFCRYPT_ONLY */