diff --git a/src/tls13.c b/src/tls13.c index 83e78a7ab..2ca7baf99 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -134,6 +134,18 @@ */ #define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; } +#if (defined(HAVE_FIPS) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 4))) || \ + defined(HAVE_SELFTEST) + +enum { +/* + MAX_HKDF_LABEL_SZ = OPAQUE16_LEN + + OPAQUE8_LEN + PROTOCOL_LABEL_SZ + MAX_LABEL_SZ + + OPAQUE8_LEN + WC_MAX_DIGEST_SIZE +*/ + MAX_TLS13_HKDF_LABEL_SZ = 47 + WC_MAX_DIGEST_SIZE +}; /* Extract data using HMAC, salt and input. * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF) @@ -143,37 +155,35 @@ * saltLen The length of the salt. * ikm The input keying material. * ikmLen The length of the input keying material. - * mac The type of digest to use. + * digest The type of digest to use. * returns 0 on success, otherwise failure. */ -static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, - byte* ikm, int ikmLen, int mac) +static int wc_Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, + byte* ikm, int ikmLen, int digest) { int ret; - int hash = 0; int len = 0; - switch (mac) { + switch (digest) { #ifndef NO_SHA256 - case sha256_mac: - hash = WC_SHA256; + case WC_SHA256: len = WC_SHA256_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA384 - case sha384_mac: - hash = WC_SHA384; + case WC_SHA384: len = WC_SHA384_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_TLS13_SHA512 - case sha512_mac: - hash = WC_SHA512; + case WC_SHA512: len = WC_SHA512_DIGEST_SIZE; break; #endif + default: + return BAD_FUNC_ARG; } /* When length is 0 then use zeroed data of digest length. */ @@ -189,7 +199,7 @@ static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, WOLFSSL_BUFFER(ikm, ikmLen); #endif - ret = wc_HKDF_Extract(hash, salt, saltLen, ikm, ikmLen, prk); + ret = wc_HKDF_Extract(digest, salt, saltLen, ikm, ikmLen, prk); #ifdef WOLFSSL_DEBUG_TLS WOLFSSL_MSG(" PRK"); @@ -199,6 +209,7 @@ static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, return ret; } + /* Expand data using HMAC, salt and label and info. * TLS v1.3 defines this function. * @@ -213,7 +224,7 @@ static int Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, * digest The type of digest to use. * returns 0 on success, otherwise failure. */ -static int HKDF_Expand_Label(byte* okm, word32 okmLen, +static int wc_Tls13_HKDF_Expand_Label(byte* okm, word32 okmLen, const byte* prk, word32 prkLen, const byte* protocol, word32 protocolLen, const byte* label, word32 labelLen, @@ -222,7 +233,7 @@ static int HKDF_Expand_Label(byte* okm, word32 okmLen, { int ret = 0; int idx = 0; - byte data[MAX_HKDF_LABEL_SZ]; + byte data[MAX_TLS13_HKDF_LABEL_SZ]; /* Output length. */ data[idx++] = (byte)(okmLen >> 8); @@ -262,6 +273,8 @@ static int HKDF_Expand_Label(byte* okm, word32 okmLen, return ret; } +#endif /* HAVE_FIPS */ + /* Size of the TLS v1.3 label use when deriving keys. */ #define TLS13_PROTOCOL_LABEL_SZ 6 /* The protocol label for TLS v1.3. */ @@ -355,7 +368,7 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, if (outputLen == -1) outputLen = hashSz; - return HKDF_Expand_Label(output, outputLen, secret, hashSz, + return wc_Tls13_HKDF_Expand_Label(output, outputLen, secret, hashSz, protocol, protocolLen, label, labelLen, hash, hashSz, digestAlg); } @@ -424,11 +437,41 @@ static int DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, if (includeMsgs) hashOutSz = hashSz; - return HKDF_Expand_Label(output, outputLen, secret, hashSz, + return wc_Tls13_HKDF_Expand_Label(output, outputLen, secret, hashSz, protocol, protocolLen, label, labelLen, hash, hashOutSz, digestAlg); } +/* Convert TLS mac ID to a hash algorithm ID + * + * mac Mac ID to convert + * returns hash ID on success, or the NONE type. + */ +static WC_INLINE int mac2hash(int mac) +{ + int hash = WC_HASH_TYPE_NONE; + switch (mac) { + #ifndef NO_SHA256 + case sha256_mac: + hash = WC_SHA256; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = WC_SHA384; + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case sha512_mac: + hash = WC_SHA512; + break; + #endif + } + return hash; +} + #ifndef NO_PSK /* The length of the binder key label. */ #define BINDER_KEY_LABEL_SZ 10 @@ -904,12 +947,12 @@ int DeriveEarlySecret(WOLFSSL* ssl) return BAD_FUNC_ARG; } #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + return wc_Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, ssl->arrays->psk_key, ssl->arrays->psk_keySz, - ssl->specs.mac_algorithm); + mac2hash(ssl->specs.mac_algorithm)); #else - return Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, - ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); + return wc_Tls13_HKDF_Extract(ssl->arrays->secret, NULL, 0, + ssl->arrays->masterSecret, 0, mac2hash(ssl->specs.mac_algorithm)); #endif } @@ -937,10 +980,10 @@ int DeriveHandshakeSecret(WOLFSSL* ssl) if (ret != 0) return ret; - return Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, + return wc_Tls13_HKDF_Extract(ssl->arrays->preMasterSecret, key, ssl->specs.hash_size, ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, - ssl->specs.mac_algorithm); + mac2hash(ssl->specs.mac_algorithm)); } /* Derive the master secret using HKDF Extract. @@ -961,9 +1004,9 @@ int DeriveMasterSecret(WOLFSSL* ssl) if (ret != 0) return ret; - ret = Tls13_HKDF_Extract(ssl->arrays->masterSecret, + ret = wc_Tls13_HKDF_Extract(ssl->arrays->masterSecret, key, ssl->specs.hash_size, - ssl->arrays->masterSecret, 0, ssl->specs.mac_algorithm); + ssl->arrays->masterSecret, 0, mac2hash(ssl->specs.mac_algorithm)); #ifdef HAVE_KEYING_MATERIAL if (ret != 0) @@ -1021,7 +1064,7 @@ int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret) return BAD_FUNC_ARG; } - return HKDF_Expand_Label(secret, ssl->specs.hash_size, + return wc_Tls13_HKDF_Expand_Label(secret, ssl->specs.hash_size, ssl->session.masterSecret, ssl->specs.hash_size, protocol, protocolLen, resumptionLabel, RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg); diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index ba9c1444f..185b7860b 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -1597,6 +1597,133 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen, return wc_HKDF_Expand(type, prk, hashSz, info, infoSz, out, outSz); } +#if !defined(HAVE_FIPS) || \ + defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 4) + /* Extract data using HMAC, salt and input. + * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + * + * prk The generated pseudorandom key. + * salt The salt. + * saltLen The length of the salt. + * ikm The input keying material. + * ikmLen The length of the input keying material. + * digest The type of digest to use. + * returns 0 on success, otherwise failure. + */ + int wc_Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, + byte* ikm, int ikmLen, int digest) + { + int ret; + int len = 0; + + switch (digest) { + #ifndef NO_SHA256 + case WC_SHA256: + len = WC_SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + len = WC_SHA384_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_TLS13_SHA512 + case WC_SHA512: + len = WC_SHA512_DIGEST_SIZE; + break; + #endif + default: + return BAD_FUNC_ARG; + } + + /* When length is 0 then use zeroed data of digest length. */ + if (ikmLen == 0) { + ikmLen = len; + XMEMSET(ikm, 0, len); + } + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" Salt"); + WOLFSSL_BUFFER(salt, saltLen); + WOLFSSL_MSG(" IKM"); + WOLFSSL_BUFFER(ikm, ikmLen); +#endif + + ret = wc_HKDF_Extract(digest, salt, saltLen, ikm, ikmLen, prk); + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" PRK"); + WOLFSSL_BUFFER(prk, len); +#endif + + return ret; + } + + /* Expand data using HMAC, salt and label and info. + * TLS v1.3 defines this function. + * + * okm The generated pseudorandom key - output key material. + * okmLen The length of generated pseudorandom key - + * output key material. + * prk The salt - pseudo-random key. + * prkLen The length of the salt - pseudo-random key. + * protocol The TLS protocol label. + * protocolLen The length of the TLS protocol label. + * info The information to expand. + * infoLen The length of the information. + * digest The type of digest to use. + * returns 0 on success, otherwise failure. + */ + int wc_Tls13_HKDF_Expand_Label(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, + const byte* protocol, word32 protocolLen, + const byte* label, word32 labelLen, + const byte* info, word32 infoLen, + int digest) + { + int ret = 0; + int idx = 0; + byte data[MAX_TLS13_HKDF_LABEL_SZ]; + + /* Output length. */ + data[idx++] = (byte)(okmLen >> 8); + data[idx++] = (byte)okmLen; + /* Length of protocol | label. */ + data[idx++] = (byte)(protocolLen + labelLen); + /* Protocol */ + XMEMCPY(&data[idx], protocol, protocolLen); + idx += protocolLen; + /* Label */ + XMEMCPY(&data[idx], label, labelLen); + idx += labelLen; + /* Length of hash of messages */ + data[idx++] = (byte)infoLen; + /* Hash of messages */ + XMEMCPY(&data[idx], info, infoLen); + idx += infoLen; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" PRK"); + WOLFSSL_BUFFER(prk, prkLen); + WOLFSSL_MSG(" Info"); + WOLFSSL_BUFFER(data, idx); +#endif + + ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen); + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" OKM"); + WOLFSSL_BUFFER(okm, okmLen); +#endif + + ForceZero(data, idx); + + return ret; + } +#endif /* newer HAVE_FIPS */ + #endif /* HAVE_HKDF */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index aebfb3a69..d81748e8d 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1362,9 +1362,6 @@ enum Misc { KEY_LABEL_SZ = 13, /* TLS key block expansion sz */ PROTOCOL_LABEL_SZ = 9, /* Length of the protocol label */ MAX_LABEL_SZ = 34, /* Maximum length of a label */ - MAX_HKDF_LABEL_SZ = OPAQUE16_LEN + - OPAQUE8_LEN + PROTOCOL_LABEL_SZ + MAX_LABEL_SZ + - OPAQUE8_LEN + WC_MAX_DIGEST_SIZE, MAX_REQUEST_SZ = 256, /* Maximum cert req len (no auth yet */ SESSION_FLUSH_COUNT = 256, /* Flush session cache unless user turns off */ TLS_MAX_PAD_SZ = 255, /* Max padding in TLS */ diff --git a/wolfssl/wolfcrypt/hmac.h b/wolfssl/wolfcrypt/hmac.h index 08f5959ae..c5da2459d 100644 --- a/wolfssl/wolfcrypt/hmac.h +++ b/wolfssl/wolfcrypt/hmac.h @@ -234,6 +234,30 @@ WOLFSSL_API int wc_HKDF(int type, const byte* inKey, word32 inKeySz, const byte* info, word32 infoSz, byte* out, word32 outSz); +#if (!defined(HAVE_FIPS) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 4))) && \ + !defined(HAVE_SELFTEST) + +enum { +/* + MAX_HKDF_LABEL_SZ = OPAQUE16_LEN + + OPAQUE8_LEN + PROTOCOL_LABEL_SZ + MAX_LABEL_SZ + + OPAQUE8_LEN + WC_MAX_DIGEST_SIZE +*/ + MAX_TLS13_HKDF_LABEL_SZ = 47 + WC_MAX_DIGEST_SIZE +}; + +WOLFSSL_API int wc_Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen, + byte* ikm, int ikmLen, int digest); + +WOLFSSL_API int wc_Tls13_HKDF_Expand_Label(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, + const byte* protocol, word32 protocolLen, + const byte* label, word32 labelLen, + const byte* info, word32 infoLen, + int digest); + +#endif /* HAVE_FIPS */ #endif /* HAVE_HKDF */ #ifdef WOLFSSL_WOLFSSH