Commit d2139cf8 authored by Matt Caswell's avatar Matt Caswell
Browse files

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: default avatarRich Salz <rsalz@openssl.org>
parent 234b8af4
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -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,14 +165,28 @@ 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)
    {
        return 0;
    }
    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;
    }
}

const EVP_PKEY_METHOD hkdf_pkey_meth = {
    EVP_PKEY_HKDF,
@@ -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)
+2 −2
Original line number Diff line number Diff line
@@ -97,9 +97,9 @@ salt value "salt" and info value "label":
    /* Error */
 if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0)
    /* Error */
 if (EVP_PKEY_CTX_set1_salt(pctx, "salt", 4) <= 0)
 if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, "salt", 4) <= 0)
    /* Error */
 if (EVP_PKEY_CTX_set1_key(pctx, "secret", 6) <= 0)
 if (EVP_PKEY_CTX_set1_hkdf_key(pctx, "secret", 6) <= 0)
    /* Error */
 if (EVP_PKEY_CTX_add1_hkdf_info(pctx, "label", 6) <= 0)
    /* Error */
+16 −7
Original line number Diff line number Diff line
@@ -21,6 +21,11 @@ extern "C" {
# define EVP_PKEY_CTRL_HKDF_SALT                (EVP_PKEY_ALG_CTRL + 4)
# define EVP_PKEY_CTRL_HKDF_KEY                 (EVP_PKEY_ALG_CTRL + 5)
# define EVP_PKEY_CTRL_HKDF_INFO                (EVP_PKEY_ALG_CTRL + 6)
# define EVP_PKEY_CTRL_HKDF_MODE                (EVP_PKEY_ALG_CTRL + 7)

# define EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND 0
# define EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY       1
# define EVP_PKEY_HKDEF_MODE_EXPAND_ONLY        2

# define EVP_PKEY_CTX_set_tls1_prf_md(pctx, md) \
            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
@@ -50,6 +55,10 @@ extern "C" {
            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
                              EVP_PKEY_CTRL_HKDF_INFO, infolen, (void *)info)

# define EVP_PKEY_CTX_hkdf_mode(pctx, mode) \
            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
                              EVP_PKEY_CTRL_HKDF_MODE, mode, NULL)

/* BEGIN ERROR CODES */
/*
 * The following lines are auto generated by the script mkerr.pl. Any changes