* https://www.openssl.org/source/license.html
*/
+/*
+ * ECDH and ECDSA low level APIs are deprecated for public use, but still ok
+ * for internal use.
+ */
+#include "internal/deprecated.h"
+
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/x509.h>
#include <openssl/asn1t.h>
#include "crypto/asn1.h"
#include "crypto/evp.h"
+#include <openssl/core_names.h>
+#include "internal/param_build.h"
#include "ec_local.h"
#ifndef OPENSSL_NO_CMS
static int ecdh_cms_encrypt(CMS_RecipientInfo *ri);
#endif
-static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key)
+static int eckey_param2type(int *pptype, void **ppval, const EC_KEY *ec_key)
{
const EC_GROUP *group;
int nid;
static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
{
- EC_KEY *ec_key = pkey->pkey.ec;
+ const EC_KEY *ec_key = pkey->pkey.ec;
void *pval = NULL;
int ptype;
unsigned char *penc = NULL, *p;
if (EVP_PKEY_id(pkey) == EVP_PKEY_SM2) {
/* For SM2, the only valid digest-alg is SM3 */
*(int *)arg2 = NID_sm3;
- } else {
- *(int *)arg2 = NID_sha256;
+ return 2; /* Make it mandatory */
}
+ *(int *)arg2 = NID_sha256;
return 1;
case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
return EC_GROUP_check(eckey->group, NULL);
}
+static
+size_t ec_pkey_dirty_cnt(const EVP_PKEY *pkey)
+{
+ return pkey->pkey.ec->dirty_cnt;
+}
+
+static ossl_inline
+int ecparams_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl)
+{
+ const EC_GROUP *ecg;
+ int curve_nid;
+
+ if (eckey == NULL)
+ return 0;
+
+ ecg = EC_KEY_get0_group(eckey);
+ if (ecg == NULL)
+ return 0;
+
+ curve_nid = EC_GROUP_get_curve_name(ecg);
+
+ if (curve_nid == NID_undef) {
+ /* explicit parameters */
+
+ /*
+ * TODO(3.0): should we support explicit parameters curves?
+ */
+ return 0;
+ } else {
+ /* named curve */
+ const char *curve_name = NULL;
+
+ if ((curve_name = OBJ_nid2sn(curve_nid)) == NULL)
+ return 0;
+
+ if (!ossl_param_bld_push_utf8_string(tmpl, OSSL_PKEY_PARAM_EC_NAME, curve_name, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+static
+int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
+ EVP_KEYMGMT *to_keymgmt)
+{
+ const EC_KEY *eckey = NULL;
+ const EC_GROUP *ecg = NULL;
+ unsigned char *pub_key_buf = NULL;
+ size_t pub_key_buflen;
+ OSSL_PARAM_BLD tmpl;
+ OSSL_PARAM *params = NULL;
+ const BIGNUM *priv_key = NULL;
+ const EC_POINT *pub_point = NULL;
+ int rv = 0;
+
+ if (from == NULL
+ || (eckey = from->pkey.ec) == NULL
+ || (ecg = EC_KEY_get0_group(eckey)) == NULL)
+ return 0;
+
+ ossl_param_bld_init(&tmpl);
+
+ /* export the domain parameters */
+ if (!ecparams_to_params(eckey, &tmpl))
+ return 0;
+
+ priv_key = EC_KEY_get0_private_key(eckey);
+ pub_point = EC_KEY_get0_public_key(eckey);
+
+ /* public_key must be present, priv_key is optional */
+ if (pub_point == NULL)
+ return 0;
+
+ /* convert pub_point to a octet string according to the SECG standard */
+ if ((pub_key_buflen = EC_POINT_point2buf(ecg, pub_point,
+ POINT_CONVERSION_COMPRESSED,
+ &pub_key_buf, NULL)) == 0)
+ return 0;
+
+ if (!ossl_param_bld_push_octet_string(&tmpl,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ pub_key_buf,
+ pub_key_buflen))
+ goto err;
+
+ if (priv_key != NULL) {
+ size_t sz;
+ int ecbits;
+ int ecdh_cofactor_mode;
+
+ /*
+ * 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;
+
+ /*
+ * The ECDH Cofactor Mode is defined only if the EC_KEY actually
+ * contains a private key, so we check for the flag and export it only
+ * in this case.
+ */
+ ecdh_cofactor_mode =
+ (EC_KEY_get_flags(eckey) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
+
+ /* Export the ECDH_COFACTOR_MODE parameter */
+ if (!ossl_param_bld_push_int(&tmpl,
+ OSSL_PKEY_PARAM_USE_COFACTOR_ECDH,
+ ecdh_cofactor_mode))
+ goto err;
+ }
+
+ params = ossl_param_bld_to_param(&tmpl);
+
+ /* We export, the provider imports */
+ rv = evp_keymgmt_import(to_keymgmt, to_keydata, OSSL_KEYMGMT_SELECT_ALL,
+ params);
+
+ err:
+ ossl_param_bld_free(params);
+ OPENSSL_free(pub_key_buf);
+ return rv;
+}
+
const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = {
EVP_PKEY_EC,
EVP_PKEY_EC,
ec_pkey_check,
ec_pkey_public_check,
- ec_pkey_param_check
+ ec_pkey_param_check,
+
+ 0, /* set_priv_key */
+ 0, /* set_pub_key */
+ 0, /* get_priv_key */
+ 0, /* get_pub_key */
+
+ ec_pkey_dirty_cnt,
+ ec_pkey_export_to
};
#if !defined(OPENSSL_NO_SM2)