Implement a EVP_PKEY KDF to KDF provider bridge
authorMatt Caswell <matt@openssl.org>
Fri, 3 Jul 2020 15:18:03 +0000 (16:18 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 10 Aug 2020 13:51:57 +0000 (14:51 +0100)
Some KDF implementations were available before the current EVP_KDF API.
They were used via EVP_PKEY_derive. There exists a bridge between the old
API and the EVP_KDF API however this bridge itself uses a legacy
EVP_PKEY_METHOD. This commit implements a provider side bridge without
having to use any legacy code.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12573)

16 files changed:
crypto/err/openssl.txt
crypto/evp/evp_err.c
crypto/evp/exchange.c
crypto/evp/pmeth_lib.c
include/openssl/evperr.h
include/openssl/kdf.h
providers/defltprov.c
providers/implementations/exchange/build.info
providers/implementations/exchange/kdf_exch.c [new file with mode: 0644]
providers/implementations/include/prov/implementations.h
providers/implementations/include/prov/kdfexchange.h [new file with mode: 0644]
providers/implementations/kdfs/tls1_prf.c
providers/implementations/keymgmt/build.info
providers/implementations/keymgmt/kdf_legacy_kmgmt.c [new file with mode: 0644]
test/pkey_meth_kdf_test.c
util/libcrypto.num

index af19ab2..d9512bc 100644 (file)
@@ -2558,6 +2558,8 @@ EVP_R_INVALID_NULL_ALGORITHM:218:invalid null algorithm
 EVP_R_INVALID_OPERATION:148:invalid operation
 EVP_R_INVALID_PROVIDER_FUNCTIONS:193:invalid provider functions
 EVP_R_INVALID_SALT_LENGTH:186:invalid salt length
+EVP_R_INVALID_SECRET_LENGTH:221:invalid secret length
+EVP_R_INVALID_SEED_LENGTH:220:invalid seed length
 EVP_R_KEYGEN_FAILURE:120:keygen failure
 EVP_R_KEYMGMT_EXPORT_FAILURE:205:keymgmt export failure
 EVP_R_KEY_SETUP_FAILED:180:key setup failed
index d13cd05..4e9970d 100644 (file)
@@ -97,6 +97,10 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
     "invalid provider functions"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SALT_LENGTH),
     "invalid salt length"},
+    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SECRET_LENGTH),
+    "invalid secret length"},
+    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SEED_LENGTH),
+    "invalid seed length"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYGEN_FAILURE), "keygen failure"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYMGMT_EXPORT_FAILURE),
     "keymgmt export failure"},
index 28e1f88..a47a0f0 100644 (file)
@@ -202,11 +202,31 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
 
     /*
      * Ensure that the key is provided, either natively, or as a cached export.
-     *  If not, go legacy
+     * If not, goto legacy
      */
     tmp_keymgmt = ctx->keymgmt;
-    provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
-                                          &tmp_keymgmt, ctx->propquery);
+    if (ctx->pkey == NULL) {
+        /*
+         * Some algorithms (e.g. legacy KDFs) don't have a pkey - so we create
+         * a blank one.
+         */
+        EVP_PKEY *pkey = EVP_PKEY_new();
+
+        if (pkey == NULL || !EVP_PKEY_set_type_by_keymgmt(pkey, tmp_keymgmt)) {
+            ERR_clear_last_mark();
+            EVP_PKEY_free(pkey);
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+        provkey = pkey->keydata = evp_keymgmt_newdata(tmp_keymgmt);
+        if (provkey == NULL)
+            EVP_PKEY_free(pkey);
+        else
+            ctx->pkey = pkey;
+    } else {
+        provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
+                                            &tmp_keymgmt, ctx->propquery);
+    }
     if (provkey == NULL)
         goto legacy;
     if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
index 17e73e0..0fabaf4 100644 (file)
@@ -21,6 +21,7 @@
 #include <openssl/core_names.h>
 #include <openssl/dh.h>
 #include <openssl/rsa.h>
+#include <openssl/kdf.h>
 #include "internal/cryptlib.h"
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
@@ -156,7 +157,6 @@ static int is_legacy_alg(int id, const char *keytype)
     case EVP_PKEY_SM2:
     case EVP_PKEY_DHX:
     case EVP_PKEY_SCRYPT:
-    case EVP_PKEY_TLS1_PRF:
     case EVP_PKEY_HKDF:
     case EVP_PKEY_CMAC:
     case EVP_PKEY_HMAC:
@@ -241,7 +241,7 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx,
      * If an ENGINE handled this method look it up. Otherwise use internal
      * tables.
      */
-    if (e)
+    if (e != NULL) {
         pmeth = ENGINE_get_pkey_meth(e, id);
     else
 # endif
@@ -759,7 +759,7 @@ int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
 
 int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md)
 {
-    OSSL_PARAM sig_md_params[3], *p = sig_md_params;
+    OSSL_PARAM sig_md_params[2], *p = sig_md_params;
     /* 80 should be big enough */
     char name[80] = "";
     const EVP_MD *tmp;
@@ -778,7 +778,7 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md)
     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST,
                                             name,
                                             sizeof(name));
-    *p++ = OSSL_PARAM_construct_end();
+    *p = OSSL_PARAM_construct_end();
 
     if (!EVP_PKEY_CTX_get_params(ctx, sig_md_params))
         return 0;
@@ -820,11 +820,113 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
                                              * only so should be safe
                                              */
                                             (char *)name, 0);
-    *p++ = OSSL_PARAM_construct_end();
+    *p = OSSL_PARAM_construct_end();
 
     return EVP_PKEY_CTX_set_params(ctx, sig_md_params);
 }
 
+int EVP_PKEY_CTX_set_tls1_prf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
+{
+    OSSL_PARAM tls1_prf_md_params[2], *p = tls1_prf_md_params;
+    const char *name;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.kex.exchprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_DERIVE,
+                                 EVP_PKEY_CTRL_TLS_MD, 0, (void *)(md));
+
+    if (md == NULL) {
+        name = "";
+    } else {
+        name = EVP_MD_name(md);
+    }
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (char *)name, 0);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, tls1_prf_md_params);
+}
+
+int EVP_PKEY_CTX_set1_tls1_prf_secret(EVP_PKEY_CTX *ctx,
+                                      const unsigned char *sec, int seclen)
+{
+    OSSL_PARAM tls1_prf_secret_params[2], *p = tls1_prf_secret_params;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.kex.exchprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_DERIVE,
+                                 EVP_PKEY_CTRL_TLS_SECRET, seclen,
+                                 (void *)(sec));
+
+
+    if (seclen < 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_SECRET_LENGTH);
+        return 0;
+    }
+
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (unsigned char *)sec,
+                                            (size_t)seclen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, tls1_prf_secret_params);
+}
+
+int EVP_PKEY_CTX_add1_tls1_prf_seed(EVP_PKEY_CTX *ctx,
+                                    const unsigned char *seed, int seedlen)
+{
+    OSSL_PARAM tls1_prf_seed_params[2], *p = tls1_prf_seed_params;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.kex.exchprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_DERIVE,
+                                 EVP_PKEY_CTRL_TLS_SEED, seedlen,
+                                 (void *)(seed));
+
+    if (seedlen < 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_SEED_LENGTH);
+        return 0;
+    }
+
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SEED,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (unsigned char *)seed,
+                                            (size_t)seedlen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, tls1_prf_seed_params);
+}
+
 static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
                                 int cmd, int p1, void *p2)
 {
@@ -926,6 +1028,16 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
      * or for generic controls that are the same across multiple key types.
      */
     if (keytype == -1) {
+        if (optype == EVP_PKEY_OP_DERIVE) {
+            switch (cmd) {
+            case EVP_PKEY_CTRL_TLS_MD:
+                return EVP_PKEY_CTX_set_tls1_prf_md(ctx, p2);
+            case EVP_PKEY_CTRL_TLS_SECRET:
+                return EVP_PKEY_CTX_set1_tls1_prf_secret(ctx, p2, p1);
+            case EVP_PKEY_CTRL_TLS_SEED:
+                return EVP_PKEY_CTX_add1_tls1_prf_seed(ctx, p2, p1);
+            }
+        }
         switch (cmd) {
         case EVP_PKEY_CTRL_MD:
             return EVP_PKEY_CTX_set_signature_md(ctx, p2);
@@ -1034,7 +1146,9 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
     }
 # endif
 
-    if (strcmp(name, "rsa_padding_mode") == 0)
+    if (strcmp(name, "md") == 0)
+        name = OSSL_ALG_PARAM_DIGEST;
+    else if (strcmp(name, "rsa_padding_mode") == 0)
         name = OSSL_ASYM_CIPHER_PARAM_PAD_MODE;
     else if (strcmp(name, "rsa_mgf1_md") == 0)
         name = OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST;
index 5aa0028..a4dd4c7 100644 (file)
@@ -210,6 +210,8 @@ int ERR_load_EVP_strings(void);
 # define EVP_R_INVALID_OPERATION                          148
 # define EVP_R_INVALID_PROVIDER_FUNCTIONS                 193
 # define EVP_R_INVALID_SALT_LENGTH                        186
+# define EVP_R_INVALID_SECRET_LENGTH                      221
+# define EVP_R_INVALID_SEED_LENGTH                        220
 # define EVP_R_KEYGEN_FAILURE                             120
 # define EVP_R_KEYMGMT_EXPORT_FAILURE                     205
 # define EVP_R_KEY_SETUP_FAILED                           180
index b3dee52..1be54af 100644 (file)
@@ -115,17 +115,13 @@ void EVP_KDF_names_do_all(const EVP_KDF *kdf,
 # define EVP_PKEY_HKDEF_MODE_EXPAND_ONLY        \
             EVP_KDF_HKDF_MODE_EXPAND_ONLY
 
-# define EVP_PKEY_CTX_set_tls1_prf_md(pctx, md) \
-            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
-                              EVP_PKEY_CTRL_TLS_MD, 0, (void *)(md))
+int EVP_PKEY_CTX_set_tls1_prf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
 
-# define EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, sec, seclen) \
-            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
-                              EVP_PKEY_CTRL_TLS_SECRET, seclen, (void *)(sec))
+int EVP_PKEY_CTX_set1_tls1_prf_secret(EVP_PKEY_CTX *pctx,
+                                      const unsigned char *sec, int seclen);
 
-# define EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed, seedlen) \
-            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
-                              EVP_PKEY_CTRL_TLS_SEED, seedlen, (void *)(seed))
+int EVP_PKEY_CTX_add1_tls1_prf_seed(EVP_PKEY_CTX *pctx,
+                                    const unsigned char *seed, int seedlen);
 
 # define EVP_PKEY_CTX_set_hkdf_md(pctx, md) \
             EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
index 4ab39e6..5b6d6a6 100644 (file)
@@ -339,6 +339,7 @@ static const OSSL_ALGORITHM deflt_keyexch[] = {
     { "X25519", "provider=default", x25519_keyexch_functions },
     { "X448", "provider=default", x448_keyexch_functions },
 #endif
+    { "TLS1-PRF", "provider=default", kdf_keyexch_functions },
     { NULL, NULL, NULL }
 };
 
@@ -384,6 +385,7 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = {
     { "ED25519", "provider=default", ed25519_keymgmt_functions },
     { "ED448", "provider=default", ed448_keymgmt_functions },
 #endif
+    { "TLS1-PRF", "provider=default", kdf_keymgmt_functions },
     { NULL, NULL, NULL }
 };
 
index 3127f9a..92932b9 100644 (file)
@@ -4,6 +4,7 @@
 $DH_GOAL=../../libimplementations.a
 $ECX_GOAL=../../libimplementations.a
 $ECDH_GOAL=../../libimplementations.a
+$KDF_GOAL=../../libimplementations.a
 
 IF[{- !$disabled{dh} -}]
   SOURCE[$DH_GOAL]=dh_exch.c
@@ -25,3 +26,5 @@ IF[{- !$disabled{ec} -}]
   SOURCE[../../libfips.a]=ecdh_exch.c
   SOURCE[../../libnonfips.a]=ecdh_exch.c
 ENDIF
+
+SOURCE[$KDF_GOAL]=kdf_exch.c
diff --git a/providers/implementations/exchange/kdf_exch.c b/providers/implementations/exchange/kdf_exch.c
new file mode 100644 (file)
index 0000000..41278e6
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/kdf.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/kdfexchange.h"
+
+static OSSL_FUNC_keyexch_newctx_fn kdf_newctx;
+static OSSL_FUNC_keyexch_init_fn kdf_init;
+static OSSL_FUNC_keyexch_derive_fn kdf_derive;
+static OSSL_FUNC_keyexch_freectx_fn kdf_freectx;
+static OSSL_FUNC_keyexch_dupctx_fn kdf_dupctx;
+static OSSL_FUNC_keyexch_set_ctx_params_fn kdf_set_ctx_params;
+static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_settable_ctx_params;
+
+typedef struct {
+    void *provctx;
+    EVP_KDF_CTX *kdfctx;
+    KDF_DATA *kdfdata;
+} PROV_KDF_CTX;
+
+static void *kdf_newctx(void *provctx)
+{
+    PROV_KDF_CTX *kdfctx = OPENSSL_zalloc(sizeof(PROV_KDF_CTX));
+    EVP_KDF *kdf = NULL;
+
+    if (kdfctx == NULL)
+        return NULL;
+
+    kdfctx->provctx = provctx;
+
+    kdf = EVP_KDF_fetch(PROV_LIBRARY_CONTEXT_OF(provctx), "TLS1-PRF", NULL);
+    if (kdf == NULL)
+        goto err;
+    kdfctx->kdfctx = EVP_KDF_new_ctx(kdf);
+    EVP_KDF_free(kdf);
+
+    if (kdfctx->kdfctx == NULL)
+        goto err;
+
+    return kdfctx;
+ err:
+    OPENSSL_free(kdfctx);
+    return NULL;
+}
+
+static int kdf_init(void *vpkdfctx, void *vkdf)
+{
+    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
+
+    if (pkdfctx == NULL || vkdf == NULL || !kdf_data_up_ref(vkdf))
+        return 0;
+    pkdfctx->kdfdata = vkdf;
+
+    return 1;
+}
+
+static int kdf_derive(void *vpkdfctx, unsigned char *secret, size_t *secretlen,
+                      size_t outlen)
+{
+    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
+
+    return EVP_KDF_derive(pkdfctx->kdfctx, secret, *secretlen);
+}
+
+static void kdf_freectx(void *vpkdfctx)
+{
+    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
+
+    EVP_KDF_CTX_free(pkdfctx->kdfctx);
+    kdf_data_free(pkdfctx->kdfdata);
+
+    OPENSSL_free(pkdfctx);
+}
+
+static void *kdf_dupctx(void *vpkdfctx)
+{
+    PROV_KDF_CTX *srcctx = (PROV_KDF_CTX *)vpkdfctx;
+    PROV_KDF_CTX *dstctx;
+
+    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+    if (dstctx == NULL)
+        return NULL;
+
+    *dstctx = *srcctx;
+
+    dstctx->kdfctx = EVP_KDF_dup_ctx(srcctx->kdfctx);
+    if (dstctx->kdfctx == NULL) {
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+    if (!kdf_data_up_ref(dstctx->kdfdata)) {
+        EVP_KDF_CTX_free(dstctx->kdfctx);
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    return dstctx;
+}
+
+static int kdf_set_ctx_params(void *vpkdfctx, const OSSL_PARAM params[])
+{
+    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
+
+    return EVP_KDF_set_ctx_params(pkdfctx->kdfctx, params);
+}
+
+
+static const OSSL_PARAM *kdf_settable_ctx_params(void)
+{
+    /*
+     * TODO(3.0): FIXME FIXME!! These settable_ctx_params functions should
+     * should have a provctx argument so we can get hold of the libctx.
+     */
+    EVP_KDF *kdf = EVP_KDF_fetch(NULL, "TLS1-PRF", NULL);
+    const OSSL_PARAM *params;
+
+    if (kdf == NULL)
+        return NULL;
+
+    params = EVP_KDF_settable_ctx_params(kdf);
+    EVP_KDF_free(kdf);
+
+    return params;
+}
+
+const OSSL_DISPATCH kdf_keyexch_functions[] = {
+    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))kdf_newctx },
+    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))kdf_init },
+    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))kdf_derive },
+    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))kdf_freectx },
+    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))kdf_dupctx },
+    { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))kdf_set_ctx_params },
+    { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
+      (void (*)(void))kdf_settable_ctx_params },
+    { 0, NULL }
+};
index 7e47004..e862e3f 100644 (file)
@@ -275,12 +275,14 @@ extern const OSSL_DISPATCH x448_keymgmt_functions[];
 extern const OSSL_DISPATCH ed25519_keymgmt_functions[];
 extern const OSSL_DISPATCH ed448_keymgmt_functions[];
 extern const OSSL_DISPATCH ec_keymgmt_functions[];
+extern const OSSL_DISPATCH kdf_keymgmt_functions[];
 
 /* Key Exchange */
 extern const OSSL_DISPATCH dh_keyexch_functions[];
 extern const OSSL_DISPATCH x25519_keyexch_functions[];
 extern const OSSL_DISPATCH x448_keyexch_functions[];
 extern const OSSL_DISPATCH ecdh_keyexch_functions[];
+extern const OSSL_DISPATCH kdf_keyexch_functions[];
 
 /* Signature */
 extern const OSSL_DISPATCH dsa_signature_functions[];
diff --git a/providers/implementations/include/prov/kdfexchange.h b/providers/implementations/include/prov/kdfexchange.h
new file mode 100644 (file)
index 0000000..5c817bb
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <openssl/crypto.h>
+#include "internal/refcount.h"
+
+struct kdf_data_st {
+    OPENSSL_CTX *libctx;
+    CRYPTO_REF_COUNT refcnt;
+    CRYPTO_RWLOCK *lock;
+};
+
+typedef struct kdf_data_st KDF_DATA;
+
+KDF_DATA *kdf_data_new(void *provctx);
+void kdf_data_free(KDF_DATA *kdfdata);
+int kdf_data_up_ref(KDF_DATA *kdfdata);
index bc7d7fd..46a1253 100644 (file)
@@ -183,9 +183,6 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     }
     /* The seed fields concatenate, so process them all */
     if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED)) != NULL) {
-        OPENSSL_cleanse(ctx->seed, ctx->seedlen);
-        ctx->seedlen = 0;
-
         for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1,
                                                       OSSL_KDF_PARAM_SEED)) {
             const void *q = ctx->seed + ctx->seedlen;
index 73597c7..53c84ac 100644 (file)
@@ -5,6 +5,7 @@ $DH_GOAL=../../libimplementations.a
 $DSA_GOAL=../../libimplementations.a
 $EC_GOAL=../../libimplementations.a
 $ECX_GOAL=../../libimplementations.a
+$KDF_GOAL=../../libimplementations.a
 
 IF[{- !$disabled{dh} -}]
   SOURCE[$DH_GOAL]=dh_kmgmt.c
@@ -33,3 +34,5 @@ ENDIF
 
 SOURCE[../../libfips.a]=rsa_kmgmt.c
 SOURCE[../../libnonfips.a]=rsa_kmgmt.c
+
+SOURCE[$KDF_GOAL]=kdf_legacy_kmgmt.c
diff --git a/providers/implementations/keymgmt/kdf_legacy_kmgmt.c b/providers/implementations/keymgmt/kdf_legacy_kmgmt.c
new file mode 100644 (file)
index 0000000..33cf87e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * This implemments a dummy key manager for legacy KDFs that still support the
+ * old way of performing a KDF via EVP_PKEY_derive(). New KDFs should not be
+ * implemented this way. In reality there is no key data for such KDFs, so this
+ * key manager does very little.
+ */
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
+#include "prov/kdfexchange.h"
+
+static OSSL_FUNC_keymgmt_new_fn kdf_newdata;
+static OSSL_FUNC_keymgmt_free_fn kdf_freedata;
+static OSSL_FUNC_keymgmt_has_fn kdf_has;
+
+KDF_DATA *kdf_data_new(void *provctx)
+{
+    KDF_DATA *kdfdata = OPENSSL_zalloc(sizeof(*kdfdata));
+
+    if (kdfdata == NULL)
+        return NULL;
+
+    kdfdata->lock = CRYPTO_THREAD_lock_new();
+    if (kdfdata->lock == NULL) {
+        OPENSSL_free(kdfdata);
+        return NULL;
+    }
+    kdfdata->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+    kdfdata->refcnt = 1;
+
+    return kdfdata;
+}
+
+void kdf_data_free(KDF_DATA *kdfdata)
+{
+    int ref = 0;
+
+    if (kdfdata == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&kdfdata->refcnt, &ref, kdfdata->lock);
+    if (ref > 0)
+        return;
+
+    CRYPTO_THREAD_lock_free(kdfdata->lock);
+    OPENSSL_free(kdfdata);
+}
+
+int kdf_data_up_ref(KDF_DATA *kdfdata)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&kdfdata->refcnt, &ref, kdfdata->lock);
+    return 1;
+}
+
+static void *kdf_newdata(void *provctx)
+{
+    return kdf_data_new(provctx);
+}
+
+static void kdf_freedata(void *kdfdata)
+{
+    kdf_data_free(kdfdata);
+}
+
+static int kdf_has(void *keydata, int selection)
+{
+    return 0;
+}
+
+const OSSL_DISPATCH kdf_keymgmt_functions[] = {
+    { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))kdf_newdata },
+    { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))kdf_freedata },
+    { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))kdf_has },
+    { 0, NULL }
+};
index cdc3d9f..55b10f5 100644 (file)
@@ -35,11 +35,13 @@ static int test_kdf_tls1_prf(void)
         TEST_error("EVP_PKEY_CTX_set_tls1_prf_md");
         goto err;
     }
-    if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, "secret", 6) <= 0) {
+    if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx,
+                                          (unsigned char *)"secret", 6) <= 0) {
         TEST_error("EVP_PKEY_CTX_set1_tls1_prf_secret");
         goto err;
     }
-    if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, "seed", 4) <= 0) {
+    if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx,
+                                        (unsigned char *)"seed", 4) <= 0) {
         TEST_error("EVP_PKEY_CTX_add1_tls1_prf_seed");
         goto err;
     }
index fe875f1..7a31db8 100644 (file)
@@ -5226,3 +5226,6 @@ PKCS7_sign_with_libctx                  ? 3_0_0   EXIST::FUNCTION:
 PKCS7_encrypt_with_libctx               ?      3_0_0   EXIST::FUNCTION:
 SMIME_read_PKCS7_ex                     ?      3_0_0   EXIST::FUNCTION:
 OSSL_PROVIDER_self_test                 ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_CTX_set_tls1_prf_md            ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_CTX_set1_tls1_prf_secret       ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_CTX_add1_tls1_prf_seed         ?      3_0_0   EXIST::FUNCTION: