EVP: Implement support for key downgrading in backends
authorRichard Levitte <levitte@openssl.org>
Mon, 23 Mar 2020 04:40:47 +0000 (05:40 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 25 Mar 2020 16:01:32 +0000 (17:01 +0100)
Downgrading EVP_PKEYs from containing provider side internal keys to
containing legacy keys demands support in the EVP_PKEY_ASN1_METHOD.

This became a bit elaborate because the code would be almost exactly
the same as the import functions int EVP_KEYMGMT.  Therefore, we end
up moving most of the code to common backend support files that can be
used both by legacy backend code and by our providers.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11375)

28 files changed:
crypto/dh/build.info
crypto/dh/dh_ameth.c
crypto/dh/dh_backend.c [new file with mode: 0644]
crypto/dsa/build.info
crypto/dsa/dsa_ameth.c
crypto/dsa/dsa_backend.c [new file with mode: 0644]
crypto/ec/build.info
crypto/ec/ec_ameth.c
crypto/ec/ec_backend.c [new file with mode: 0644]
crypto/ec/ecx_backend.c [new file with mode: 0644]
crypto/ec/ecx_backend.h [new file with mode: 0644]
crypto/ec/ecx_meth.c
crypto/ffc/build.info
crypto/ffc/ffc_backend.c [new file with mode: 0644]
crypto/rsa/build.info
crypto/rsa/rsa_ameth.c
crypto/rsa/rsa_backend.c [new file with mode: 0644]
include/crypto/dh.h
include/crypto/dsa.h
include/crypto/ec.h
include/crypto/ecx.h
include/crypto/rsa.h
include/internal/ffc.h
providers/implementations/keymgmt/dh_kmgmt.c
providers/implementations/keymgmt/dsa_kmgmt.c
providers/implementations/keymgmt/ec_kmgmt.c
providers/implementations/keymgmt/ecx_kmgmt.c
providers/implementations/keymgmt/rsa_kmgmt.c

index 56c085b..ce0918e 100644 (file)
@@ -1,6 +1,6 @@
 LIBS=../../libcrypto
 
-$COMMON=dh_lib.c dh_key.c dh_group_params.c dh_check.c
+$COMMON=dh_lib.c dh_key.c dh_group_params.c dh_check.c dh_backend.c
 
 SOURCE[../../libcrypto]=$COMMON\
         dh_asn1.c dh_gen.c dh_err.c dh_depr.c \
index 877a66f..d0eacec 100644 (file)
@@ -25,6 +25,7 @@
 #include <openssl/cms.h>
 #include <openssl/core_names.h>
 #include "internal/param_build.h"
+#include "internal/ffc.h"
 
 /*
  * i2d/d2i like DH parameter functions which use the appropriate routine for
@@ -543,6 +544,25 @@ static int dh_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
     return rv;
 }
 
+static int dh_pkey_import_from(const OSSL_PARAM params[], void *key)
+{
+    EVP_PKEY *pkey = key;
+    DH *dh = DH_new();
+
+    if (dh == NULL) {
+        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!ffc_fromdata(dh_get0_params(dh), params)
+        || !dh_key_fromdata(dh, params)
+        || !EVP_PKEY_assign_DH(pkey, dh)) {
+        DH_free(dh);
+        return 0;
+    }
+    return 1;
+}
+
 const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
     EVP_PKEY_DH,
     EVP_PKEY_DH,
@@ -585,6 +605,7 @@ const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
 
     dh_pkey_dirty_cnt,
     dh_pkey_export_to,
+    dh_pkey_import_from,
 };
 
 const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = {
diff --git a/crypto/dh/dh_backend.c b/crypto/dh/dh_backend.c
new file mode 100644 (file)
index 0000000..bbeb096
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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/core_names.h>
+#include "crypto/dh.h"
+
+/*
+ * The intention with the "backend" source file is to offer backend functions
+ * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
+ * implementations alike.
+ */
+
+int dh_key_fromdata(DH *dh, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_priv_key, *param_pub_key;
+    BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+    if (dh == NULL)
+        return 0;
+
+    param_priv_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+    param_pub_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+
+    /*
+     * DH documentation says that a public key must be present if a
+     * private key is present.
+     * We want to have at least a public key either way, so we end up
+     * requiring it unconditionally.
+     */
+    if (param_priv_key != NULL && param_pub_key == NULL)
+        return 0;
+
+    if ((param_priv_key != NULL
+         && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
+        || (param_pub_key != NULL
+            && !OSSL_PARAM_get_BN(param_pub_key, &pub_key)))
+        goto err;
+
+    if (!DH_set0_key(dh, pub_key, priv_key))
+        goto err;
+
+    return 1;
+
+ err:
+    BN_clear_free(priv_key);
+    BN_free(pub_key);
+    return 0;
+}
index 35a95a2..d8f0350 100644 (file)
@@ -1,7 +1,7 @@
 LIBS=../../libcrypto
 
 $COMMON=dsa_sign.c dsa_vrf.c dsa_lib.c dsa_ossl.c dsa_aid.c dsa_check.c \
-        dsa_key.c
+        dsa_key.c dsa_backend.c
 
 SOURCE[../../libcrypto]=$COMMON\
         dsa_gen.c dsa_asn1.c \
index 92134f9..53daf33 100644 (file)
 #include <openssl/core_names.h>
 #include "internal/cryptlib.h"
 #include "crypto/asn1.h"
+#include "crypto/dsa.h"
 #include "crypto/evp.h"
 #include "internal/param_build.h"
+#include "internal/ffc.h"
 #include "dsa_local.h"
 
 static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
@@ -569,6 +571,25 @@ static int dsa_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
     return rv;
 }
 
+static int dsa_pkey_import_from(const OSSL_PARAM params[], void *key)
+{
+    EVP_PKEY *pkey = key;
+    DSA *dsa = DSA_new();
+
+    if (dsa == NULL) {
+        ERR_raise(ERR_LIB_DSA, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!ffc_fromdata(dsa_get0_params(dsa), params)
+        || !dsa_key_fromdata(dsa, params)
+        || !EVP_PKEY_assign_DSA(pkey, dsa)) {
+        DSA_free(dsa);
+        return 0;
+    }
+    return 1;
+}
+
 /* NB these are sorted in pkey_id order, lowest first */
 
 const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5] = {
@@ -632,6 +653,7 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5] = {
      NULL, NULL, NULL, NULL,
 
      dsa_pkey_dirty_cnt,
-     dsa_pkey_export_to
+     dsa_pkey_export_to,
+     dsa_pkey_import_from
     }
 };
diff --git a/crypto/dsa/dsa_backend.c b/crypto/dsa/dsa_backend.c
new file mode 100644 (file)
index 0000000..b927465
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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/core_names.h>
+#include "crypto/dsa.h"
+
+/*
+ * The intention with the "backend" source file is to offer backend support
+ * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
+ * implementations alike.
+ */
+
+int dsa_key_fromdata(DSA *dsa, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_priv_key, *param_pub_key;
+    BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+    if (dsa == NULL)
+        return 0;
+
+    param_priv_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+    param_pub_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+
+    /* It's ok if neither half is present */
+    if (param_priv_key == NULL && param_pub_key == NULL)
+        return 1;
+
+    /*
+     * DH documentation says that a public key must be present if a
+     * private key is present.
+     */
+    if (param_priv_key != NULL && param_pub_key == NULL)
+        return 0;
+
+    if (param_pub_key != NULL && !OSSL_PARAM_get_BN(param_pub_key, &pub_key))
+        goto err;
+    if (param_priv_key != NULL && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
+        goto err;
+
+    if (!DSA_set0_key(dsa, pub_key, priv_key))
+        goto err;
+
+    return 1;
+
+ err:
+    BN_clear_free(priv_key);
+    BN_free(pub_key);
+    return 0;
+}
index f70543d..4494ce7 100644 (file)
@@ -51,7 +51,7 @@ $COMMON=ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c \
         ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c curve25519.c \
         curve448/arch_32/f_impl.c curve448/f_generic.c curve448/scalar.c \
         curve448/curve448_tables.c curve448/eddsa.c curve448/curve448.c \
-        $ECASM ecdsa_aid.c
+        $ECASM ecdsa_aid.c ec_backend.c ecx_backend.c
 SOURCE[../../libcrypto]=$COMMON ec_ameth.c ec_pmeth.c ecx_meth.c ecx_key.c \
                         ec_err.c ecdh_kdf.c eck_prn.c ec_evp_lib.c
 SOURCE[../../providers/libfips.a]=$COMMON
index 944fc05..f3812e4 100644 (file)
@@ -744,6 +744,26 @@ int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
     return rv;
 }
 
+static int ec_pkey_import_from(const OSSL_PARAM params[], void *key)
+{
+    EVP_PKEY *pkey = key;
+    EC_KEY *ec = EC_KEY_new();
+
+    if (ec == NULL) {
+        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!ec_key_domparams_fromdata(ec, params)
+        || !ec_key_otherparams_fromdata(ec, params)
+        || !ec_key_fromdata(ec, params, 1)
+        || !EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+        EC_KEY_free(ec);
+        return 0;
+    }
+    return 1;
+}
+
 const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = {
     EVP_PKEY_EC,
     EVP_PKEY_EC,
@@ -789,7 +809,8 @@ const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = {
     0, /* get_pub_key */
 
     ec_pkey_dirty_cnt,
-    ec_pkey_export_to
+    ec_pkey_export_to,
+    ec_pkey_import_from
 };
 
 #if !defined(OPENSSL_NO_SM2)
diff --git a/crypto/ec/ec_backend.c b/crypto/ec/ec_backend.c
new file mode 100644 (file)
index 0000000..b4520a7
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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/core_names.h>
+#include <openssl/objects.h>
+#include <openssl/params.h>
+#include "crypto/bn.h"
+#include "crypto/ec.h"
+
+/*
+ * The intention with the "backend" source file is to offer backend support
+ * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
+ * implementations alike.
+ */
+
+int ec_set_param_ecdh_cofactor_mode(EC_KEY *ec, const OSSL_PARAM *p)
+{
+    const EC_GROUP *ecg = EC_KEY_get0_group(ec);
+    const BIGNUM *cofactor;
+    int mode;
+
+    if (!OSSL_PARAM_get_int(p, &mode))
+        return 0;
+
+    /*
+     * mode can be only 0 for disable, or 1 for enable here.
+     *
+     * This is in contrast with the same parameter on an ECDH EVP_PKEY_CTX that
+     * also supports mode == -1 with the meaning of "reset to the default for
+     * the associated key".
+     */
+    if (mode < 0 || mode > 1)
+        return 0;
+
+    if ((cofactor = EC_GROUP_get0_cofactor(ecg)) == NULL )
+        return 0;
+
+    /* ECDH cofactor mode has no effect if cofactor is 1 */
+    if (BN_is_one(cofactor))
+        return 1;
+
+    if (mode == 1)
+        EC_KEY_set_flags(ec, EC_FLAG_COFACTOR_ECDH);
+    else if (mode == 0)
+        EC_KEY_clear_flags(ec, EC_FLAG_COFACTOR_ECDH);
+
+    return 1;
+}
+
+/*
+ * Callers of ec_key_fromdata MUST make sure that ec_key_params_fromdata has
+ * been called before!
+ *
+ * This function only gets the bare keypair, domain parameters and other
+ * parameters are treated separately, and domain parameters are required to
+ * define a keypair.
+ */
+int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
+{
+    const OSSL_PARAM *param_priv_key, *param_pub_key;
+    BN_CTX *ctx = NULL;
+    BIGNUM *priv_key = NULL;
+    unsigned char *pub_key = NULL;
+    size_t pub_key_len;
+    const EC_GROUP *ecg = NULL;
+    EC_POINT *pub_point = NULL;
+    int ok = 0;
+
+    ecg = EC_KEY_get0_group(ec);
+    if (ecg == NULL)
+        return 0;
+
+    param_priv_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+    param_pub_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+
+    ctx = BN_CTX_new_ex(ec_key_get_libctx(ec));
+    if (ctx == NULL)
+        goto err;
+    /*
+     * We want to have at least a public key either way, so we end up
+     * requiring it unconditionally.
+     */
+    if (param_pub_key == NULL
+            || !OSSL_PARAM_get_octet_string(param_pub_key,
+                                            (void **)&pub_key, 0, &pub_key_len)
+            || (pub_point = EC_POINT_new(ecg)) == NULL
+            || !EC_POINT_oct2point(ecg, pub_point,
+                                   pub_key, pub_key_len, ctx))
+        goto err;
+
+    if (param_priv_key != NULL && include_private) {
+        int fixed_words;
+        const BIGNUM *order;
+
+        /*
+         * Key import/export should never leak the bit length of the secret
+         * scalar in the key.
+         *
+         * For this reason, on export we use padded BIGNUMs with fixed length.
+         *
+         * When importing we also should make sure that, even if short lived,
+         * the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as
+         * soon as possible, so that any processing of this BIGNUM might opt for
+         * constant time implementations in the backend.
+         *
+         * Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have
+         * to preallocate the BIGNUM internal buffer to a fixed public size big
+         * enough that operations performed during the processing never trigger
+         * a realloc which would leak the size of the scalar through memory
+         * accesses.
+         *
+         * Fixed Length
+         * ------------
+         *
+         * The order of the large prime subgroup of the curve is our choice for
+         * a fixed public size, as that is generally the upper bound for
+         * generating a private key in EC cryptosystems and should fit all valid
+         * secret scalars.
+         *
+         * For padding on export we just use the bit length of the order
+         * converted to bytes (rounding up).
+         *
+         * For preallocating the BIGNUM storage we look at the number of "words"
+         * required for the internal representation of the order, and we
+         * preallocate 2 extra "words" in case any of the subsequent processing
+         * might temporarily overflow the order length.
+         */
+        order = EC_GROUP_get0_order(ecg);
+        if (order == NULL || BN_is_zero(order))
+            goto err;
+
+        fixed_words = bn_get_top(order) + 2;
+
+        if ((priv_key = BN_secure_new()) == NULL)
+            goto err;
+        if (bn_wexpand(priv_key, fixed_words) == NULL)
+            goto err;
+        BN_set_flags(priv_key, BN_FLG_CONSTTIME);
+
+        if (!OSSL_PARAM_get_BN(param_priv_key, &priv_key))
+            goto err;
+    }
+
+    if (priv_key != NULL
+            && !EC_KEY_set_private_key(ec, priv_key))
+        goto err;
+
+    if (!EC_KEY_set_public_key(ec, pub_point))
+        goto err;
+
+    ok = 1;
+
+ err:
+    BN_CTX_free(ctx);
+    BN_clear_free(priv_key);
+    OPENSSL_free(pub_key);
+    EC_POINT_free(pub_point);
+    return ok;
+}
+
+int ec_key_domparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_ec_name;
+    EC_GROUP *ecg = NULL;
+    char *curve_name = NULL;
+    int ok = 0;
+
+    if (ec == NULL)
+        return 0;
+
+    param_ec_name = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_NAME);
+    if (param_ec_name == NULL) {
+        /* explicit parameters */
+
+        /*
+         * TODO(3.0): should we support explicit parameters curves?
+         */
+        return 0;
+    } else {
+        /* named curve */
+        int curve_nid;
+
+        if (!OSSL_PARAM_get_utf8_string(param_ec_name, &curve_name, 0)
+                || curve_name == NULL
+                || (curve_nid = ec_curve_name2nid(curve_name)) == NID_undef)
+            goto err;
+
+        if ((ecg = EC_GROUP_new_by_curve_name_ex(ec_key_get_libctx(ec),
+                                                 curve_nid)) == NULL)
+            goto err;
+    }
+
+    if (!EC_KEY_set_group(ec, ecg))
+        goto err;
+
+    /*
+     * TODO(3.0): if the group has changed, should we invalidate the private and
+     * public key?
+     */
+
+    ok = 1;
+
+ err:
+    OPENSSL_free(curve_name);
+    EC_GROUP_free(ecg);
+    return ok;
+}
+
+int ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *p;
+
+    if (ec == NULL)
+        return 0;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH);
+    if (p != NULL && !ec_set_param_ecdh_cofactor_mode(ec, p))
+        return 0;
+
+    return 1;
+}
diff --git a/crypto/ec/ecx_backend.c b/crypto/ec/ecx_backend.c
new file mode 100644 (file)
index 0000000..e613337
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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/core_names.h>
+#include <openssl/params.h>
+#include "crypto/ecx.h"
+#include "ecx_backend.h"
+
+/*
+ * The intention with the "backend" source file is to offer backend support
+ * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
+ * implementations alike.
+ */
+
+int ecx_key_fromdata(ECX_KEY *ecx, const OSSL_PARAM params[],
+                     int include_private)
+{
+    size_t privkeylen = 0, pubkeylen;
+    const OSSL_PARAM *param_priv_key = NULL, *param_pub_key;
+    unsigned char *pubkey;
+
+    if (ecx == NULL)
+        return 0;
+
+    param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+    if (include_private)
+        param_priv_key =
+            OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+    /*
+     * If a private key is present then a public key must also be present.
+     * Alternatively we've just got a public key.
+     */
+    if (param_pub_key == NULL)
+        return 0;
+
+    if (param_priv_key != NULL
+        && !OSSL_PARAM_get_octet_string(param_priv_key,
+                                        (void **)&ecx->privkey, ecx->keylen,
+                                        &privkeylen))
+        return 0;
+
+    pubkey = ecx->pubkey;
+    if (!OSSL_PARAM_get_octet_string(param_pub_key,
+                                     (void **)&pubkey,
+                                     sizeof(ecx->pubkey), &pubkeylen))
+        return 0;
+
+    if (pubkeylen != ecx->keylen
+        || (param_priv_key != NULL && privkeylen != ecx->keylen))
+        return 0;
+
+    ecx->haspubkey = 1;
+
+    return 1;
+}
+
diff --git a/crypto/ec/ecx_backend.h b/crypto/ec/ecx_backend.h
new file mode 100644 (file)
index 0000000..50ece17
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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
+ */
+
+#define ISX448(id)      ((id) == EVP_PKEY_X448)
+#define IS25519(id)     ((id) == EVP_PKEY_X25519 || (id) == EVP_PKEY_ED25519)
+#define KEYLENID(id)    (IS25519(id) ? X25519_KEYLEN \
+                                     : ((id) == EVP_PKEY_X448 ? X448_KEYLEN \
+                                                              : ED448_KEYLEN))
+#define KEYNID2TYPE(id) \
+    (IS25519(id) ?  ECX_KEY_TYPE_X25519 \
+                 : ((id) == EVP_PKEY_X448 ? ECX_KEY_TYPE_X448 \
+                                          : ((id) == EVP_PKEY_ED25519 ? ECX_KEY_TYPE_ED25519 \
+                                                                      : ECX_KEY_TYPE_ED448)))
+#define KEYLEN(p)       KEYLENID((p)->ameth->pkey_id)
index 9b9536f..97d1b13 100644 (file)
 #include "crypto/ecx.h"
 #include "ec_local.h"
 #include "curve448/curve448_local.h"
-
-#define ISX448(id)      ((id) == EVP_PKEY_X448)
-#define IS25519(id)     ((id) == EVP_PKEY_X25519 || (id) == EVP_PKEY_ED25519)
-#define KEYLENID(id)    (IS25519(id) ? X25519_KEYLEN \
-                                     : ((id) == EVP_PKEY_X448 ? X448_KEYLEN \
-                                                              : ED448_KEYLEN))
-#define KEYNID2TYPE(id) \
-    (IS25519(id) ?  ECX_KEY_TYPE_X25519 \
-                 : ((id) == EVP_PKEY_X448 ? ECX_KEY_TYPE_X448 \
-                                          : ((id) == EVP_PKEY_ED25519 ? ECX_KEY_TYPE_ED25519 \
-                                                                      : ECX_KEY_TYPE_ED448)))
-#define KEYLEN(p)       KEYLENID((p)->ameth->pkey_id)
-
+#include "ecx_backend.h"
 
 typedef enum {
     KEY_OP_PUBLIC,
@@ -452,6 +440,30 @@ static int ecx_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
     return rv;
 }
 
+static int ecx_generic_import_from(const OSSL_PARAM params[], void *key,
+                                   int keytype)
+{
+    EVP_PKEY *pkey = key;
+    ECX_KEY *ecx = ecx_key_new(KEYNID2TYPE(keytype), 0);
+
+    if (ecx == NULL) {
+        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!ecx_key_fromdata(ecx, params, 1)
+        || !EVP_PKEY_assign(pkey, keytype, ecx)) {
+        ecx_key_free(ecx);
+        return 0;
+    }
+    return 1;
+}
+
+static int x25519_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_X25519);
+}
+
 const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     EVP_PKEY_X25519,
     EVP_PKEY_X25519,
@@ -494,9 +506,15 @@ const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     ecx_get_priv_key,
     ecx_get_pub_key,
     ecx_pkey_dirty_cnt,
-    ecx_pkey_export_to
+    ecx_pkey_export_to,
+    x25519_import_from
 };
 
+static int x448_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_X448);
+}
+
 const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
     EVP_PKEY_X448,
     EVP_PKEY_X448,
@@ -539,7 +557,8 @@ const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
     ecx_get_priv_key,
     ecx_get_pub_key,
     ecx_pkey_dirty_cnt,
-    ecx_pkey_export_to
+    ecx_pkey_export_to,
+    x448_import_from
 };
 
 static int ecd_size25519(const EVP_PKEY *pkey)
@@ -614,6 +633,10 @@ static int ecd_sig_info_set448(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
     return 1;
 }
 
+static int ed25519_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_ED25519);
+}
 
 const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
     EVP_PKEY_ED25519,
@@ -656,9 +679,15 @@ const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
     ecx_get_priv_key,
     ecx_get_pub_key,
     ecx_pkey_dirty_cnt,
-    ecx_pkey_export_to
+    ecx_pkey_export_to,
+    ed25519_import_from
 };
 
+static int ed448_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_ED448);
+}
+
 const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = {
     EVP_PKEY_ED448,
     EVP_PKEY_ED448,
@@ -700,7 +729,8 @@ const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = {
     ecx_get_priv_key,
     ecx_get_pub_key,
     ecx_pkey_dirty_cnt,
-    ecx_pkey_export_to
+    ecx_pkey_export_to,
+    ed448_import_from
 };
 
 static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
index c8bc7e9..a04430d 100644 (file)
@@ -1,7 +1,7 @@
 LIBS=../../libcrypto
 
 $COMMON=ffc_params.c ffc_params_generate.c ffc_key_generate.c\
-        ffc_params_validate.c ffc_key_validate.c
+        ffc_params_validate.c ffc_key_validate.c ffc_backend.c
 
 SOURCE[../../libcrypto]=$COMMON
 SOURCE[../../providers/libfips.a]=$COMMON
diff --git a/crypto/ffc/ffc_backend.c b/crypto/ffc/ffc_backend.c
new file mode 100644 (file)
index 0000000..cde9e43
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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/core_names.h>
+#include "internal/ffc.h"
+
+/*
+ * The intention with the "backend" source file is to offer backend support
+ * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
+ * implementations alike.
+ */
+
+int ffc_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_p, *param_q, *param_g;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL;
+
+    if (ffc == NULL)
+        return 0;
+
+    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
+    param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_Q);
+    param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
+
+    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
+        || (param_q != NULL && !OSSL_PARAM_get_BN(param_q, &q))
+        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)))
+        goto err;
+
+    ffc_params_set0_pqg(ffc, p, q, g);
+    return 1;
+
+ err:
+    BN_free(p);
+    BN_free(q);
+    BN_free(g);
+    return 0;
+}
index ddb4e6f..c1d1a37 100644 (file)
@@ -2,7 +2,7 @@ LIBS=../../libcrypto
 
 $COMMON=rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_aid.c rsa_pk1.c \
         rsa_none.c rsa_oaep.c rsa_chk.c rsa_pss.c rsa_x931.c rsa_crpt.c \
-        rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c
+        rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c rsa_backend.c
 
 SOURCE[../../libcrypto]=$COMMON\
         rsa_saos.c rsa_err.c rsa_asn1.c rsa_depr.c rsa_ameth.c rsa_prn.c \
index 06d7a8c..58341a9 100644 (file)
@@ -1187,6 +1187,24 @@ static int rsa_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
     return rv;
 }
 
+static int rsa_pkey_import_from(const OSSL_PARAM params[], void *key)
+{
+    EVP_PKEY *pkey = key;
+    RSA *rsa = RSA_new();
+
+    if (rsa == NULL) {
+        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!rsa_fromdata(rsa, params)
+        || !EVP_PKEY_assign_RSA(pkey, rsa)) {
+        RSA_free(rsa);
+        return 0;
+    }
+    return 1;
+}
+
 const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[2] = {
     {
      EVP_PKEY_RSA,
@@ -1225,7 +1243,8 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[2] = {
      0, 0, 0, 0,
 
      rsa_pkey_dirty_cnt,
-     rsa_pkey_export_to
+     rsa_pkey_export_to,
+     rsa_pkey_import_from
     },
 
     {
@@ -1270,5 +1289,6 @@ const EVP_PKEY_ASN1_METHOD rsa_pss_asn1_meth = {
      0, 0, 0, 0,
 
      rsa_pkey_dirty_cnt,
-     rsa_pkey_export_to
+     rsa_pkey_export_to,
+     rsa_pkey_import_from
 };
diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c
new file mode 100644 (file)
index 0000000..f68d38c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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/core_names.h>
+#include <openssl/params.h>
+#include "crypto/rsa.h"
+
+/*
+ * The intention with the "backend" source file is to offer backend support
+ * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
+ * implementations alike.
+ */
+
+DEFINE_STACK_OF(BIGNUM)
+
+static int collect_numbers(STACK_OF(BIGNUM) *numbers,
+                           const OSSL_PARAM params[], const char *key)
+{
+    const OSSL_PARAM *p = NULL;
+
+    if (numbers == NULL)
+        return 0;
+
+    for (p = params; (p = OSSL_PARAM_locate_const(p, key)) != NULL; p++) {
+        BIGNUM *tmp = NULL;
+
+        if (!OSSL_PARAM_get_BN(p, &tmp)
+            || sk_BIGNUM_push(numbers, tmp) == 0)
+            return 0;
+    }
+
+    return 1;
+}
+
+int rsa_fromdata(RSA *rsa, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_n, *param_e,  *param_d;
+    BIGNUM *n = NULL, *e = NULL, *d = NULL;
+    STACK_OF(BIGNUM) *factors = NULL, *exps = NULL, *coeffs = NULL;
+    int is_private = 0;
+
+    if (rsa == NULL)
+        return 0;
+
+    param_n = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N);
+    param_e = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E);
+    param_d = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D);
+
+    if ((param_n != NULL && !OSSL_PARAM_get_BN(param_n, &n))
+        || (param_e != NULL && !OSSL_PARAM_get_BN(param_e, &e))
+        || (param_d != NULL && !OSSL_PARAM_get_BN(param_d, &d)))
+        goto err;
+
+    is_private = (d != NULL);
+
+    if (!RSA_set0_key(rsa, n, e, d))
+        goto err;
+    n = e = d = NULL;
+
+    if (is_private) {
+        if (!collect_numbers(factors = sk_BIGNUM_new_null(), params,
+                             OSSL_PKEY_PARAM_RSA_FACTOR)
+            || !collect_numbers(exps = sk_BIGNUM_new_null(), params,
+                                OSSL_PKEY_PARAM_RSA_EXPONENT)
+            || !collect_numbers(coeffs = sk_BIGNUM_new_null(), params,
+                                OSSL_PKEY_PARAM_RSA_COEFFICIENT))
+            goto err;
+
+        /* It's ok if this private key just has n, e and d */
+        if (sk_BIGNUM_num(factors) != 0
+            && !rsa_set0_all_params(rsa, factors, exps, coeffs))
+            goto err;
+    }
+
+    sk_BIGNUM_free(factors);
+    sk_BIGNUM_free(exps);
+    sk_BIGNUM_free(coeffs);
+    return 1;
+
+ err:
+    BN_free(n);
+    BN_free(e);
+    BN_free(d);
+    sk_BIGNUM_pop_free(factors, BN_free);
+    sk_BIGNUM_pop_free(exps, BN_free);
+    sk_BIGNUM_pop_free(coeffs, BN_free);
+    return 0;
+}
+
index 7c7cebd..5d5470f 100644 (file)
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/core.h>
 #include <openssl/dh.h>
 #include "internal/ffc.h"
 
@@ -19,6 +20,7 @@ int dh_generate_public_key(BN_CTX *ctx, DH *dh, const BIGNUM *priv_key,
 
 FFC_PARAMS *dh_get0_params(DH *dh);
 int dh_get0_nid(const DH *dh);
+int dh_key_fromdata(DH *dh, const OSSL_PARAM params[]);
 
 int dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret);
 int dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret);
index eab5d44..0afec99 100644 (file)
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/core.h>
 #include <openssl/dsa.h>
 #include "internal/ffc.h"
 
@@ -24,6 +25,7 @@ int dsa_sign_int(int type, const unsigned char *dgst,
 const unsigned char *dsa_algorithmidentifier_encoding(int md_nid, size_t *len);
 
 FFC_PARAMS *dsa_get0_params(DSA *dsa);
+int dsa_key_fromdata(DSA *dsa, const OSSL_PARAM params[]);
 
 int dsa_generate_public_key(BN_CTX *ctx, const DSA *dsa, const BIGNUM *priv_key,
                             BIGNUM *pub_key);
index 00b1b25..91fd9eb 100644 (file)
@@ -14,6 +14,7 @@
 # include <openssl/opensslconf.h>
 
 # ifndef OPENSSL_NO_EC
+#  include <openssl/core.h>
 #  include <openssl/ec.h>
 
 /*-
@@ -56,5 +57,12 @@ OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *eckey);
 const char *ec_curve_nid2name(int nid);
 int ec_curve_name2nid(const char *name);
 const unsigned char *ecdsa_algorithmidentifier_encoding(int md_nid, size_t *len);
+
+/* Backend support */
+int ec_key_fromdata(EC_KEY *ecx, const OSSL_PARAM params[], int include_private);
+int ec_key_domparams_fromdata(EC_KEY *ecx, const OSSL_PARAM params[]);
+int ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[]);
+int ec_set_param_ecdh_cofactor_mode(EC_KEY *ec, const OSSL_PARAM *p);
+
 # endif /* OPENSSL_NO_EC */
 #endif
index 8afb104..41020a2 100644 (file)
@@ -15,6 +15,7 @@
 
 # ifndef OPENSSL_NO_EC
 
+#  include <openssl/core.h>
 #  include <openssl/e_os2.h>
 #  include <openssl/crypto.h>
 #  include "internal/refcount.h"
@@ -107,5 +108,9 @@ int s390x_x448_mul(unsigned char u_dst[56],
                    const unsigned char u_src[56],
                    const unsigned char d_src[56]);
 
+/* Backend support */
+int ecx_key_fromdata(ECX_KEY *ecx, const OSSL_PARAM params[],
+                     int include_private);
+
 # endif /* OPENSSL_NO_EC */
 #endif
index 09335fa..a92e666 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef OSSL_INTERNAL_RSA_H
 # define OSSL_INTERNAL_RSA_H
 
+#include <openssl/core.h>
 #include <openssl/rsa.h>
 
 RSA *rsa_new_with_ctx(OPENSSL_CTX *libctx);
@@ -20,6 +21,7 @@ int rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes,
 int rsa_get0_all_params(RSA *r, STACK_OF(BIGNUM_const) *primes,
                         STACK_OF(BIGNUM_const) *exps,
                         STACK_OF(BIGNUM_const) *coeffs);
+int rsa_fromdata(RSA *rsa, const OSSL_PARAM params[]);
 
 int rsa_padding_check_PKCS1_type_2_TLS(OPENSSL_CTX *ctx, unsigned char *to,
                                        size_t tlen, const unsigned char *from,
index 006be73..fd10076 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef OSSL_INTERNAL_FFC_H
 # define OSSL_INTERNAL_FFC_H
 
+# include <openssl/core.h>
 # include <openssl/bn.h>
 # include <openssl/evp.h>
 # include <openssl/dh.h> /* Uses Error codes from DH */
@@ -154,4 +155,6 @@ int ffc_validate_public_key_partial(const FFC_PARAMS *params,
 int ffc_validate_private_key(const BIGNUM *upper, const BIGNUM *priv_key,
                              int *ret);
 
+int ffc_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[]);
+
 #endif /* OSSL_INTERNAL_FFC_H */
index c9aef88..4ec48fe 100644 (file)
@@ -39,32 +39,6 @@ static OSSL_OP_keymgmt_export_types_fn dh_export_types;
 #define DH_POSSIBLE_SELECTIONS                 \
     (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
 
-static int params_to_domparams(DH *dh, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *param_p, *param_g;
-    BIGNUM *p = NULL, *g = NULL;
-
-    if (dh == NULL)
-        return 0;
-
-    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
-    param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
-
-    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
-        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)))
-        goto err;
-
-    if (!DH_set0_pqg(dh, p, NULL, g))
-        goto err;
-
-    return 1;
-
- err:
-    BN_free(p);
-    BN_free(g);
-    return 0;
-}
-
 static int domparams_to_params(DH *dh, OSSL_PARAM_BLD *tmpl)
 {
     const BIGNUM *dh_p = NULL, *dh_g = NULL;
@@ -83,47 +57,6 @@ static int domparams_to_params(DH *dh, OSSL_PARAM_BLD *tmpl)
     return 1;
 }
 
-static int params_to_key(DH *dh, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *param_priv_key, *param_pub_key;
-    BIGNUM *priv_key = NULL, *pub_key = NULL;
-
-    if (dh == NULL)
-        return 0;
-
-    if (!params_to_domparams(dh, params))
-        return 0;
-
-    param_priv_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
-    param_pub_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
-
-    /*
-     * DH documentation says that a public key must be present if a
-     * private key is present.
-     * We want to have at least a public key either way, so we end up
-     * requiring it unconditionally.
-     */
-    if (param_pub_key == NULL)
-        return 0;
-
-    if ((param_priv_key != NULL
-         && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
-        || !OSSL_PARAM_get_BN(param_pub_key, &pub_key))
-        goto err;
-
-    if (!DH_set0_key(dh, pub_key, priv_key))
-        goto err;
-
-    return 1;
-
- err:
-    BN_clear_free(priv_key);
-    BN_free(pub_key);
-    return 0;
-}
-
 static int key_to_params(DH *dh, OSSL_PARAM_BLD *tmpl)
 {
     const BIGNUM *priv_key = NULL, *pub_key = NULL;
@@ -204,9 +137,9 @@ static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
         ok = 1;
 
     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
-        ok = ok && params_to_domparams(dh, params);
+        ok = ok && ffc_fromdata(dh_get0_params(dh), params);
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
-        ok = ok && params_to_key(dh, params);
+        ok = ok && dh_key_fromdata(dh, params);
 
     return ok;
 }
index a8ef074..080ba74 100644 (file)
@@ -39,35 +39,6 @@ static OSSL_OP_keymgmt_export_types_fn dsa_export_types;
 #define DSA_POSSIBLE_SELECTIONS                 \
     (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
 
-static int params_to_domparams(DSA *dsa, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *param_p, *param_q, *param_g;
-    BIGNUM *p = NULL, *q = NULL, *g = NULL;
-
-    if (dsa == NULL)
-        return 0;
-
-    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
-    param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_Q);
-    param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
-
-    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
-        || (param_q != NULL && !OSSL_PARAM_get_BN(param_q, &q))
-        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)))
-        goto err;
-
-    if (!DSA_set0_pqg(dsa, p, q, g))
-        goto err;
-
-    return 1;
-
- err:
-    BN_free(p);
-    BN_free(q);
-    BN_free(g);
-    return 0;
-}
-
 static int domparams_to_params(DSA *dsa, OSSL_PARAM_BLD *tmpl)
 {
     const BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
@@ -89,46 +60,6 @@ static int domparams_to_params(DSA *dsa, OSSL_PARAM_BLD *tmpl)
     return 1;
 }
 
-static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *param_priv_key, *param_pub_key;
-    BIGNUM *priv_key = NULL, *pub_key = NULL;
-
-    if (dsa == NULL)
-        return 0;
-
-    if (!params_to_domparams(dsa, params))
-        return 0;
-
-    param_priv_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
-    param_pub_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
-
-    /*
-     * DSA documentation says that a public key must be present if a private key
-     * is.
-     */
-    if (param_priv_key != NULL && param_pub_key == NULL)
-        return 0;
-
-    if ((param_priv_key != NULL
-         && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
-        || (param_pub_key != NULL
-            && !OSSL_PARAM_get_BN(param_pub_key, &pub_key)))
-        goto err;
-
-    if (pub_key != NULL && !DSA_set0_key(dsa, pub_key, priv_key))
-        goto err;
-
-    return 1;
-
- err:
-    BN_clear_free(priv_key);
-    BN_free(pub_key);
-    return 0;
-}
-
 static int key_to_params(DSA *dsa, OSSL_PARAM_BLD *tmpl)
 {
     const BIGNUM *priv_key = NULL, *pub_key = NULL;
@@ -211,9 +142,9 @@ static int dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
         ok = 1;
 
     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
-        ok = ok && params_to_domparams(dsa, params);
+        ok = ok && ffc_fromdata(dsa_get0_params(dsa), params);
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
-        ok = ok && params_to_key(dsa, params);
+        ok = ok && dsa_key_fromdata(dsa, params);
 
     return ok;
 }
index 4f8f44d..354ca0c 100644 (file)
@@ -55,55 +55,6 @@ const char *ec_query_operation_name(int operation_id)
     return NULL;
 }
 
-static ossl_inline
-int params_to_domparams(EC_KEY *ec, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *param_ec_name;
-    EC_GROUP *ecg = NULL;
-    char *curve_name = NULL;
-    int ok = 0;
-
-    if (ec == NULL)
-        return 0;
-
-    param_ec_name = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_NAME);
-    if (param_ec_name == NULL) {
-        /* explicit parameters */
-
-        /*
-         * TODO(3.0): should we support explicit parameters curves?
-         */
-        return 0;
-    } else {
-        /* named curve */
-        int curve_nid;
-
-        if (!OSSL_PARAM_get_utf8_string(param_ec_name, &curve_name, 0)
-                || curve_name == NULL
-                || (curve_nid = ec_curve_name2nid(curve_name)) == NID_undef)
-            goto err;
-
-        if ((ecg = EC_GROUP_new_by_curve_name_ex(ec_key_get_libctx(ec),
-                                                 curve_nid)) == NULL)
-            goto err;
-    }
-
-    if (!EC_KEY_set_group(ec, ecg))
-        goto err;
-
-    /*
-     * TODO(3.0): if the group has changed, should we invalidate the private and
-     * public key?
-     */
-
-    ok = 1;
-
- err:
-    OPENSSL_free(curve_name);
-    EC_GROUP_free(ecg);
-    return ok;
-}
-
 static ossl_inline
 int domparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
 {
@@ -141,120 +92,6 @@ int domparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
     return 1;
 }
 
-/*
- * Callers of params_to_key MUST make sure that params_to_domparams has been
- * called before!
- *
- * This function only imports the bare keypair, domain parameters and other
- * parameters are imported separately, and domain parameters are required to
- * define a keypair.
- */
-static ossl_inline
-int params_to_key(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
-{
-    const OSSL_PARAM *param_priv_key, *param_pub_key;
-    BN_CTX *ctx = NULL;
-    BIGNUM *priv_key = NULL;
-    unsigned char *pub_key = NULL;
-    size_t pub_key_len;
-    const EC_GROUP *ecg = NULL;
-    EC_POINT *pub_point = NULL;
-    int ok = 0;
-
-    ecg = EC_KEY_get0_group(ec);
-    if (ecg == NULL)
-        return 0;
-
-    param_priv_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
-    param_pub_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
-
-    ctx = BN_CTX_new_ex(ec_key_get_libctx(ec));
-    if (ctx == NULL)
-        goto err;
-    /*
-     * We want to have at least a public key either way, so we end up
-     * requiring it unconditionally.
-     */
-    if (param_pub_key == NULL
-            || !OSSL_PARAM_get_octet_string(param_pub_key,
-                                            (void **)&pub_key, 0, &pub_key_len)
-            || (pub_point = EC_POINT_new(ecg)) == NULL
-            || !EC_POINT_oct2point(ecg, pub_point,
-                                   pub_key, pub_key_len, ctx))
-        goto err;
-
-    if (param_priv_key != NULL && include_private) {
-        int fixed_top;
-        const BIGNUM *order;
-
-        /*
-         * Key import/export should never leak the bit length of the secret
-         * scalar in the key.
-         *
-         * For this reason, on export we use padded BIGNUMs with fixed length.
-         *
-         * When importing we also should make sure that, even if short lived,
-         * the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as
-         * soon as possible, so that any processing of this BIGNUM might opt for
-         * constant time implementations in the backend.
-         *
-         * Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have
-         * to preallocate the BIGNUM internal buffer to a fixed public size big
-         * enough that operations performed during the processing never trigger
-         * a realloc which would leak the size of the scalar through memory
-         * accesses.
-         *
-         * Fixed Length
-         * ------------
-         *
-         * The order of the large prime subgroup of the curve is our choice for
-         * a fixed public size, as that is generally the upper bound for
-         * generating a private key in EC cryptosystems and should fit all valid
-         * secret scalars.
-         *
-         * For padding on export we just use the bit length of the order
-         * converted to bytes (rounding up).
-         *
-         * For preallocating the BIGNUM storage we look at the number of "words"
-         * required for the internal representation of the order, and we
-         * preallocate 2 extra "words" in case any of the subsequent processing
-         * might temporarily overflow the order length.
-         */
-        order = EC_GROUP_get0_order(ecg);
-        if (order == NULL || BN_is_zero(order))
-            goto err;
-
-        fixed_top = bn_get_top(order) + 2;
-
-        if ((priv_key = BN_secure_new()) == NULL)
-            goto err;
-        if (bn_wexpand(priv_key, fixed_top) == NULL)
-            goto err;
-        BN_set_flags(priv_key, BN_FLG_CONSTTIME);
-
-        if (!OSSL_PARAM_get_BN(param_priv_key, &priv_key))
-            goto err;
-    }
-
-    if (priv_key != NULL
-            && !EC_KEY_set_private_key(ec, priv_key))
-        goto err;
-
-    if (!EC_KEY_set_public_key(ec, pub_point))
-        goto err;
-
-    ok = 1;
-
- err:
-    BN_CTX_free(ctx);
-    BN_clear_free(priv_key);
-    OPENSSL_free(pub_key);
-    EC_POINT_free(pub_point);
-    return ok;
-}
-
 /*
  * Callers of key_to_params MUST make sure that domparams_to_params is also
  * called!
@@ -346,56 +183,6 @@ int key_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl, int include_private
     return ret;
 }
 
-static ossl_inline
-int ec_set_param_ecdh_cofactor_mode(EC_KEY *ec, const OSSL_PARAM *p)
-{
-    const EC_GROUP *ecg = EC_KEY_get0_group(ec);
-    const BIGNUM *cofactor;
-    int mode;
-
-    if (!OSSL_PARAM_get_int(p, &mode))
-        return 0;
-
-    /*
-     * mode can be only 0 for disable, or 1 for enable here.
-     *
-     * This is in contrast with the same parameter on an ECDH EVP_PKEY_CTX that
-     * also supports mode == -1 with the meaning of "reset to the default for
-     * the associated key".
-     */
-    if (mode < 0 || mode > 1)
-        return 0;
-
-    if ((cofactor = EC_GROUP_get0_cofactor(ecg)) == NULL )
-        return 0;
-
-    /* ECDH cofactor mode has no effect if cofactor is 1 */
-    if (BN_is_one(cofactor))
-        return 1;
-
-    if (mode == 1)
-        EC_KEY_set_flags(ec, EC_FLAG_COFACTOR_ECDH);
-    else if (mode == 0)
-        EC_KEY_clear_flags(ec, EC_FLAG_COFACTOR_ECDH);
-
-    return 1;
-}
-
-static ossl_inline
-int params_to_otherparams(EC_KEY *ec, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *p;
-
-    if (ec == NULL)
-        return 0;
-
-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH);
-    if (p != NULL && !ec_set_param_ecdh_cofactor_mode(ec, p))
-        return 0;
-
-    return 1;
-}
-
 static ossl_inline
 int otherparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
 {
@@ -509,15 +296,15 @@ int ec_import(void *keydata, int selection, const OSSL_PARAM params[])
         return 0;
 
     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
-        ok = ok && params_to_domparams(ec, params);
+        ok = ok && ec_key_domparams_fromdata(ec, params);
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
         int include_private =
             selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
 
-        ok = ok && params_to_key(ec, params, include_private);
+        ok = ok && ec_key_fromdata(ec, params, include_private);
     }
     if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
-        ok = ok && params_to_otherparams(ec, params);
+        ok = ok && ec_key_otherparams_fromdata(ec, params);
 
     return ok;
 }
index 121980e..221287b 100644 (file)
@@ -74,9 +74,8 @@ static int ecx_has(void *keydata, int selection)
 static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
     ECX_KEY *key = keydata;
-    size_t privkeylen = 0, pubkeylen;
-    const OSSL_PARAM *param_priv_key = NULL, *param_pub_key;
-    unsigned char *pubkey;
+    int ok = 1;
+    int include_private = 0;
 
     if (key == NULL)
         return 0;
@@ -84,38 +83,11 @@ static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[])
     if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
         return 0;
 
-    param_pub_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
-
-    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
-        param_priv_key =
-            OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
-    /*
-     * If a private key is present then a public key must also be present.
-     * Alternatively we've just got a public key.
-     */
-    if (param_pub_key == NULL)
-        return 0;
-
-    if (param_priv_key != NULL
-             && !OSSL_PARAM_get_octet_string(param_priv_key,
-                                            (void **)&key->privkey, key->keylen,
-                                             &privkeylen))
-        return 0;
-
-    pubkey = key->pubkey;
-    if (!OSSL_PARAM_get_octet_string(param_pub_key,
-                                     (void **)&pubkey,
-                                     sizeof(key->pubkey), &pubkeylen))
-        return 0;
-
-    if (pubkeylen != key->keylen
-            || (param_priv_key != NULL && privkeylen != key->keylen))
-        return 0;
-
-    key->haspubkey = 1;
+    include_private = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0);
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+        ok = ok && ecx_key_fromdata(key, params, include_private);
 
-    return 1;
+    return ok;
 }
 
 static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl)
index 2826d33..176cf34 100644 (file)
@@ -51,80 +51,6 @@ static OSSL_OP_keymgmt_export_types_fn rsa_export_types;
 DEFINE_STACK_OF(BIGNUM)
 DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM)
 
-static int collect_numbers(STACK_OF(BIGNUM) *numbers,
-                           const OSSL_PARAM params[], const char *key)
-{
-    const OSSL_PARAM *p = NULL;
-
-    if (numbers == NULL)
-        return 0;
-
-    for (p = params; (p = OSSL_PARAM_locate_const(p, key)) != NULL; p++) {
-        BIGNUM *tmp = NULL;
-
-        if (!OSSL_PARAM_get_BN(p, &tmp))
-            return 0;
-        sk_BIGNUM_push(numbers, tmp);
-    }
-
-    return 1;
-}
-
-static int params_to_key(RSA *rsa, const OSSL_PARAM params[])
-{
-    const OSSL_PARAM *param_n, *param_e,  *param_d;
-    BIGNUM *n = NULL, *e = NULL, *d = NULL;
-    STACK_OF(BIGNUM) *factors = NULL, *exps = NULL, *coeffs = NULL;
-    int is_private = 0;
-
-    if (rsa == NULL)
-        return 0;
-
-    param_n = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N);
-    param_e = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E);
-    param_d = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D);
-
-    if ((param_n != NULL && !OSSL_PARAM_get_BN(param_n, &n))
-        || (param_e != NULL && !OSSL_PARAM_get_BN(param_e, &e))
-        || (param_d != NULL && !OSSL_PARAM_get_BN(param_d, &d)))
-        goto err;
-
-    is_private = (d != NULL);
-
-    if (!RSA_set0_key(rsa, n, e, d))
-        goto err;
-    n = e = d = NULL;
-
-    if (is_private) {
-        if (!collect_numbers(factors = sk_BIGNUM_new_null(), params,
-                             OSSL_PKEY_PARAM_RSA_FACTOR)
-            || !collect_numbers(exps = sk_BIGNUM_new_null(), params,
-                                OSSL_PKEY_PARAM_RSA_EXPONENT)
-            || !collect_numbers(coeffs = sk_BIGNUM_new_null(), params,
-                                OSSL_PKEY_PARAM_RSA_COEFFICIENT))
-            goto err;
-
-        /* It's ok if this private key just has n, e and d */
-        if (sk_BIGNUM_num(factors) != 0
-            && !rsa_set0_all_params(rsa, factors, exps, coeffs))
-            goto err;
-    }
-
-    sk_BIGNUM_free(factors);
-    sk_BIGNUM_free(exps);
-    sk_BIGNUM_free(coeffs);
-    return 1;
-
- err:
-    BN_free(n);
-    BN_free(e);
-    BN_free(d);
-    sk_BIGNUM_pop_free(factors, BN_free);
-    sk_BIGNUM_pop_free(exps, BN_free);
-    sk_BIGNUM_pop_free(coeffs, BN_free);
-    return 0;
-}
-
 static int export_numbers(OSSL_PARAM_BLD *tmpl, const char *key,
                           STACK_OF(BIGNUM_const) *numbers)
 {
@@ -240,7 +166,7 @@ static int rsa_import(void *keydata, int selection, const OSSL_PARAM params[])
     /* TODO(3.0) PSS and OAEP should bring on parameters */
 
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
-        ok = ok && params_to_key(rsa, params);
+        ok = ok && rsa_fromdata(rsa, params);
 
     return ok;
 }