summaryrefslogtreecommitdiffstats
path: root/crypto/kdf
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2016-11-07 10:16:57 +0000
committerMatt Caswell <matt@openssl.org>2016-11-09 10:36:54 +0000
commitd2139cf8dffcfe4a936ef55d25f769b162a8c603 (patch)
tree683bae690101582b6c7dd4340bb2d02cc38b03dc /crypto/kdf
parent234b8af4b748311b8856bfd30ae45d187a184465 (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/kdf')
-rw-r--r--crypto/kdf/hkdf.c37
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)