/*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * 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
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/bn.h>
-#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/params.h>
+#include "crypto/bn.h"
+#include "crypto/ec.h"
#include "internal/param_build.h"
#include "prov/implementations.h"
#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
static OSSL_OP_keymgmt_new_fn ec_newdata;
static OSSL_OP_keymgmt_free_fn ec_freedata;
static OSSL_OP_keymgmt_set_params_fn ec_set_params;
static OSSL_OP_keymgmt_settable_params_fn ec_settable_params;
static OSSL_OP_keymgmt_has_fn ec_has;
+static OSSL_OP_keymgmt_match_fn ec_match;
+static OSSL_OP_keymgmt_validate_fn ec_validate;
static OSSL_OP_keymgmt_import_fn ec_import;
static OSSL_OP_keymgmt_import_types_fn ec_import_types;
static OSSL_OP_keymgmt_export_fn ec_export;
switch (operation_id) {
case OSSL_OP_KEYEXCH:
return "ECDH";
-#if 0
case OSSL_OP_SIGNATURE:
- return deflt_signature;
-#endif
+ return "ECDSA";
}
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 = OBJ_sn2nid(curve_name)) == NID_undef)
- goto err;
-
- if ((ecg = EC_GROUP_new_by_curve_name(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)
{
/* named curve */
const char *curve_name = NULL;
- if ((curve_name = OBJ_nid2sn(curve_nid)) == NULL)
+ if ((curve_name = ec_curve_nid2name(curve_nid)) == NULL)
return 0;
- if (!ossl_param_bld_push_utf8_string(tmpl, OSSL_PKEY_PARAM_EC_NAME, curve_name, 0))
+ if (!ossl_param_bld_push_utf8_string(tmpl, OSSL_PKEY_PARAM_EC_NAME,
+ curve_name, 0))
return 0;
}
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;
- 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);
-
- /*
- * 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, NULL))
- goto err;
-
- if (param_priv_key != NULL && include_private
- && !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_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!
pub_key, pub_key_len))
goto err;
- if (priv_key != NULL && include_private
- && !ossl_param_bld_push_BN(tmpl,
- OSSL_PKEY_PARAM_PRIV_KEY,
- priv_key))
- goto err;
+ if (priv_key != NULL && include_private) {
+ size_t sz;
+ int ecbits;
+
+ /*
+ * 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.
+ */
+ ecbits = EC_GROUP_order_bits(ecg);
+ if (ecbits <= 0)
+ goto err;
+ sz = (ecbits + 7 ) / 8;
+ if (!ossl_param_bld_push_BN_pad(tmpl,
+ OSSL_PKEY_PARAM_PRIV_KEY,
+ priv_key, sz))
+ goto err;
+ }
ret = 1;
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)
{
static
void *ec_newdata(void *provctx)
{
- return EC_KEY_new();
+ return EC_KEY_new_ex(PROV_LIBRARY_CONTEXT_OF(provctx));
}
static
EC_KEY *ec = keydata;
int ok = 0;
- if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
- ok = 1;
+ if (ec != NULL) {
+ if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
+ if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+ ok = ok && (EC_KEY_get0_group(ec) != NULL);
+ /*
+ * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be
+ * available, so no extra check is needed other than the previous one
+ * against EC_POSSIBLE_SELECTIONS.
+ */
+ }
+ return ok;
+}
+
+static int ec_match(const void *keydata1, const void *keydata2, int selection)
+{
+ const EC_KEY *ec1 = keydata1;
+ const EC_KEY *ec2 = keydata2;
+ const EC_GROUP *group_a = EC_KEY_get0_group(ec1);
+ const EC_GROUP *group_b = EC_KEY_get0_group(ec2);
+ int ok = 1;
- if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
- ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
- ok = ok && (EC_KEY_get0_group(ec) != NULL);
- /*
- * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be available,
- * so no extra check is needed other than the previous one against
- * EC_POSSIBLE_SELECTIONS.
- */
+ ok = ok && group_a != NULL && group_b != NULL
+ && EC_GROUP_cmp(group_a, group_b, NULL) == 0;
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+ const BIGNUM *pa = EC_KEY_get0_private_key(ec1);
+ const BIGNUM *pb = EC_KEY_get0_private_key(ec2);
+
+ ok = ok && BN_cmp(pa, pb) == 0;
+ }
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+ const EC_POINT *pa = EC_KEY_get0_public_key(ec1);
+ const EC_POINT *pb = EC_KEY_get0_public_key(ec2);
+ ok = ok && EC_POINT_cmp(group_b, pa, pb, NULL);
+ }
return ok;
}
int ec_import(void *keydata, int selection, const OSSL_PARAM params[])
{
EC_KEY *ec = keydata;
- int ok = 0;
+ int ok = 1;
if (ec == NULL)
return 0;
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;
}
return 1;
}
+static
+int ec_validate(void *keydata, int selection)
+{
+ EC_KEY *eck = keydata;
+ int ok = 0;
+ BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(eck));
+
+ if (ctx == NULL)
+ return 0;
+
+ if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+ ok = ok && EC_GROUP_check(EC_KEY_get0_group(eck), ctx);
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && ec_key_public_check(eck, ctx);
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && ec_key_private_check(eck);
+
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR)
+ ok = ok && ec_key_pairwise_check(eck, ctx);
+
+ BN_CTX_free(ctx);
+ return ok;
+}
+
const OSSL_DISPATCH ec_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata },
{ OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))ec_set_params },
{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))ec_settable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has },
+ { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match },
+ { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))ec_validate },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export },