diff --git a/src/libp11-int.h b/src/libp11-int.h index 5c2b295f..54a52bcd 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -336,6 +336,10 @@ extern int pkcs11_generate_key(PKCS11_TOKEN * token, int algorithm, unsigned int bits, char *label, unsigned char* id, size_t id_len); +/* Generate and store a private EC key on the token */ +extern int pkcs11_generate_ec_key(PKCS11_TOKEN * token, const char *curve, + char *label, unsigned char* id, size_t id_len); + /* Get the RSA key modulus size (in bytes) */ extern int pkcs11_get_key_size(PKCS11_KEY *); diff --git a/src/libp11.exports b/src/libp11.exports index 4aa37218..d1f11f31 100644 --- a/src/libp11.exports +++ b/src/libp11.exports @@ -29,6 +29,7 @@ PKCS11_init_token PKCS11_init_pin PKCS11_change_pin PKCS11_generate_key +PKCS11_generate_ec_key PKCS11_store_private_key PKCS11_store_public_key PKCS11_store_certificate diff --git a/src/libp11.h b/src/libp11.h index e3da4181..bf2cac6b 100644 --- a/src/libp11.h +++ b/src/libp11.h @@ -452,6 +452,20 @@ P11_DEPRECATED_FUNC extern int PKCS11_get_key_modulus(PKCS11_KEY *, BIGNUM **); /* Get the RSA key public exponent as BIGNUM */ P11_DEPRECATED_FUNC extern int PKCS11_get_key_exponent(PKCS11_KEY *, BIGNUM **); +/** + * Generate a private EC key on the token + * + * @param token token returned by PKCS11_find_token() + * @param curve EC curve name + * @param label label for this key + * @param id bytes to use as the id value + * @param id_len length of the id value + * @retval 0 success + * @retval -1 error + */ +extern int PKCS11_generate_ec_key(PKCS11_TOKEN *token, const char *curve, + char *label, unsigned char* id, size_t id_len); + /* Sign with the EC private key */ P11_DEPRECATED_FUNC extern int PKCS11_ecdsa_sign( const unsigned char *m, unsigned int m_len, diff --git a/src/p11_front.c b/src/p11_front.c index 3a7bcd57..7b79bceb 100644 --- a/src/p11_front.c +++ b/src/p11_front.c @@ -290,6 +290,14 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, return pkcs11_generate_key(token, algorithm, bits, label, id, id_len); } +int PKCS11_generate_ec_key(PKCS11_TOKEN *token, const char *curve, + char *label, unsigned char *id, size_t id_len) +{ + if (check_token_fork(token) < 0) + return -1; + return pkcs11_generate_ec_key(token, curve, label, id, id_len); +} + int PKCS11_get_key_size(PKCS11_KEY *key) { if (check_key_fork(key) < 0) diff --git a/src/p11_key.c b/src/p11_key.c index e2ffe3ba..b8f916a6 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -194,6 +194,98 @@ int pkcs11_generate_key(PKCS11_TOKEN *token, int algorithm, unsigned int bits, return 0; } +/** + * Generate a keyPair directly on token + */ +int pkcs11_generate_ec_key(PKCS11_TOKEN *token, const char *curve, + char *label, unsigned char* id, size_t id_len) { + + PKCS11_SLOT *slot = TOKEN2SLOT(token); + PKCS11_CTX *ctx = TOKEN2CTX(token); + PKCS11_SLOT_private *spriv = PRIVSLOT(slot); + + CK_ATTRIBUTE pubkey_attrs[32]; + CK_ATTRIBUTE privkey_attrs[32]; + unsigned int n_pub = 0, n_priv = 0; + CK_MECHANISM mechanism = { + CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 + }; + CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; + int rv; + + unsigned char *ecdsa_params = NULL; + int ecdsa_params_len = 0; + unsigned char *tmp = NULL; + ASN1_OBJECT *curve_obj = NULL; + int curve_nid = NID_undef; + + /* make sure we have a session */ + if (!spriv->haveSession && PKCS11_open_session(slot, 1)) + return -1; + + curve_nid = EC_curve_nist2nid(curve); + if (curve_nid == NID_undef) + curve_nid = OBJ_sn2nid(curve); + if (curve_nid == NID_undef) + curve_nid = OBJ_ln2nid(curve); + if (curve_nid == NID_undef) + return -1; + + curve_obj = OBJ_nid2obj(curve_nid); + if (!curve_obj) + return -1; + ecdsa_params_len = i2d_ASN1_OBJECT(curve_obj, NULL); + ecdsa_params = (unsigned char *)OPENSSL_malloc(ecdsa_params_len); + if (!ecdsa_params) + return -1; + tmp = ecdsa_params; + i2d_ASN1_OBJECT(curve_obj, &tmp); + + /* pubkey attributes */ + pkcs11_addattr(pubkey_attrs + n_pub++, CKA_ID, id, id_len); + if (label) + pkcs11_addattr_s(pubkey_attrs + n_pub++, CKA_LABEL, label); + pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_TOKEN, TRUE); + pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_DERIVE, TRUE); + pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_WRAP, FALSE); + pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_VERIFY, TRUE); + pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_VERIFY_RECOVER, FALSE); + pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_ENCRYPT, FALSE); + pkcs11_addattr(pubkey_attrs + n_pub++, CKA_ECDSA_PARAMS, ecdsa_params, ecdsa_params_len); + + /* privkey attributes */ + pkcs11_addattr(privkey_attrs + n_priv++, CKA_ID, id, id_len); + if (label) + pkcs11_addattr_s(privkey_attrs + n_priv++, CKA_LABEL, label); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_TOKEN, TRUE); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_PRIVATE, TRUE); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_SENSITIVE, TRUE); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_DERIVE, TRUE); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_UNWRAP, FALSE); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_SIGN, TRUE); + pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_DECRYPT, FALSE); + + /* call the pkcs11 module to create the key pair */ + rv = CRYPTOKI_call(ctx, C_GenerateKeyPair( + spriv->session, + &mechanism, + pubkey_attrs, + n_pub, + privkey_attrs, + n_priv, + &pub_key_obj, + &priv_key_obj + )); + + /* zap all memory allocated when building the template */ + pkcs11_zap_attrs(privkey_attrs, n_priv); + pkcs11_zap_attrs(pubkey_attrs, n_pub); + OPENSSL_free(ecdsa_params); + + CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); + return 0; +} + /* * Store a private key on the token */