diff options
author | Matt Caswell <matt@openssl.org> | 2016-11-07 10:16:57 +0000 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2016-11-09 10:36:54 +0000 |
commit | d2139cf8dffcfe4a936ef55d25f769b162a8c603 (patch) | |
tree | 683bae690101582b6c7dd4340bb2d02cc38b03dc /crypto | |
parent | 234b8af4b748311b8856bfd30ae45d187a184465 (diff) |
Update HKDF to support separte Extract and Expand steps
At the moment you can only do an HKDF Extract and Expand in one go. For
TLS1.3 we need to be able to do an Extract first, and the subsequently do
a number of Expand steps on the same PRK.
Reviewed-by: Rich Salz <rsalz@openssl.org>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/kdf/hkdf.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/crypto/kdf/hkdf.c b/crypto/kdf/hkdf.c index 00b95b5a88..0bcb1c2f05 100644 --- a/crypto/kdf/hkdf.c +++ b/crypto/kdf/hkdf.c @@ -34,6 +34,7 @@ static unsigned char *HKDF_Expand(const EVP_MD *evp_md, unsigned char *okm, size_t okm_len); typedef struct { + int mode; const EVP_MD *md; unsigned char *salt; size_t salt_len; @@ -77,6 +78,10 @@ static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) kctx->md = p2; return 1; + case EVP_PKEY_CTRL_HKDF_MODE: + kctx->mode = p1; + return 1; + case EVP_PKEY_CTRL_HKDF_SALT: if (p1 == 0 || p2 == NULL) return 1; @@ -160,13 +165,27 @@ static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, if (kctx->md == NULL || kctx->key == NULL) return 0; - if (HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key, kctx->key_len, - kctx->info, kctx->info_len, key, *keylen) == NULL) - { + switch (kctx->mode) { + case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND: + return HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key, + kctx->key_len, kctx->info, kctx->info_len, key, + *keylen) != NULL; + + case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY: + if (key == NULL) { + *keylen = EVP_MD_size(kctx->md); + return 1; + } + return HKDF_Extract(kctx->md, kctx->salt, kctx->salt_len, kctx->key, + kctx->key_len, key, keylen) != NULL; + + case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY: + return HKDF_Expand(kctx->md, kctx->key, kctx->key_len, kctx->info, + kctx->info_len, key, *keylen) != NULL; + + default: return 0; } - - return 1; } const EVP_PKEY_METHOD hkdf_pkey_meth = { @@ -206,12 +225,16 @@ static unsigned char *HKDF(const EVP_MD *evp_md, unsigned char *okm, size_t okm_len) { unsigned char prk[EVP_MAX_MD_SIZE]; + unsigned char *ret; size_t prk_len; if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, &prk_len)) return NULL; - return HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len); + ret = HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len); + OPENSSL_cleanse(prk, sizeof(prk)); + + return ret; } static unsigned char *HKDF_Extract(const EVP_MD *evp_md, @@ -245,7 +268,7 @@ static unsigned char *HKDF_Expand(const EVP_MD *evp_md, if (okm_len % dig_len) n++; - if (n > 255) + if (n > 255 || okm == NULL) return NULL; if ((hmac = HMAC_CTX_new()) == NULL) |