Merge pull request #1960 from Jakuje/eddsa
Add support for (X)EdDSA keys in OpenPGP driver
This commit is contained in:
commit
5f9085fedb
|
@ -2002,6 +2002,10 @@ static int asn1_encode(sc_context_t *ctx, const struct sc_asn1_entry *asn1,
|
|||
u8 *obj = NULL, *buf = NULL, *tmp;
|
||||
size_t total = 0, objsize;
|
||||
|
||||
if (asn1 == NULL) {
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
for (idx = 0; asn1[idx].name != NULL; idx++) {
|
||||
r = asn1_encode_entry(ctx, &asn1[idx], &obj, &objsize, depth);
|
||||
if (r) {
|
||||
|
|
|
@ -66,7 +66,7 @@ static const struct sc_atr_table pgp_atrs[] = {
|
|||
{ "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, default_cardname_v2, SC_CARD_TYPE_OPENPGP_V2, 0, NULL },
|
||||
{
|
||||
"3b:da:11:ff:81:b1:fe:55:1f:03:00:31:84:73:80:01:80:00:90:00:e4",
|
||||
"ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:ff:ff:ff",
|
||||
"ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:ff:ff:00",
|
||||
"Gnuk v1.x.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL
|
||||
},
|
||||
{ "3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1", NULL, "Yubikey NEO (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL },
|
||||
|
@ -87,7 +87,8 @@ static struct sc_card_driver pgp_drv = {
|
|||
};
|
||||
|
||||
|
||||
static pgp_ec_curves_t ec_curves[] = {
|
||||
/* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
|
||||
static pgp_ec_curves_t ec_curves_openpgp[] = {
|
||||
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */
|
||||
{{{1, 3, 132, 0, 34, -1}}, 384}, /* ansiX9p384r1 */
|
||||
{{{1, 3, 132, 0, 35, -1}}, 521}, /* ansiX9p521r1 */
|
||||
|
@ -97,11 +98,14 @@ static pgp_ec_curves_t ec_curves[] = {
|
|||
{{{-1}}, 0} /* This entry must not be touched. */
|
||||
};
|
||||
|
||||
struct sc_object_id curve25519_oid = {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}};
|
||||
|
||||
/* Gnuk supports NIST, SECG and Curve25519 since version 1.2 */
|
||||
static pgp_ec_curves_t ec_curves_gnuk[] = {
|
||||
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */
|
||||
{{{1, 3, 132, 0, 10, -1}}, 256}, /* secp256k1 */
|
||||
/*{{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, //cv25519
|
||||
{{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, // ed25519 */
|
||||
{{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */
|
||||
{{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, /* ed25519 for signatures => CKK_EC_EDWARDS */
|
||||
{{{-1}}, 0} /* This entry must not be touched. */
|
||||
};
|
||||
|
||||
|
@ -448,6 +452,13 @@ pgp_init(sc_card_t *card)
|
|||
: (priv->bcd_version < OPENPGP_CARD_3_4) ? pgp33_objects
|
||||
: pgp34_objects;
|
||||
|
||||
/* With gnuk, we use different curves */
|
||||
if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
|
||||
priv->ec_curves = ec_curves_gnuk;
|
||||
} else {
|
||||
priv->ec_curves = ec_curves_openpgp;
|
||||
}
|
||||
|
||||
/* change file path to MF for re-use in MF */
|
||||
sc_format_path("3f00", &file->path);
|
||||
|
||||
|
@ -500,22 +511,15 @@ pgp_init(sc_card_t *card)
|
|||
switch (card->type) {
|
||||
case SC_CARD_TYPE_OPENPGP_V3:
|
||||
/* RSA 1024 was removed for v3+ */
|
||||
_sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
|
||||
_sc_card_add_rsa_alg(card, 3072, flags_rsa, 0);
|
||||
_sc_card_add_rsa_alg(card, 4096, flags_rsa, 0);
|
||||
/* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
|
||||
for (i=0; ec_curves[i].oid.value[0] >= 0; i++)
|
||||
{
|
||||
_sc_card_add_ec_alg(card, ec_curves[i].size, flags_ecc, ext_flags, &ec_curves[i].oid);
|
||||
}
|
||||
break;
|
||||
_sc_card_add_rsa_alg(card, 3072, flags_rsa, 0);
|
||||
/* fallthrough */
|
||||
case SC_CARD_TYPE_OPENPGP_GNUK:
|
||||
_sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
|
||||
/* Gnuk supports NIST, SECG and Curve25519 since version 1.2 */
|
||||
for (i=0; ec_curves_gnuk[i].oid.value[0] >= 0; i++)
|
||||
for (i=0; priv->ec_curves[i].oid.value[0] >= 0; i++)
|
||||
{
|
||||
_sc_card_add_ec_alg(card, ec_curves_gnuk[i].size,
|
||||
flags_ecc, ext_flags, &ec_curves_gnuk[i].oid);
|
||||
_sc_card_add_ec_alg(card, priv->ec_curves[i].size,
|
||||
flags_ecc, ext_flags, &priv->ec_curves[i].oid);
|
||||
}
|
||||
break;
|
||||
case SC_CARD_TYPE_OPENPGP_V2:
|
||||
|
@ -565,21 +569,27 @@ pgp_parse_hist_bytes(sc_card_t *card, u8 *ctlv, size_t ctlv_len)
|
|||
* Internal: parse an algorithm attributes DO
|
||||
**/
|
||||
static int
|
||||
pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_t *key_info)
|
||||
pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob,
|
||||
sc_cardctl_openpgp_keygen_info_t *key_info)
|
||||
{
|
||||
struct pgp_priv_data *priv = DRVDATA(card);
|
||||
struct sc_object_id oid;
|
||||
unsigned int j, r;
|
||||
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
|
||||
if (blob == NULL || blob->data == NULL || blob->len == 0 ||
|
||||
blob->id < 0x00c1 || blob->id > 0x00c3 || key_info == NULL)
|
||||
return SC_ERROR_INCORRECT_PARAMETERS;
|
||||
blob->id < 0x00c1 || blob->id > 0x00c3 || key_info == NULL) {
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
||||
}
|
||||
|
||||
key_info->key_id = blob->id - 0x00c0; /* attribute algorithm blobs are C1 - C3 */
|
||||
|
||||
switch (blob->data[0]) {
|
||||
case SC_OPENPGP_KEYALGO_RSA:
|
||||
if (blob->len < 5)
|
||||
return SC_ERROR_INCORRECT_PARAMETERS;
|
||||
if (blob->len < 5) {
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
||||
}
|
||||
|
||||
key_info->algorithm = SC_OPENPGP_KEYALGO_RSA;
|
||||
key_info->u.rsa.modulus_len = bebytes2ushort(blob->data + 1);
|
||||
|
@ -591,8 +601,9 @@ pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_
|
|||
break;
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
|
||||
/* SC_OPENPGP_KEYALGO_ECDH || SC_OPENPGP_KEYALGO_ECDSA */
|
||||
/* SC_OPENPGP_KEYALGO_ECDH || SC_OPENPGP_KEYALGO_ECDSA || SC_OPENPGP_KEYALGO_EDDSA */
|
||||
key_info->algorithm = blob->data[0];
|
||||
|
||||
/* last byte is only set if pubkey import is supported, empty otherwise*/
|
||||
|
@ -618,20 +629,25 @@ pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_
|
|||
return r;
|
||||
}
|
||||
/* compare with list of supported ec_curves */
|
||||
for (j=0; ec_curves[j].oid.value[0] >= 0; j++){
|
||||
if (sc_compare_oid(&ec_curves[j].oid, &oid)){
|
||||
key_info->u.ec.oid = ec_curves[j].oid;
|
||||
key_info->u.ec.key_length = ec_curves[j].size;
|
||||
for (j = 0; priv->ec_curves[j].oid.value[0] >= 0; j++) {
|
||||
if (sc_compare_oid(&priv->ec_curves[j].oid, &oid)) {
|
||||
sc_log(card->ctx, "Matched EC oid %s (%d)",
|
||||
sc_dump_oid(&oid), j);
|
||||
key_info->u.ec.oid = priv->ec_curves[j].oid;
|
||||
key_info->u.ec.key_length = priv->ec_curves[j].size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We did not match the OID */
|
||||
if (priv->ec_curves[j].oid.value[0] < 0) {
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_NOT_IMPLEMENTED;
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
return SC_SUCCESS;
|
||||
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
@ -647,6 +663,8 @@ pgp_get_card_features(sc_card_t *card)
|
|||
size_t i;
|
||||
pgp_blob_t *blob, *blob6e, *blob73;
|
||||
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
|
||||
/* parse card capabilities from historical bytes in ATR */
|
||||
if (hist_bytes_len > 0) {
|
||||
/* category indicator 0x00, 0x10 or 0x80 => compact TLV (ISO) */
|
||||
|
@ -776,24 +794,46 @@ pgp_get_card_features(sc_card_t *card)
|
|||
for (i = 0x00c1; i <= 0x00c3; i++) {
|
||||
sc_cardctl_openpgp_keygen_info_t key_info;
|
||||
|
||||
sc_log(card->ctx, "Parsing algorithm attribues DO %zX" , i);
|
||||
|
||||
/* OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */
|
||||
if ((pgp_get_blob(card, blob73, i, &blob) >= 0) &&
|
||||
(pgp_parse_algo_attr_blob(blob, &key_info) >= 0)) {
|
||||
(pgp_parse_algo_attr_blob(card, blob, &key_info) >= 0)) {
|
||||
unsigned long flags = 0, ext_flags = 0;
|
||||
|
||||
/* RSA [RFC 4880] */
|
||||
if (key_info.algorithm == SC_OPENPGP_KEYALGO_RSA){
|
||||
switch (key_info.algorithm) {
|
||||
case SC_OPENPGP_KEYALGO_RSA:
|
||||
/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 /
|
||||
* v3.x section 7.2.11 & 7.2.12 */
|
||||
unsigned long flags = SC_ALGORITHM_RSA_PAD_PKCS1 |
|
||||
SC_ALGORITHM_RSA_HASH_NONE |
|
||||
SC_ALGORITHM_ONBOARD_KEY_GEN; /* key gen on card */
|
||||
_sc_card_add_rsa_alg(card, key_info.u.rsa.modulus_len, flags, 0);
|
||||
}
|
||||
/* v3.0+: ECC [RFC 4880 & 6637] */
|
||||
else if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| key_info.algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
|
||||
flags = SC_ALGORITHM_RSA_PAD_PKCS1 |
|
||||
SC_ALGORITHM_RSA_HASH_NONE |
|
||||
SC_ALGORITHM_ONBOARD_KEY_GEN; /* key gen on card */
|
||||
|
||||
unsigned long flags, ext_flags;
|
||||
_sc_card_add_rsa_alg(card, key_info.u.rsa.modulus_len, flags, 0);
|
||||
sc_log(card->ctx, "DO %zX: Added RSA algorithm, mod_len = %"
|
||||
SC_FORMAT_LEN_SIZE_T"u",
|
||||
i, key_info.u.rsa.modulus_len);
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
/* The montgomery curve (curve25519) needs to go through
|
||||
* different paths, otherwise we handle it as a normal EC key */
|
||||
if (sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) {
|
||||
/* CKM_XEDDSA supports both Sign and Derive, but
|
||||
* OpenPGP card supports only derivation using these
|
||||
* keys as far as I know */
|
||||
_sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length,
|
||||
SC_ALGORITHM_ECDH_CDH_RAW, 0, &key_info.u.ec.oid);
|
||||
|
||||
sc_log(card->ctx, "DO %zX: Added XEDDSA algorithm (%d), mod_len = %d" ,
|
||||
i, key_info.algorithm, key_info.u.ec.key_length);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
/* v3.0+: ECC [RFC 4880 & 6637] */
|
||||
/* EdDSA from draft-ietf-openpgp-rfc4880bis-08 */
|
||||
flags = 0, ext_flags = 0;
|
||||
|
||||
if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDH)
|
||||
flags = SC_ALGORITHM_ECDH_CDH_RAW;
|
||||
|
@ -804,7 +844,21 @@ pgp_get_card_features(sc_card_t *card)
|
|||
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE;
|
||||
|
||||
_sc_card_add_ec_alg(card, key_info.u.ec.key_length, flags, ext_flags,
|
||||
&key_info.u.ec.oid);
|
||||
&key_info.u.ec.oid);
|
||||
sc_log(card->ctx, "DO %zX: Added EC algorithm (%d), mod_len = %d" ,
|
||||
i, key_info.algorithm, key_info.u.ec.key_length);
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
_sc_card_add_eddsa_alg(card, key_info.u.ec.key_length,
|
||||
SC_ALGORITHM_EDDSA_RAW, 0, &key_info.u.ec.oid);
|
||||
|
||||
sc_log(card->ctx, "DO %zX: Added EDDSA algorithm (%d), mod_len = %d" ,
|
||||
i, key_info.algorithm, key_info.u.ec.key_length);
|
||||
break;
|
||||
default:
|
||||
sc_log(card->ctx, "DO %zX: Unknown algorithm ID (%d)" ,
|
||||
i, key_info.algorithm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1551,10 +1605,6 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
|||
else if ((r = pgp_get_blob(card, blob, 0x0086, &pubkey_blob)) >= 0
|
||||
&& (r = pgp_read_blob(card, pubkey_blob)) >= 0) {
|
||||
|
||||
p15pubkey.algorithm = SC_ALGORITHM_EC;
|
||||
p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
|
||||
p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len;
|
||||
|
||||
switch(tag & 0xFFFE) {
|
||||
case DO_SIGN: aa_tag = 0x00C1; break;
|
||||
case DO_ENCR: aa_tag = 0x00C2; break;
|
||||
|
@ -1567,31 +1617,74 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
|||
if (aa_tag && ((r = pgp_get_blob(card, priv->mf, 0x006e, &blob6e)) >= 0) &&
|
||||
((r = pgp_get_blob(card, blob6e, 0x0073, &blob73)) >= 0) &&
|
||||
((r = pgp_get_blob(card, blob73, aa_tag, &aa_blob)) >= 0) &&
|
||||
((r = pgp_parse_algo_attr_blob(aa_blob, &key_info)) >= 0)) {
|
||||
((r = pgp_parse_algo_attr_blob(card, aa_blob, &key_info)) >= 0)) {
|
||||
switch (key_info.algorithm) {
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
/* In EDDSA key case we do not have to care about OIDs
|
||||
* as we support only one for now */
|
||||
p15pubkey.algorithm = SC_ALGORITHM_EDDSA;
|
||||
p15pubkey.u.eddsa.pubkey.value = pubkey_blob->data;
|
||||
p15pubkey.u.eddsa.pubkey.len = pubkey_blob->len;
|
||||
/* PKCS#11 3.0: 2.3.5 Edwards EC public keys only support the use
|
||||
* of the curveName selection to specify a curve name as defined
|
||||
* in [RFC 8032] */
|
||||
|
||||
if ((r = sc_encode_oid(card->ctx, &key_info.u.ec.oid,
|
||||
&p15pubkey.u.ec.params.der.value,
|
||||
&p15pubkey.u.ec.params.der.len)) == 0) {
|
||||
p15pubkey.u.ec.params.type = 1;
|
||||
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len);
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
/* This yields either EC(DSA) key or EC_MONTGOMERY (curve25519) key */
|
||||
if (sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) {
|
||||
p15pubkey.algorithm = SC_ALGORITHM_XEDDSA;
|
||||
p15pubkey.u.eddsa.pubkey.value = pubkey_blob->data;
|
||||
p15pubkey.u.eddsa.pubkey.len = pubkey_blob->len;
|
||||
/* PKCS#11 3.0 2.3.7 Montgomery EC public keys only support
|
||||
* the use of the curveName selection to specify a curve
|
||||
* name as defined in [RFC7748] */
|
||||
/* XXX only curve25519 supported now. Theoretically could be
|
||||
* also curve448 or OIDs */
|
||||
|
||||
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
if ((r = sc_encode_oid(card->ctx, &key_info.u.ec.oid,
|
||||
&p15pubkey.u.ec.params.der.value,
|
||||
&p15pubkey.u.ec.params.der.len)) == 0) {
|
||||
p15pubkey.algorithm = SC_ALGORITHM_EC;
|
||||
p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
|
||||
p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len;
|
||||
p15pubkey.u.ec.params.type = 1;
|
||||
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len);
|
||||
} else {
|
||||
sc_log(card->ctx, "Unable to encode EC curve OID from algorithm info");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sc_log(card->ctx, "Unknown algorithm ID received (%d)", key_info.algorithm);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
sc_log(card->ctx, "Unable to find Algorithm Attribute for EC curve OID");
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
LOG_TEST_RET(card->ctx, r, "error getting elements");
|
||||
}
|
||||
|
||||
/* clean up anything we may have set in p15pubkey that can not be freed */
|
||||
if (p15pubkey.algorithm == SC_ALGORITHM_RSA) {
|
||||
if (p15pubkey.algorithm == SC_ALGORITHM_RSA) {
|
||||
p15pubkey.u.rsa.modulus.data = NULL;
|
||||
p15pubkey.u.rsa.modulus.len = 0;
|
||||
p15pubkey.u.rsa.exponent.data = NULL;
|
||||
p15pubkey.u.rsa.exponent.len = 0;
|
||||
} else
|
||||
if (p15pubkey.algorithm == SC_ALGORITHM_EC) {
|
||||
} else if (p15pubkey.algorithm == SC_ALGORITHM_EC) {
|
||||
p15pubkey.u.ec.ecpointQ.value = NULL;
|
||||
p15pubkey.u.ec.ecpointQ.len = 0;
|
||||
/* p15pubkey.u.ec.params.der and named_curve will be freed by sc_pkcs15_erase_pubkey */
|
||||
} else if (p15pubkey.algorithm == SC_ALGORITHM_EDDSA
|
||||
|| p15pubkey.algorithm == SC_ALGORITHM_XEDDSA) {
|
||||
p15pubkey.u.eddsa.pubkey.value = NULL;
|
||||
p15pubkey.u.eddsa.pubkey.len = 0;
|
||||
}
|
||||
sc_pkcs15_erase_pubkey(&p15pubkey);
|
||||
|
||||
|
@ -1843,7 +1936,7 @@ pgp_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left)
|
|||
|
||||
/* In general, the PIN Reference is extracted from the key-id,
|
||||
* for example, CHV0 -> Ref=0, CHV1 -> Ref=1.
|
||||
* However, in the case of OpenGPG, the PIN Ref to compose APDU
|
||||
* However, in the case of OpenPGP, the PIN Ref to compose APDU
|
||||
* must be 81, 82, 83.
|
||||
* So, if we receive Ref=1, Ref=2, we must convert to 81, 82...
|
||||
* In OpenPGP v1, the PINs are named CHV1, CHV2, CHV3.
|
||||
|
@ -1964,6 +2057,7 @@ int pgp_logout(struct sc_card *card)
|
|||
|
||||
/**
|
||||
* ABI: ISO 7816-8 SET SECURITY ENVIRONMENT.
|
||||
* This is optional in the OpenPGP Card 3.4 specs
|
||||
*/
|
||||
static int
|
||||
pgp_set_security_env(sc_card_t *card,
|
||||
|
@ -1973,9 +2067,11 @@ pgp_set_security_env(sc_card_t *card,
|
|||
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
|
||||
/* The SC_SEC_ENV_ALG_PRESENT is set always so let it pass for GNUK */
|
||||
if ((env->flags & SC_SEC_ENV_ALG_PRESENT)
|
||||
&& (env->algorithm != SC_ALGORITHM_RSA)
|
||||
&& (priv->bcd_version < OPENPGP_CARD_3_0))
|
||||
&& (priv->bcd_version < OPENPGP_CARD_3_0)
|
||||
&& (card->type != SC_CARD_TYPE_OPENPGP_GNUK))
|
||||
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
|
||||
"only RSA algorithm supported");
|
||||
|
||||
|
@ -2006,6 +2102,9 @@ pgp_set_security_env(sc_card_t *card,
|
|||
"requested usage");
|
||||
}
|
||||
break;
|
||||
case SC_SEC_OPERATION_DERIVE:
|
||||
sc_log(card->ctx, "Operation: Derive: No particular action needed");
|
||||
break;
|
||||
default:
|
||||
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
|
||||
"invalid operation");
|
||||
|
@ -2093,6 +2192,9 @@ pgp_compute_signature(sc_card_t *card, const u8 *data,
|
|||
break;
|
||||
case 0x01:
|
||||
default:
|
||||
/* From PKCS #11 point of view, we should be able to use
|
||||
* curve25519 to do digital signature, but it is not how it
|
||||
* is used in OpenPGP so we will not allow it here */
|
||||
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
|
||||
"invalid key reference");
|
||||
}
|
||||
|
@ -2129,21 +2231,86 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
|
|||
sc_security_env_t *env = &priv->sec_env;
|
||||
sc_apdu_t apdu;
|
||||
u8 apdu_case = SC_APDU_CASE_4;
|
||||
u8 *temp = NULL;
|
||||
u8 *temp = NULL, *p = NULL;
|
||||
size_t templen, pklen, dolen;
|
||||
int r;
|
||||
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
|
||||
/* padding according to OpenPGP card spec 1.1 & 2.x section 7.2.9 / 3.x section 7.2.11 */
|
||||
if (!(temp = malloc(inlen + 1)))
|
||||
/* padding according to OpenPGP card spec 1.1 & 2.x section 7.2.9 / 3.x section 7.2.11
|
||||
* The longest possible prefix is 10 bytes for ECDH */
|
||||
templen = inlen + 10;
|
||||
if (!(temp = malloc(templen)))
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
||||
/* padding byte: 0xa6 = ECC; 0x00 = RSA; 0x02 = AES */
|
||||
(env->algorithm == SC_ALGORITHM_EC) ? (temp[0] = 0xa6) : (temp[0] = 0x00);
|
||||
memcpy(temp + 1, in, inlen);
|
||||
in = temp;
|
||||
inlen += 1;
|
||||
|
||||
if (env->operation != SC_SEC_OPERATION_DECIPHER) {
|
||||
/* padding byte: 0xa6 = ECC; 0x00 = RSA; 0x02 = AES */
|
||||
switch (env->algorithm) {
|
||||
case SC_ALGORITHM_RSA:
|
||||
/* This is just PKCS#1.5 start byte and it should be already
|
||||
* provided by the padding routines. But it lets put it here
|
||||
* to make sure it does not conflict with following indicators */
|
||||
temp[0] = 0x00;
|
||||
memcpy(temp + 1, in, inlen);
|
||||
inlen += 1;
|
||||
break;
|
||||
|
||||
case SC_ALGORITHM_EC:
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
/* Calculate length of External Public Key (0x86) */
|
||||
r = sc_asn1_put_tag(0x86, NULL, inlen, NULL, 0, NULL);
|
||||
if (r <= 0) {
|
||||
free(temp);
|
||||
LOG_FUNC_RETURN(card->ctx, r);
|
||||
}
|
||||
pklen = r;
|
||||
|
||||
/* Calculate lenght of Public Key DO (0x7F49) */
|
||||
r = sc_asn1_put_tag(0x7f49, NULL, pklen, NULL, 0, NULL);
|
||||
if (r <= 0) {
|
||||
free(temp);
|
||||
LOG_FUNC_RETURN(card->ctx, r);
|
||||
}
|
||||
dolen = r;
|
||||
|
||||
p = temp;
|
||||
/* This is 0xA6 Cipher DO with associated length field */
|
||||
r = sc_asn1_put_tag(0xA6, NULL, dolen, p, templen - (p - temp), &p);
|
||||
if (r != SC_SUCCESS) {
|
||||
free(temp);
|
||||
LOG_FUNC_RETURN(card->ctx, r);
|
||||
}
|
||||
|
||||
/* Public Key DO (0x7F49) with associated length field */
|
||||
r = sc_asn1_put_tag(0x7F49, NULL, pklen, p, templen - (p - temp), &p);
|
||||
if (r != SC_SUCCESS) {
|
||||
free(temp);
|
||||
LOG_FUNC_RETURN(card->ctx, r);
|
||||
}
|
||||
|
||||
/* External Public Key (0x86) with associated length */
|
||||
r = sc_asn1_put_tag(0x86, in, inlen, p, templen - (p - temp), &p);
|
||||
if (r != SC_SUCCESS) {
|
||||
free(temp);
|
||||
LOG_FUNC_RETURN(card->ctx, r);
|
||||
}
|
||||
inlen = (p - temp);
|
||||
break;
|
||||
case SC_ALGORITHM_AES:
|
||||
/* not supported yet */
|
||||
/*
|
||||
temp[0] = 0x02;
|
||||
memcpy(temp + 1, in, inlen);
|
||||
inlen += 1;
|
||||
*/
|
||||
/* fall through */
|
||||
default:
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
}
|
||||
|
||||
in = temp;
|
||||
|
||||
if (env->operation != SC_SEC_OPERATION_DECIPHER &&
|
||||
env->operation != SC_SEC_OPERATION_DERIVE) {
|
||||
free(temp);
|
||||
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
|
||||
"invalid operation");
|
||||
|
@ -2223,7 +2390,8 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_
|
|||
if (priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) {
|
||||
/* ECDSA and ECDH */
|
||||
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
|
||||
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA
|
||||
|| key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA){
|
||||
data_len = key_info->u.ec.oid_len+1;
|
||||
data = malloc(data_len);
|
||||
if (!data)
|
||||
|
@ -2270,7 +2438,7 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_
|
|||
} else {
|
||||
sc_cardctl_openpgp_keygen_info_t old_key_info;
|
||||
|
||||
if (pgp_parse_algo_attr_blob(algo_blob, &old_key_info) != SC_SUCCESS
|
||||
if (pgp_parse_algo_attr_blob(card, algo_blob, &old_key_info) != SC_SUCCESS
|
||||
|| old_key_info.algorithm != key_info->algorithm)
|
||||
LOG_TEST_RET(card->ctx, SC_ERROR_NO_CARD_SUPPORT,
|
||||
"Requested algorithm not supported");
|
||||
|
@ -2427,7 +2595,8 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
|
|||
}
|
||||
/* ECC */
|
||||
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
|
||||
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA
|
||||
|| key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
|
||||
/* Algorithm ID, see https://tools.ietf.org/html/rfc6637#section-5 */
|
||||
*p = key_info->algorithm + 6;
|
||||
p += 1;
|
||||
|
@ -2721,6 +2890,9 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
|
|||
&& card->type < SC_CARD_TYPE_OPENPGP_V3
|
||||
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
if (key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA
|
||||
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
|
||||
/* set Control Reference Template for key */
|
||||
if (key_info->key_id == SC_OPENPGP_KEY_SIGN)
|
||||
|
|
|
@ -184,6 +184,8 @@ struct pgp_priv_data {
|
|||
size_t max_cert_size;
|
||||
size_t max_specialDO_size;
|
||||
|
||||
pgp_ec_curves_t *ec_curves;
|
||||
|
||||
sc_security_env_t sec_env;
|
||||
};
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ static void sc_card_free(sc_card_t *card)
|
|||
int i;
|
||||
for (i=0; i<card->algorithm_count; i++) {
|
||||
struct sc_algorithm_info *info = (card->algorithms + i);
|
||||
if (info->algorithm == SC_ALGORITHM_EC) {
|
||||
if (info->algorithm == SC_ALGORITHM_EC) {
|
||||
struct sc_ec_parameters ep = info->u._ec.params;
|
||||
|
||||
free(ep.named_curve);
|
||||
|
@ -1096,16 +1096,18 @@ int _sc_card_add_symmetric_alg(sc_card_t *card, unsigned int algorithm,
|
|||
return _sc_card_add_algorithm(card, &info);
|
||||
}
|
||||
|
||||
int _sc_card_add_ec_alg(sc_card_t *card, unsigned int key_length,
|
||||
static int
|
||||
_sc_card_add_ec_alg_int(sc_card_t *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid)
|
||||
struct sc_object_id *curve_oid,
|
||||
int algorithm)
|
||||
{
|
||||
sc_algorithm_info_t info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
sc_init_oid(&info.u._ec.params.id);
|
||||
|
||||
info.algorithm = SC_ALGORITHM_EC;
|
||||
info.algorithm = algorithm;
|
||||
info.key_length = key_length;
|
||||
info.flags = flags;
|
||||
|
||||
|
@ -1116,6 +1118,32 @@ int _sc_card_add_ec_alg(sc_card_t *card, unsigned int key_length,
|
|||
return _sc_card_add_algorithm(card, &info);
|
||||
}
|
||||
|
||||
int _sc_card_add_ec_alg(sc_card_t *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid)
|
||||
{
|
||||
return _sc_card_add_ec_alg_int(card, key_length, flags, ext_flags,
|
||||
curve_oid, SC_ALGORITHM_EC);
|
||||
}
|
||||
|
||||
int _sc_card_add_eddsa_alg(sc_card_t *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid)
|
||||
{
|
||||
/* For simplicity, share the ec union with the curve information */
|
||||
return _sc_card_add_ec_alg_int(card, key_length, flags, ext_flags,
|
||||
curve_oid, SC_ALGORITHM_EDDSA);
|
||||
}
|
||||
|
||||
int _sc_card_add_xeddsa_alg(sc_card_t *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid)
|
||||
{
|
||||
/* For simplicity, share the ec union with the curve information */
|
||||
return _sc_card_add_ec_alg_int(card, key_length, flags, ext_flags,
|
||||
curve_oid, SC_ALGORITHM_XEDDSA);
|
||||
}
|
||||
|
||||
sc_algorithm_info_t * sc_card_find_alg(sc_card_t *card,
|
||||
unsigned int algorithm, unsigned int key_length, void *param)
|
||||
{
|
||||
|
@ -1126,13 +1154,15 @@ sc_algorithm_info_t * sc_card_find_alg(sc_card_t *card,
|
|||
|
||||
if (info->algorithm != algorithm)
|
||||
continue;
|
||||
if (param) {
|
||||
if (info->algorithm == SC_ALGORITHM_EC ||
|
||||
info->algorithm == SC_ALGORITHM_EDDSA ||
|
||||
info->algorithm == SC_ALGORITHM_XEDDSA)
|
||||
if (sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id))
|
||||
return info;
|
||||
}
|
||||
if (info->key_length != key_length)
|
||||
continue;
|
||||
if (param) {
|
||||
if (info->algorithm == SC_ALGORITHM_EC)
|
||||
if(!sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id))
|
||||
continue;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -1144,6 +1174,18 @@ sc_algorithm_info_t * sc_card_find_ec_alg(sc_card_t *card,
|
|||
return sc_card_find_alg(card, SC_ALGORITHM_EC, key_length, curve_name);
|
||||
}
|
||||
|
||||
sc_algorithm_info_t * sc_card_find_eddsa_alg(sc_card_t *card,
|
||||
unsigned int key_length, struct sc_object_id *curve_name)
|
||||
{
|
||||
return sc_card_find_alg(card, SC_ALGORITHM_EDDSA, key_length, curve_name);
|
||||
}
|
||||
|
||||
sc_algorithm_info_t * sc_card_find_xeddsa_alg(sc_card_t *card,
|
||||
unsigned int key_length, struct sc_object_id *curve_name)
|
||||
{
|
||||
return sc_card_find_alg(card, SC_ALGORITHM_XEDDSA, key_length, curve_name);
|
||||
}
|
||||
|
||||
int _sc_card_add_rsa_alg(sc_card_t *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long exponent)
|
||||
{
|
||||
|
|
|
@ -974,6 +974,7 @@ typedef struct sc_cardctl_piv_genkey_info_st {
|
|||
#define SC_OPENPGP_KEYALGO_RSA 0x01
|
||||
#define SC_OPENPGP_KEYALGO_ECDH 0x12
|
||||
#define SC_OPENPGP_KEYALGO_ECDSA 0x13
|
||||
#define SC_OPENPGP_KEYALGO_EDDSA 0x16
|
||||
|
||||
#define SC_OPENPGP_KEYFORMAT_RSA_STD 0 /* See 4.3.3.6 Algorithm Attributes */
|
||||
#define SC_OPENPGP_KEYFORMAT_RSA_STDN 1 /* OpenPGP card spec v2 */
|
||||
|
|
|
@ -93,6 +93,7 @@ typedef unsigned __int8 uint8_t;
|
|||
#define SCARD_S_SUCCESS 0x00000000 /**< No error was encountered. */
|
||||
#define SCARD_E_CANCELLED 0x80100002 /**< The action was cancelled by an SCardCancel request. */
|
||||
#define SCARD_E_INVALID_HANDLE 0x80100003 /**< The supplied handle was invalid. */
|
||||
#define SCARD_E_UNKNOWN_READER 0x80100009 /**< The specified reader name is not recognized. */
|
||||
#define SCARD_E_TIMEOUT 0x8010000A /**< The user-specified timeout value has expired. */
|
||||
#define SCARD_E_SHARING_VIOLATION 0x8010000B /**< The smart card cannot be accessed because of other connections outstanding. */
|
||||
#define SCARD_E_NO_SMARTCARD 0x8010000C /**< The operation requires a smart card, but no smart card is currently in the device. */
|
||||
|
|
|
@ -153,6 +153,12 @@ int _sc_card_add_rsa_alg(struct sc_card *card, unsigned int key_length,
|
|||
int _sc_card_add_ec_alg(struct sc_card *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid);
|
||||
int _sc_card_add_eddsa_alg(struct sc_card *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid);
|
||||
int _sc_card_add_xeddsa_alg(struct sc_card *card, unsigned int key_length,
|
||||
unsigned long flags, unsigned long ext_flags,
|
||||
struct sc_object_id *curve_oid);
|
||||
|
||||
/********************************************************************/
|
||||
/* pkcs1 padding/encoding functions */
|
||||
|
|
|
@ -175,6 +175,7 @@ sc_pkcs15_encode_pubkey
|
|||
sc_pkcs15_encode_pubkey_dsa
|
||||
sc_pkcs15_encode_pubkey_rsa
|
||||
sc_pkcs15_encode_pubkey_ec
|
||||
sc_pkcs15_encode_pubkey_eddsa
|
||||
sc_pkcs15_encode_pubkey_gostr3410
|
||||
sc_pkcs15_encode_pubkey_as_spki
|
||||
sc_pkcs15_encode_pukdf_entry
|
||||
|
|
|
@ -78,6 +78,8 @@ extern "C" {
|
|||
#define SC_ALGORITHM_DSA 1
|
||||
#define SC_ALGORITHM_EC 2
|
||||
#define SC_ALGORITHM_GOSTR3410 3
|
||||
#define SC_ALGORITHM_EDDSA 4
|
||||
#define SC_ALGORITHM_XEDDSA 5
|
||||
|
||||
/* Symmetric algorithms */
|
||||
#define SC_ALGORITHM_DES 64
|
||||
|
@ -189,6 +191,10 @@ extern "C" {
|
|||
SC_ALGORITHM_ECDSA_HASH_SHA384 | \
|
||||
SC_ALGORITHM_ECDSA_HASH_SHA512)
|
||||
|
||||
/* EdDSA algorithms */
|
||||
#define SC_ALGORITHM_EDDSA_RAW 0x00400000
|
||||
#define SC_ALGORITHM_XEDDSA_RAW 0x00800000
|
||||
|
||||
/* define mask of all algorithms that can do raw */
|
||||
#define SC_ALGORITHM_RAW_MASK (SC_ALGORITHM_RSA_RAW | \
|
||||
SC_ALGORITHM_GOSTR3410_RAW | \
|
||||
|
@ -1555,6 +1561,10 @@ struct sc_algorithm_info * sc_card_find_rsa_alg(struct sc_card *card,
|
|||
unsigned int key_length);
|
||||
struct sc_algorithm_info * sc_card_find_ec_alg(struct sc_card *card,
|
||||
unsigned int field_length, struct sc_object_id *curve_oid);
|
||||
struct sc_algorithm_info * sc_card_find_eddsa_alg(struct sc_card *card,
|
||||
unsigned int field_length, struct sc_object_id *curve_oid);
|
||||
struct sc_algorithm_info * sc_card_find_xeddsa_alg(struct sc_card *card,
|
||||
unsigned int field_length, struct sc_object_id *curve_oid);
|
||||
struct sc_algorithm_info * sc_card_find_gostr3410_alg(struct sc_card *card,
|
||||
unsigned int key_length);
|
||||
struct sc_algorithm_info * sc_card_find_alg(sc_card_t *card,
|
||||
|
|
|
@ -412,7 +412,6 @@ static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = {
|
|||
asn1_encode_pbes2_params,
|
||||
asn1_free_pbes2_params },
|
||||
#endif
|
||||
|
||||
#ifdef SC_ALGORITHM_EC
|
||||
{ SC_ALGORITHM_EC, {{ 1, 2, 840, 10045, 2, 1, -1}},
|
||||
asn1_decode_ec_params,
|
||||
|
@ -448,6 +447,14 @@ static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = {
|
|||
asn1_decode_ec_params,
|
||||
asn1_encode_ec_params,
|
||||
asn1_free_ec_params },
|
||||
#endif
|
||||
#ifdef SC_ALGORITHM_EDDSA
|
||||
/* aka Ed25519 */
|
||||
{ SC_ALGORITHM_EDDSA, {{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef SC_ALGORITHM_XEDDSA
|
||||
/* aka curve25519 */
|
||||
{ SC_ALGORITHM_XEDDSA, {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, NULL, NULL, NULL },
|
||||
#endif
|
||||
{ -1, {{ -1 }}, NULL, NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -70,6 +70,7 @@ static const pgp_pin_cfg_t pin_cfg_v2[3] = {
|
|||
{ "Admin PIN", 0x03, PGP_ADMIN_PIN_FLAGS, 8, 2 }
|
||||
};
|
||||
|
||||
static struct sc_object_id curve25519_oid = {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}};
|
||||
|
||||
#define PGP_SIG_PRKEY_USAGE (SC_PKCS15_PRKEY_USAGE_SIGN \
|
||||
| SC_PKCS15_PRKEY_USAGE_SIGNRECOVER \
|
||||
|
@ -169,6 +170,8 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
sc_path_t path;
|
||||
sc_file_t *file = NULL;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
|
||||
set_string(&p15card->tokeninfo->label, "OpenPGP card");
|
||||
set_string(&p15card->tokeninfo->manufacturer_id, "OpenPGP project");
|
||||
|
||||
|
@ -203,6 +206,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
* 01-03: max length of pins 1-3
|
||||
* 04-07: tries left for pins 1-3
|
||||
*/
|
||||
sc_log(ctx, "Reading PW status bytes");
|
||||
if ((r = read_file(card, "006E:0073:00C4", c4data, sizeof(c4data))) < 0)
|
||||
goto failed;
|
||||
if (r != 7) {
|
||||
|
@ -251,19 +255,22 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
* 20-39: finger print for ENC key
|
||||
* 40-59: finger print for AUT key
|
||||
*/
|
||||
sc_log(ctx, "Reading Fingerprints");
|
||||
if ((r = read_file(card, "006E:0073:00C5", c5data, sizeof(c5data))) < 0)
|
||||
goto failed;
|
||||
if (r < 60) {
|
||||
sc_log(ctx,
|
||||
sc_log(ctx,
|
||||
"finger print bytes have unexpected length (expected 60, got %d)\n", r);
|
||||
return SC_ERROR_OBJECT_NOT_VALID;
|
||||
}
|
||||
|
||||
sc_log(ctx, "Adding private keys");
|
||||
/* XXX: check if "halfkeys" can be stored with gpg2. If not, add key pairs in one loop */
|
||||
for (i = 0; i < 3; i++) {
|
||||
sc_pkcs15_prkey_info_t prkey_info;
|
||||
sc_pkcs15_object_t prkey_obj;
|
||||
u8 cxdata[12];
|
||||
int cxdata_len = sizeof(cxdata);
|
||||
char path_template[] = "006E:0073:00Cx";
|
||||
int j;
|
||||
|
||||
|
@ -272,7 +279,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
memset(&cxdata, 0, sizeof(cxdata));
|
||||
|
||||
path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */
|
||||
if ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
|
||||
if ((cxdata_len = read_file(card, path_template, cxdata, sizeof(cxdata))) < 1)
|
||||
goto failed;
|
||||
|
||||
/* check validity using finger prints */
|
||||
|
@ -283,6 +290,10 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
|
||||
/* only add valid keys, i.e. those with a legal algorithm identifier & finger print */
|
||||
if (j >= 0 && cxdata[0] != 0) {
|
||||
struct sc_object_id oid;
|
||||
struct sc_algorithm_info * algorithm_info; /* no need to free */
|
||||
|
||||
algorithm_info = NULL;
|
||||
prkey_info.id.len = 1;
|
||||
prkey_info.id.value[0] = i + 1;
|
||||
prkey_info.usage = key_cfg[i].prkey_usage;
|
||||
|
@ -294,24 +305,96 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
prkey_obj.auth_id.len = 1;
|
||||
prkey_obj.auth_id.value[0] = key_cfg[i].prkey_pin;
|
||||
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_RSA && r >= 3) {
|
||||
prkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
/* need to get size from algorithms using oid */
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH ||
|
||||
cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA ||
|
||||
cxdata[0] == SC_OPENPGP_KEYALGO_EDDSA) {
|
||||
r = sc_asn1_decode_object_id(&cxdata[1], cxdata_len-1, &oid);
|
||||
if (r != SC_SUCCESS) {
|
||||
sc_log(ctx, "Failed to parse OID for elliptic curve algorithm");
|
||||
}
|
||||
}
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) {
|
||||
|
||||
switch (cxdata[0]) {
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
if (sc_compare_oid(&oid, &curve25519_oid)) {
|
||||
if ((algorithm_info = sc_card_find_xeddsa_alg(card, 0, &oid)))
|
||||
prkey_info.field_length = algorithm_info->key_length;
|
||||
else {
|
||||
sc_log(ctx, "algorithm not found");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
if((algorithm_info = sc_card_find_ec_alg(card, 0, &oid)))
|
||||
prkey_info.field_length = algorithm_info->key_length;
|
||||
else {
|
||||
sc_log(ctx, "algorithm not found");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
if ((algorithm_info = sc_card_find_eddsa_alg(card, 0, &oid)))
|
||||
prkey_info.field_length = algorithm_info->key_length;
|
||||
else {
|
||||
sc_log(ctx, "algorithm not found");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cxdata[0]) {
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
/* Filter out invalid usage: EdDSA does not support anything but sign */
|
||||
prkey_info.usage &= PGP_SIG_PRKEY_USAGE;
|
||||
r = sc_pkcs15emu_add_eddsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
break;
|
||||
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
/* This can result in either ECDSA key or EC_MONTGOMERY
|
||||
* so we need to check OID */
|
||||
if (sc_compare_oid(&oid, &curve25519_oid)) {
|
||||
/* This can do only DERIVE */
|
||||
prkey_info.usage = SC_PKCS15_PRKEY_USAGE_DERIVE;
|
||||
r = sc_pkcs15emu_add_xeddsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
break;
|
||||
}
|
||||
prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
|
||||
prkey_info.usage &= ~PGP_ENC_PRKEY_USAGE;
|
||||
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
break;
|
||||
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN;
|
||||
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
break;
|
||||
|
||||
case SC_OPENPGP_KEYALGO_RSA:
|
||||
if (cxdata_len >= 3) {
|
||||
prkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
break;
|
||||
}
|
||||
/* Fallthrough */
|
||||
default:
|
||||
sc_log(ctx, "Invalid algorithm identifier %x (length = %d)",
|
||||
cxdata[0], r);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
sc_log(ctx, "Adding public keys");
|
||||
/* Add public keys */
|
||||
for (i = 0; i < 3; i++) {
|
||||
sc_pkcs15_pubkey_info_t pubkey_info;
|
||||
sc_pkcs15_object_t pubkey_obj;
|
||||
u8 cxdata[10];
|
||||
u8 cxdata[12];
|
||||
int cxdata_len = sizeof(cxdata);
|
||||
char path_template[] = "006E:0073:00Cx";
|
||||
int j;
|
||||
|
||||
|
@ -320,7 +403,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
memset(&cxdata, 0, sizeof(cxdata));
|
||||
|
||||
path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */
|
||||
if ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
|
||||
if ((cxdata_len = read_file(card, path_template, cxdata, sizeof(cxdata))) < 1)
|
||||
goto failed;
|
||||
|
||||
/* check validity using finger prints */
|
||||
|
@ -331,6 +414,10 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
|
||||
/* only add valid keys, i.e. those with a legal algorithm identifier & finger print */
|
||||
if (j >= 0 && cxdata[0] != 0) {
|
||||
struct sc_object_id oid;
|
||||
struct sc_algorithm_info * algorithm_info; /* no need to free */
|
||||
|
||||
algorithm_info = NULL;
|
||||
pubkey_info.id.len = 1;
|
||||
pubkey_info.id.value[0] = i + 1;
|
||||
pubkey_info.usage = key_cfg[i].pubkey_usage;
|
||||
|
@ -339,13 +426,78 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label));
|
||||
pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
|
||||
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_RSA && r >= 3) {
|
||||
pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH ||
|
||||
cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA ||
|
||||
cxdata[0] == SC_OPENPGP_KEYALGO_EDDSA) {
|
||||
r = sc_asn1_decode_object_id(&cxdata[1], cxdata_len-1, &oid);
|
||||
if (r != SC_SUCCESS) {
|
||||
sc_log(ctx, "Failed to parse OID for elliptic curve algorithm");
|
||||
}
|
||||
}
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) {
|
||||
|
||||
switch (cxdata[0]) {
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
if (sc_compare_oid(&oid, &curve25519_oid)) {
|
||||
if ((algorithm_info = sc_card_find_xeddsa_alg(card, 0, &oid)))
|
||||
pubkey_info.field_length = algorithm_info->key_length;
|
||||
else {
|
||||
sc_log(ctx, "algorithm not found");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
if((algorithm_info = sc_card_find_ec_alg(card, 0, &oid)))
|
||||
pubkey_info.field_length = algorithm_info->key_length;
|
||||
else {
|
||||
sc_log(ctx, "algorithm not found");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
if ((algorithm_info = sc_card_find_eddsa_alg(card, 0, &oid)))
|
||||
pubkey_info.field_length = algorithm_info->key_length;
|
||||
else {
|
||||
sc_log(ctx, "algorithm not found");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cxdata[0]) {
|
||||
case SC_OPENPGP_KEYALGO_EDDSA:
|
||||
/* assuming Ed25519 as it is the only supported now */
|
||||
/* Filter out invalid usage: ED does not support anything but sign */
|
||||
pubkey_info.usage &= PGP_SIG_PUBKEY_USAGE;
|
||||
r = sc_pkcs15emu_add_eddsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_ECDH:
|
||||
/* This can result in either ECDSA key or EC_MONTGOMERY
|
||||
* so we need to check OID */
|
||||
if (sc_compare_oid(&oid, &curve25519_oid)) {
|
||||
/* XXX What can this key do? */
|
||||
pubkey_info.usage = SC_PKCS15_PRKEY_USAGE_DERIVE;
|
||||
r = sc_pkcs15emu_add_xeddsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
break;
|
||||
}
|
||||
pubkey_info.usage = SC_PKCS15_PRKEY_USAGE_DERIVE;
|
||||
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_ECDSA:
|
||||
pubkey_info.usage = PGP_SIG_PUBKEY_USAGE;
|
||||
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
break;
|
||||
case SC_OPENPGP_KEYALGO_RSA:
|
||||
if (cxdata_len >= 3) {
|
||||
pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
sc_log(ctx, "Invalid algorithm identifier %x (length = %d)",
|
||||
cxdata[0], r);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
|
@ -388,13 +540,13 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
|
||||
failed:
|
||||
if (r < 0) {
|
||||
sc_log(card->ctx,
|
||||
sc_log(card->ctx,
|
||||
"Failed to initialize OpenPGP emulation: %s\n",
|
||||
sc_strerror(r));
|
||||
}
|
||||
sc_file_free(file);
|
||||
|
||||
return r;
|
||||
LOG_FUNC_RETURN(ctx, r);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -617,6 +617,14 @@ sc_pkcs15_free_prkey(struct sc_pkcs15_prkey *key)
|
|||
if (key->u.ec.ecpointQ.value)
|
||||
free(key->u.ec.ecpointQ.value);
|
||||
break;
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
free(key->u.eddsa.pubkey.value);
|
||||
key->u.eddsa.pubkey.value = NULL;
|
||||
key->u.eddsa.pubkey.len = 0;
|
||||
free(key->u.eddsa.value.value);
|
||||
key->u.eddsa.value.value = NULL;
|
||||
key->u.eddsa.value.len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -783,6 +791,13 @@ sc_pkcs15_convert_prkey(struct sc_pkcs15_prkey *pkcs15_key, void *evp_key)
|
|||
break;
|
||||
}
|
||||
#endif /* !defined(OPENSSL_NO_EC) */
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
case EVP_PKEY_ED25519: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
#endif /* EVP_PKEY_ED25519 */
|
||||
|
||||
default:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
|
|
@ -580,6 +580,12 @@ static struct sc_asn1_entry c_asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE] = {
|
|||
{ NULL, 0, 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
#define C_ASN1_EDDSA_PUBKEY_SIZE 2
|
||||
static struct sc_asn1_entry c_asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE] = {
|
||||
{ "pubkey", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL },
|
||||
{ NULL, 0, 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
sc_pkcs15_decode_pubkey_rsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_rsa *key,
|
||||
|
@ -767,6 +773,47 @@ sc_pkcs15_encode_pubkey_ec(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key,
|
|||
sc_asn1_encode(ctx, asn1_ec_pointQ, buf, buflen));
|
||||
}
|
||||
|
||||
/*
|
||||
* EdDSA keys are just byte strings. For now only
|
||||
* for Ed25519 keys 32B length are supported
|
||||
*/
|
||||
int
|
||||
sc_pkcs15_decode_pubkey_eddsa(sc_context_t *ctx,
|
||||
struct sc_pkcs15_pubkey_eddsa *key,
|
||||
const u8 *buf, size_t buflen)
|
||||
{
|
||||
int r;
|
||||
u8 * pubkey = NULL;
|
||||
size_t pubkey_len;
|
||||
struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE];
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey);
|
||||
sc_format_asn1_entry(asn1_eddsa_pubkey + 0, &pubkey, &pubkey_len, 1);
|
||||
r = sc_asn1_decode(ctx, asn1_eddsa_pubkey, buf, buflen, NULL, NULL);
|
||||
if (r < 0)
|
||||
LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
|
||||
|
||||
key->pubkey.len = pubkey_len;
|
||||
key->pubkey.value = pubkey;
|
||||
|
||||
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
sc_pkcs15_encode_pubkey_eddsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_eddsa *key,
|
||||
u8 **buf, size_t *buflen)
|
||||
{
|
||||
struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE];
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey);
|
||||
sc_format_asn1_entry(asn1_eddsa_pubkey + 0, key->pubkey.value, &key->pubkey.len, 1);
|
||||
|
||||
LOG_FUNC_RETURN(ctx,
|
||||
sc_asn1_encode(ctx, asn1_eddsa_pubkey, buf, buflen));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key,
|
||||
|
@ -780,6 +827,9 @@ sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key,
|
|||
return sc_pkcs15_encode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len);
|
||||
if (key->algorithm == SC_ALGORITHM_EC)
|
||||
return sc_pkcs15_encode_pubkey_ec(ctx, &key->u.ec, buf, len);
|
||||
if (key->algorithm == SC_ALGORITHM_EDDSA ||
|
||||
key->algorithm == SC_ALGORITHM_XEDDSA) /* XXX encoding is the same here */
|
||||
return sc_pkcs15_encode_pubkey_eddsa(ctx, &key->u.eddsa, buf, len);
|
||||
|
||||
sc_log(ctx, "Encoding of public key type %u not supported", key->algorithm);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
|
@ -897,6 +947,9 @@ sc_pkcs15_decode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key,
|
|||
return sc_pkcs15_decode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len);
|
||||
if (key->algorithm == SC_ALGORITHM_EC)
|
||||
return sc_pkcs15_decode_pubkey_ec(ctx, &key->u.ec, buf, len);
|
||||
if (key->algorithm == SC_ALGORITHM_EDDSA ||
|
||||
key->algorithm == SC_ALGORITHM_XEDDSA)
|
||||
return sc_pkcs15_decode_pubkey_eddsa(ctx, &key->u.eddsa, buf, len);
|
||||
|
||||
sc_log(ctx, "Decoding of public key type %u not supported", key->algorithm);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
|
@ -939,6 +992,12 @@ sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_obj
|
|||
case SC_PKCS15_TYPE_PUBKEY_EC:
|
||||
algorithm = SC_ALGORITHM_EC;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_EDDSA:
|
||||
algorithm = SC_ALGORITHM_EDDSA;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_XEDDSA:
|
||||
algorithm = SC_ALGORITHM_XEDDSA;
|
||||
break;
|
||||
default:
|
||||
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported public key type.");
|
||||
}
|
||||
|
@ -984,7 +1043,8 @@ sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_obj
|
|||
r = sc_pkcs15_read_file(p15card, &info->path, &data, &len);
|
||||
LOG_TEST_GOTO_ERR(ctx, r, "Failed to read public key file.");
|
||||
|
||||
if (algorithm == SC_ALGORITHM_EC && *data == (SC_ASN1_TAG_SEQUENCE | SC_ASN1_TAG_CONSTRUCTED))
|
||||
if ((algorithm == SC_ALGORITHM_EC || algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA)
|
||||
&& *data == (SC_ASN1_TAG_SEQUENCE | SC_ASN1_TAG_CONSTRUCTED))
|
||||
r = sc_pkcs15_pubkey_from_spki_sequence(ctx, data, len, &pubkey);
|
||||
else
|
||||
r = sc_pkcs15_decode_pubkey(ctx, pubkey, data, len);
|
||||
|
@ -1067,6 +1127,22 @@ sc_pkcs15_pubkey_from_prvkey(struct sc_context *ctx, struct sc_pkcs15_prkey *prv
|
|||
}
|
||||
memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len);
|
||||
pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len;
|
||||
break;
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
/* Copy pubkey */
|
||||
if (prvkey->u.eddsa.pubkey.value == NULL || prvkey->u.eddsa.pubkey.len <= 0) {
|
||||
sc_pkcs15_free_pubkey(pubkey);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
|
||||
}
|
||||
pubkey->u.eddsa.pubkey.value = malloc(prvkey->u.eddsa.pubkey.len);
|
||||
if (!pubkey->u.eddsa.pubkey.value) {
|
||||
sc_pkcs15_free_pubkey(pubkey);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
memcpy(pubkey->u.eddsa.pubkey.value, prvkey->u.eddsa.pubkey.value, prvkey->u.eddsa.pubkey.len);
|
||||
pubkey->u.eddsa.pubkey.len = prvkey->u.eddsa.pubkey.len;
|
||||
|
||||
break;
|
||||
default:
|
||||
sc_log(ctx, "Unsupported private key algorithm");
|
||||
|
@ -1160,6 +1236,18 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
|
|||
rv = SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
break;
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
/* Copy pubkey */
|
||||
pubkey->u.eddsa.pubkey.value = malloc(key->u.eddsa.pubkey.len);
|
||||
if (!pubkey->u.eddsa.pubkey.value) {
|
||||
rv = SC_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
memcpy(pubkey->u.eddsa.pubkey.value, key->u.eddsa.pubkey.value, key->u.eddsa.pubkey.len);
|
||||
pubkey->u.eddsa.pubkey.len = key->u.eddsa.pubkey.len;
|
||||
|
||||
break;
|
||||
default:
|
||||
sc_log(ctx, "Unsupported private key algorithm");
|
||||
|
@ -1215,6 +1303,12 @@ sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *key)
|
|||
if (key->u.ec.ecpointQ.value)
|
||||
free(key->u.ec.ecpointQ.value);
|
||||
break;
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
free(key->u.eddsa.pubkey.value);
|
||||
key->u.eddsa.pubkey.value = NULL;
|
||||
key->u.eddsa.pubkey.len = 0;
|
||||
break;
|
||||
}
|
||||
sc_mem_clear(key, sizeof(*key));
|
||||
}
|
||||
|
@ -1413,8 +1507,7 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke
|
|||
}
|
||||
memcpy(pubkey->u.ec.ecpointQ.value, pk.value, pk.len);
|
||||
pubkey->u.ec.ecpointQ.len = pk.len;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* Public key is expected to be encapsulated into BIT STRING */
|
||||
r = sc_pkcs15_decode_pubkey(ctx, pubkey, pk.value, pk.len);
|
||||
LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 parsing of subjectPubkeyInfo failed");
|
||||
|
@ -1517,7 +1610,11 @@ static struct ec_curve_info {
|
|||
|
||||
{"secp192k1", "1.3.132.0.31", "06052B8104001F", 192},
|
||||
{"secp256k1", "1.3.132.0.10", "06052B8104000A", 256},
|
||||
{NULL, NULL, NULL, 0},
|
||||
|
||||
{"ed25519", "1.3.6.1.4.1.11591.15.1", "06092B06010401DA470F01", 255},
|
||||
{"curve25519", "1.3.6.1.4.1.3029.1.5.1", "060A2B060104019755010501", 255},
|
||||
|
||||
{NULL, NULL, NULL, 0}, /* Do not touch this */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1715,6 +1812,12 @@ sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key)
|
|||
break;
|
||||
}
|
||||
#endif /* !defined(OPENSSL_NO_EC) */
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
case EVP_PKEY_ED25519: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
#endif /* EVP_PKEY_ED25519 */
|
||||
default:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ static int use_key(struct sc_pkcs15_card *p15card,
|
|||
|
||||
sc_unlock(p15card->card);
|
||||
|
||||
return r;
|
||||
LOG_FUNC_RETURN(p15card->card->ctx, r);
|
||||
}
|
||||
|
||||
static int format_senv(struct sc_pkcs15_card *p15card,
|
||||
|
@ -213,6 +213,28 @@ static int format_senv(struct sc_pkcs15_card *p15card,
|
|||
senv_out->algorithm = SC_ALGORITHM_GOSTR3410;
|
||||
break;
|
||||
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
*alg_info_out = sc_card_find_eddsa_alg(p15card->card, prkey->field_length, NULL);
|
||||
if (*alg_info_out == NULL) {
|
||||
sc_log(ctx,
|
||||
"Card does not support EDDSA with field_size %"SC_FORMAT_LEN_SIZE_T"u",
|
||||
prkey->field_length);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
senv_out->algorithm = SC_ALGORITHM_EDDSA;
|
||||
break;
|
||||
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
*alg_info_out = sc_card_find_xeddsa_alg(p15card->card, prkey->field_length, NULL);
|
||||
if (*alg_info_out == NULL) {
|
||||
sc_log(ctx,
|
||||
"Card does not support XEDDSA with field_size %"SC_FORMAT_LEN_SIZE_T"u",
|
||||
prkey->field_length);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
senv_out->algorithm = SC_ALGORITHM_XEDDSA;
|
||||
break;
|
||||
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
*alg_info_out = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL);
|
||||
if (*alg_info_out == NULL) {
|
||||
|
@ -320,6 +342,7 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card,
|
|||
|
||||
switch (obj->type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
if (out == NULL || *poutlen < (prkey->field_length + 7) / 8) {
|
||||
*poutlen = (prkey->field_length + 7) / 8;
|
||||
r = 0; /* say no data to return */
|
||||
|
@ -580,7 +603,9 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
|||
modlen = (prkey->modulus_length + 7) / 8 * 2;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
modlen = ((prkey->field_length +7) / 8) * 2; /* 2*nLen */
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
modlen = ((prkey->field_length +7) / 8) * 2; /* 2*nLen */
|
||||
break;
|
||||
default:
|
||||
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported");
|
||||
|
|
|
@ -364,6 +364,7 @@ int sc_pkcs15emu_add_ec_prkey(sc_pkcs15_card_t *p15card,
|
|||
|
||||
return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_EC, obj, &key);
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_add_ec_pubkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
|
||||
{
|
||||
|
@ -375,6 +376,56 @@ int sc_pkcs15emu_add_ec_pubkey(sc_pkcs15_card_t *p15card,
|
|||
return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_EC, obj, &key);
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_add_eddsa_prkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_object_t *obj, const sc_pkcs15_prkey_info_t *in_key)
|
||||
{
|
||||
sc_pkcs15_prkey_info_t key = *in_key;
|
||||
|
||||
if (key.access_flags == 0)
|
||||
key.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
|
||||
| SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
|
||||
| SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
|
||||
| SC_PKCS15_PRKEY_ACCESS_LOCAL;
|
||||
|
||||
return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_EDDSA, obj, &key);
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_add_eddsa_pubkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
|
||||
{
|
||||
sc_pkcs15_pubkey_info_t key = *in_key;
|
||||
|
||||
if (key.access_flags == 0)
|
||||
key.access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
|
||||
|
||||
return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_EDDSA, obj, &key);
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_add_xeddsa_prkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_object_t *obj, const sc_pkcs15_prkey_info_t *in_key)
|
||||
{
|
||||
sc_pkcs15_prkey_info_t key = *in_key;
|
||||
|
||||
if (key.access_flags == 0)
|
||||
key.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
|
||||
| SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
|
||||
| SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
|
||||
| SC_PKCS15_PRKEY_ACCESS_LOCAL;
|
||||
|
||||
return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_XEDDSA, obj, &key);
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_add_xeddsa_pubkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
|
||||
{
|
||||
sc_pkcs15_pubkey_info_t key = *in_key;
|
||||
|
||||
if (key.access_flags == 0)
|
||||
key.access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
|
||||
|
||||
return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_XEDDSA, obj, &key);
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_add_x509_cert(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_object_t *obj, const sc_pkcs15_cert_info_t *cert)
|
||||
{
|
||||
|
|
|
@ -221,12 +221,21 @@ struct sc_pkcs15_pubkey_ec {
|
|||
struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */
|
||||
};
|
||||
|
||||
struct sc_pkcs15_pubkey_eddsa {
|
||||
struct sc_pkcs15_u8 pubkey;
|
||||
};
|
||||
|
||||
struct sc_pkcs15_prkey_ec {
|
||||
struct sc_ec_parameters params;
|
||||
sc_pkcs15_bignum_t privateD; /* note this is bignum */
|
||||
struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */
|
||||
};
|
||||
|
||||
struct sc_pkcs15_prkey_eddsa {
|
||||
struct sc_pkcs15_u8 pubkey;
|
||||
struct sc_pkcs15_u8 value;
|
||||
};
|
||||
|
||||
struct sc_pkcs15_pubkey_gostr3410 {
|
||||
struct sc_pkcs15_gost_parameters params;
|
||||
sc_pkcs15_bignum_t xy;
|
||||
|
@ -246,6 +255,7 @@ struct sc_pkcs15_pubkey {
|
|||
struct sc_pkcs15_pubkey_rsa rsa;
|
||||
struct sc_pkcs15_pubkey_dsa dsa;
|
||||
struct sc_pkcs15_pubkey_ec ec;
|
||||
struct sc_pkcs15_pubkey_eddsa eddsa;
|
||||
struct sc_pkcs15_pubkey_gostr3410 gostr3410;
|
||||
} u;
|
||||
};
|
||||
|
@ -259,6 +269,7 @@ struct sc_pkcs15_prkey {
|
|||
struct sc_pkcs15_prkey_rsa rsa;
|
||||
struct sc_pkcs15_prkey_dsa dsa;
|
||||
struct sc_pkcs15_prkey_ec ec;
|
||||
struct sc_pkcs15_prkey_eddsa eddsa;
|
||||
struct sc_pkcs15_prkey_gostr3410 gostr3410;
|
||||
struct sc_pkcs15_skey secret;
|
||||
} u;
|
||||
|
@ -440,12 +451,16 @@ typedef struct sc_pkcs15_skey_info sc_pkcs15_skey_info_t;
|
|||
#define SC_PKCS15_TYPE_PRKEY_DSA 0x102
|
||||
#define SC_PKCS15_TYPE_PRKEY_GOSTR3410 0x103
|
||||
#define SC_PKCS15_TYPE_PRKEY_EC 0x104
|
||||
#define SC_PKCS15_TYPE_PRKEY_EDDSA 0x105
|
||||
#define SC_PKCS15_TYPE_PRKEY_XEDDSA 0x106
|
||||
|
||||
#define SC_PKCS15_TYPE_PUBKEY 0x200
|
||||
#define SC_PKCS15_TYPE_PUBKEY_RSA 0x201
|
||||
#define SC_PKCS15_TYPE_PUBKEY_DSA 0x202
|
||||
#define SC_PKCS15_TYPE_PUBKEY_GOSTR3410 0x203
|
||||
#define SC_PKCS15_TYPE_PUBKEY_EC 0x204
|
||||
#define SC_PKCS15_TYPE_PUBKEY_EDDSA 0x205
|
||||
#define SC_PKCS15_TYPE_PUBKEY_XEDDSA 0x206
|
||||
|
||||
#define SC_PKCS15_TYPE_SKEY 0x300
|
||||
#define SC_PKCS15_TYPE_SKEY_GENERIC 0x301
|
||||
|
@ -705,6 +720,8 @@ int sc_pkcs15_decode_pubkey_ec(struct sc_context *,
|
|||
struct sc_pkcs15_pubkey_ec *, const u8 *, size_t);
|
||||
int sc_pkcs15_encode_pubkey_ec(struct sc_context *,
|
||||
struct sc_pkcs15_pubkey_ec *, u8 **, size_t *);
|
||||
int sc_pkcs15_encode_pubkey_eddsa(struct sc_context *,
|
||||
struct sc_pkcs15_pubkey_eddsa *, u8 **, size_t *);
|
||||
int sc_pkcs15_decode_pubkey(struct sc_context *,
|
||||
struct sc_pkcs15_pubkey *, const u8 *, size_t);
|
||||
int sc_pkcs15_encode_pubkey(struct sc_context *,
|
||||
|
@ -1014,6 +1031,14 @@ int sc_pkcs15emu_add_ec_prkey(struct sc_pkcs15_card *,
|
|||
const struct sc_pkcs15_object *, const sc_pkcs15_prkey_info_t *);
|
||||
int sc_pkcs15emu_add_ec_pubkey(struct sc_pkcs15_card *,
|
||||
const struct sc_pkcs15_object *, const sc_pkcs15_pubkey_info_t *);
|
||||
int sc_pkcs15emu_add_eddsa_prkey(struct sc_pkcs15_card *,
|
||||
const struct sc_pkcs15_object *, const sc_pkcs15_prkey_info_t *);
|
||||
int sc_pkcs15emu_add_eddsa_pubkey(struct sc_pkcs15_card *,
|
||||
const struct sc_pkcs15_object *, const sc_pkcs15_pubkey_info_t *);
|
||||
int sc_pkcs15emu_add_xeddsa_prkey(struct sc_pkcs15_card *,
|
||||
const struct sc_pkcs15_object *, const sc_pkcs15_prkey_info_t *);
|
||||
int sc_pkcs15emu_add_xeddsa_pubkey(struct sc_pkcs15_card *,
|
||||
const struct sc_pkcs15_object *, const sc_pkcs15_pubkey_info_t *);
|
||||
int sc_pkcs15emu_add_x509_cert(struct sc_pkcs15_card *,
|
||||
const struct sc_pkcs15_object *, const sc_pkcs15_cert_info_t *);
|
||||
int sc_pkcs15emu_add_data_object(struct sc_pkcs15_card *,
|
||||
|
|
|
@ -38,7 +38,7 @@ int sc_decipher(sc_card_t *card,
|
|||
int r;
|
||||
|
||||
if (card == NULL || crgram == NULL || out == NULL) {
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
}
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
if (card->ops->decipher == NULL)
|
||||
|
|
|
@ -79,6 +79,8 @@ static struct fmap map_CKA_KEY_TYPE[] = {
|
|||
_(CKK_DH),
|
||||
_(CKK_ECDSA),
|
||||
_(CKK_EC),
|
||||
_(CKK_EC_EDWARDS),
|
||||
_(CKK_EC_MONTGOMERY),
|
||||
_(CKK_RC2),
|
||||
_(CKK_RC4),
|
||||
_(CKK_RC5),
|
||||
|
@ -145,8 +147,8 @@ static struct fmap p11_attr_names[] = {
|
|||
b(CKA_ALWAYS_SENSITIVE),
|
||||
_(CKA_KEY_GEN_MECHANISM),
|
||||
b(CKA_MODIFIABLE),
|
||||
_(CKA_ECDSA_PARAMS),
|
||||
_(CKA_EC_PARAMS),
|
||||
_(CKA_ECDSA_PARAMS),
|
||||
_(CKA_EC_POINT),
|
||||
_(CKA_SECONDARY_AUTH),
|
||||
ul(CKA_AUTH_PIN_FLAGS),
|
||||
|
|
|
@ -1079,6 +1079,8 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot, struct pkcs15_any_object *obj,
|
|||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
if (slot->p11card != NULL) {
|
||||
pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL);
|
||||
if (!slot->p11card)
|
||||
|
@ -1269,6 +1271,26 @@ _pkcs15_create_typed_objects(struct pkcs15_fw_data *fw_data)
|
|||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = pkcs15_create_pkcs11_objects(fw_data, SC_PKCS15_TYPE_PRKEY_EDDSA, "EdDSA private key",
|
||||
__pkcs15_create_prkey_object);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = pkcs15_create_pkcs11_objects(fw_data, SC_PKCS15_TYPE_PUBKEY_EDDSA, "EdDSA public key",
|
||||
__pkcs15_create_pubkey_object);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = pkcs15_create_pkcs11_objects(fw_data, SC_PKCS15_TYPE_PRKEY_XEDDSA, "XEdDSA private key",
|
||||
__pkcs15_create_prkey_object);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = pkcs15_create_pkcs11_objects(fw_data, SC_PKCS15_TYPE_PUBKEY_XEDDSA, "XEdDSA public key",
|
||||
__pkcs15_create_pubkey_object);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = pkcs15_create_pkcs11_objects(fw_data, SC_PKCS15_TYPE_PRKEY_GOSTR3410, "GOSTR3410 private key",
|
||||
__pkcs15_create_prkey_object);
|
||||
if (rv < 0)
|
||||
|
@ -1512,7 +1534,7 @@ _add_public_objects(struct sc_pkcs11_slot *slot, struct pkcs15_fw_data *fw_data)
|
|||
/* PKCS#15 4.1.3 is a little vague, but implies if not PRIVATE it is readable
|
||||
* even if there is an auth_id to allow writing for example.
|
||||
* See bug issue #291
|
||||
* treat pubkey and cert as readable.a
|
||||
* treat pubkey and cert as readable.
|
||||
*/
|
||||
if (obj->p15_object->auth_id.len && !(is_pubkey(obj) || is_cert(obj)))
|
||||
continue;
|
||||
|
@ -2219,6 +2241,14 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil
|
|||
args.key.algorithm = SC_ALGORITHM_GOSTR3410;
|
||||
gost = &args.key.u.gostr3410;
|
||||
break;
|
||||
case CKK_EC_EDWARDS:
|
||||
args.key.algorithm = SC_ALGORITHM_EDDSA;
|
||||
/* TODO */
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
case CKK_EC_MONTGOMERY:
|
||||
args.key.algorithm = SC_ALGORITHM_XEDDSA;
|
||||
/* TODO */
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
case CKK_EC:
|
||||
args.key.algorithm = SC_ALGORITHM_EC;
|
||||
/* TODO: -DEE Do not have PKCS15 card with EC to test this */
|
||||
|
@ -2563,6 +2593,8 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile
|
|||
rsa = &args.key.u.rsa;
|
||||
break;
|
||||
case CKK_EC:
|
||||
case CKK_EC_EDWARDS:
|
||||
case CKK_EC_MONTGOMERY:
|
||||
/* TODO: -DEE Do not have real pkcs15 card with EC */
|
||||
/* fall through */
|
||||
default:
|
||||
|
@ -3093,7 +3125,9 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism,
|
|||
|
||||
if (pMechanism->mechanism != CKM_RSA_PKCS_KEY_PAIR_GEN
|
||||
&& pMechanism->mechanism != CKM_GOSTR3410_KEY_PAIR_GEN
|
||||
&& pMechanism->mechanism != CKM_EC_KEY_PAIR_GEN)
|
||||
&& pMechanism->mechanism != CKM_EC_KEY_PAIR_GEN
|
||||
&& pMechanism->mechanism != CKM_EC_EDWARDS_KEY_PAIR_GEN
|
||||
&& pMechanism->mechanism != CKM_EC_MONTGOMERY_KEY_PAIR_GEN)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
if (!p11card)
|
||||
|
@ -3137,6 +3171,10 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism,
|
|||
keytype = CKK_RSA;
|
||||
else if (rv != CKR_OK && pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN)
|
||||
keytype = CKK_EC;
|
||||
else if (rv != CKR_OK && pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN)
|
||||
keytype = CKK_EC_EDWARDS;
|
||||
else if (rv != CKR_OK && pMechanism->mechanism == CKM_EC_MONTGOMERY_KEY_PAIR_GEN)
|
||||
keytype = CKK_EC_MONTGOMERY;
|
||||
else if (rv != CKR_OK && pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN)
|
||||
keytype = CKK_GOSTR3410;
|
||||
else if (rv != CKR_OK)
|
||||
|
@ -3170,12 +3208,30 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism,
|
|||
der->value = (unsigned char *) ptr;
|
||||
if (rv != CKR_OK) {
|
||||
sc_unlock(p11card->card);
|
||||
return sc_to_cryptoki_error(rc, "C_GenerateKeyPair");
|
||||
return sc_to_cryptoki_error(rv, "C_GenerateKeyPair");
|
||||
}
|
||||
|
||||
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_EC;
|
||||
pub_args.key.algorithm = SC_ALGORITHM_EC;
|
||||
}
|
||||
else if (keytype == CKK_EC_EDWARDS) {
|
||||
/* TODO Validate EC_PARAMS contains curveName "edwards25519" or "edwards448" (from RFC 8032)
|
||||
* or id-Ed25519 or id-Ed448 (or equivalent OIDs in oId field) (from RFC 8410)
|
||||
* otherwise return CKR_CURVE_NOT_SUPPORTED
|
||||
*/
|
||||
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_EDDSA;
|
||||
pub_args.key.algorithm = SC_ALGORITHM_EDDSA;
|
||||
return CKR_CURVE_NOT_SUPPORTED;
|
||||
}
|
||||
else if (keytype == CKK_EC_MONTGOMERY) {
|
||||
/* TODO Validate EC_PARAMS contains curveName "curve25519" or "curve448" (from RFC 7748)
|
||||
* or id-X25519 or id-X448 (or equivalent OIDs in oId field) (from RFC 8410)
|
||||
* otherwise return CKR_CURVE_NOT_SUPPORTED
|
||||
*/
|
||||
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_XEDDSA;
|
||||
pub_args.key.algorithm = SC_ALGORITHM_XEDDSA;
|
||||
return CKR_CURVE_NOT_SUPPORTED;
|
||||
}
|
||||
else {
|
||||
/* CKA_KEY_TYPE is set, but keytype isn't correct */
|
||||
rv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
|
@ -3788,7 +3844,7 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
|
|||
*/
|
||||
if ((attr->type == CKA_MODULUS) || (attr->type == CKA_PUBLIC_EXPONENT) ||
|
||||
((attr->type == CKA_MODULUS_BITS) && (prkey->prv_p15obj->type == SC_PKCS15_TYPE_PRKEY_EC)) ||
|
||||
(attr->type == CKA_ECDSA_PARAMS)) {
|
||||
(attr->type == CKA_EC_PARAMS)) {
|
||||
/* First see if we have an associated public key */
|
||||
if (prkey->pub_data) {
|
||||
key = prkey->pub_data;
|
||||
|
@ -3886,6 +3942,12 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
|
|||
case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_EC_EDWARDS;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_EC_MONTGOMERY;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_EC;
|
||||
break;
|
||||
|
@ -3917,6 +3979,11 @@ pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
|
|||
case CKA_MODULUS_BITS:
|
||||
check_attribute_buffer(attr, sizeof(CK_ULONG));
|
||||
switch (prkey->prv_p15obj->type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
/* TODO where to get field length ? */
|
||||
*(CK_ULONG *) attr->pValue = 255;
|
||||
return CKR_OK;
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
if (key) {
|
||||
if (key->u.ec.params.field_length > 0)
|
||||
|
@ -4133,6 +4200,12 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj,
|
|||
case CKM_GOSTR3410_WITH_GOSTR3411:
|
||||
flags = SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411;
|
||||
break;
|
||||
case CKM_EDDSA:
|
||||
flags = SC_ALGORITHM_EDDSA_RAW;
|
||||
break;
|
||||
case CKM_XEDDSA:
|
||||
flags = SC_ALGORITHM_XEDDSA_RAW;
|
||||
break;
|
||||
case CKM_ECDSA:
|
||||
flags = SC_ALGORITHM_ECDSA_HASH_NONE;
|
||||
break;
|
||||
|
@ -4200,7 +4273,7 @@ pkcs15_prkey_unwrap(struct sc_pkcs11_session *session, void *obj,
|
|||
struct pkcs15_fw_data *fw_data = NULL;
|
||||
struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj;
|
||||
struct pkcs15_any_object *targetKeyObj = (struct pkcs15_any_object *) targetKey;
|
||||
int rv;
|
||||
int rv;
|
||||
|
||||
sc_log(context, "Initiating unwrapping with private key.");
|
||||
|
||||
|
@ -4413,6 +4486,7 @@ pkcs15_prkey_derive(struct sc_pkcs11_session *session, void *obj,
|
|||
*/
|
||||
switch (prkey->base.p15_object->type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
case SC_PKCS15_TYPE_PRKEY_XEDDSA:
|
||||
{
|
||||
CK_ECDH1_DERIVE_PARAMS * ecdh_params = (CK_ECDH1_DERIVE_PARAMS *) pParameters;
|
||||
ulSeedDataLen = ecdh_params->ulPublicDataLen;
|
||||
|
@ -4736,6 +4810,10 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_
|
|||
/* even if we do not, we should not assume RSA */
|
||||
if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_GOSTR3410)
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410;
|
||||
else if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_EDDSA)
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_EC_EDWARDS;
|
||||
else if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_XEDDSA)
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_EC_MONTGOMERY;
|
||||
else if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_EC)
|
||||
*(CK_KEY_TYPE*)attr->pValue = CKK_EC;
|
||||
else
|
||||
|
@ -5486,6 +5564,10 @@ static CK_RV
|
|||
get_ec_pubkey_params(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
|
||||
{
|
||||
struct sc_ec_parameters *ecp;
|
||||
unsigned long value_len = 0;
|
||||
unsigned char *value = NULL;
|
||||
|
||||
int r;
|
||||
|
||||
if (key == NULL)
|
||||
return CKR_ATTRIBUTE_TYPE_INVALID;
|
||||
|
@ -5493,6 +5575,27 @@ get_ec_pubkey_params(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
|
|||
return CKR_ATTRIBUTE_TYPE_INVALID;
|
||||
|
||||
switch (key->algorithm) {
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
r = sc_encode_oid(context, &key->alg_id->oid, &value, (size_t *)&value_len);
|
||||
if (r != SC_SUCCESS) {
|
||||
return sc_to_cryptoki_error(r, NULL);
|
||||
}
|
||||
|
||||
attr->ulValueLen = value_len;
|
||||
if (attr->pValue == NULL_PTR) {
|
||||
free(value);
|
||||
return CKR_OK;
|
||||
}
|
||||
if (attr->ulValueLen < value_len) {
|
||||
free(value);
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
memcpy(attr->pValue, value, value_len);
|
||||
free(value);
|
||||
return CKR_OK;
|
||||
|
||||
case SC_ALGORITHM_EC:
|
||||
/* TODO parms should not be in two places */
|
||||
/* ec_params may be in key->alg_id or in key->u.ec */
|
||||
|
@ -5524,6 +5627,28 @@ get_ec_pubkey_point(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
|
|||
return CKR_ATTRIBUTE_TYPE_INVALID;
|
||||
|
||||
switch (key->algorithm) {
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
rc = sc_pkcs15_encode_pubkey_eddsa(context, &key->u.eddsa, &value, &value_len);
|
||||
if (rc != SC_SUCCESS)
|
||||
return sc_to_cryptoki_error(rc, NULL);
|
||||
|
||||
if (attr->pValue == NULL_PTR) {
|
||||
attr->ulValueLen = value_len;
|
||||
free(value);
|
||||
return CKR_OK;
|
||||
}
|
||||
if (attr->ulValueLen < value_len) {
|
||||
attr->ulValueLen = value_len;
|
||||
free(value);
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
attr->ulValueLen = value_len;
|
||||
|
||||
memcpy(attr->pValue, value, value_len);
|
||||
free(value);
|
||||
return CKR_OK;
|
||||
|
||||
case SC_ALGORITHM_EC:
|
||||
rc = sc_pkcs15_encode_pubkey_ec(context, &key->u.ec, &value, &value_len);
|
||||
if (rc != SC_SUCCESS)
|
||||
|
@ -5688,46 +5813,53 @@ static CK_RV register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
|
|||
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA, &mech_info, CKK_EC, NULL, NULL);
|
||||
if (!mt)
|
||||
return CKR_HOST_MEMORY;
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (flags & SC_ALGORITHM_ECDSA_HASH_NONE) {
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENSSL
|
||||
/* if card supports RAW add sign_and_hash using RAW for mechs card does not support */
|
||||
/* if card supports RAW add sign_and_hash using RAW for mechs card does not support */
|
||||
|
||||
if (flags & SC_ALGORITHM_ECDSA_RAW) {
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA1)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA1, CKM_SHA_1, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
if (flags & SC_ALGORITHM_ECDSA_RAW) {
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA1)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
|
||||
CKM_ECDSA_SHA1, CKM_SHA_1, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA224)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA224, CKM_SHA224, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA224)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
|
||||
CKM_ECDSA_SHA224, CKM_SHA224, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA256)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA256, CKM_SHA256, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA256)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
|
||||
CKM_ECDSA_SHA256, CKM_SHA256, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA384)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA384, CKM_SHA384, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA384)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
|
||||
CKM_ECDSA_SHA384, CKM_SHA384, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA512)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_ECDSA_SHA512, CKM_SHA512, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA512)) {
|
||||
rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
|
||||
CKM_ECDSA_SHA512, CKM_SHA512, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flags & SC_ALGORITHM_ECDSA_HASH_SHA1) {
|
||||
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1, &mech_info, CKK_EC, NULL, NULL);
|
||||
|
@ -5776,7 +5908,7 @@ static CK_RV register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
|
|||
|
||||
/* ADD ECDH mechanisms */
|
||||
/* The PIV uses curves where CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE produce the same results */
|
||||
if(flags & SC_ALGORITHM_ECDH_CDH_RAW) {
|
||||
if (flags & SC_ALGORITHM_ECDH_CDH_RAW) {
|
||||
mech_info.flags &= ~(CKF_SIGN | CKF_VERIFY);
|
||||
mech_info.flags |= CKF_DERIVE;
|
||||
|
||||
|
@ -5809,6 +5941,87 @@ static CK_RV register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
|
|||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_RV register_eddsa_mechanisms(struct sc_pkcs11_card *p11card, int flags,
|
||||
CK_ULONG min_key_size, CK_ULONG max_key_size)
|
||||
{
|
||||
CK_MECHANISM_INFO mech_info;
|
||||
sc_pkcs11_mechanism_type_t *mt;
|
||||
CK_RV rc;
|
||||
|
||||
mech_info.flags = CKF_HW | CKF_SIGN;
|
||||
mech_info.ulMinKeySize = min_key_size;
|
||||
mech_info.ulMaxKeySize = max_key_size;
|
||||
|
||||
if (flags & SC_ALGORITHM_EDDSA_RAW) {
|
||||
mt = sc_pkcs11_new_fw_mechanism(CKM_EDDSA, &mech_info, CKK_EC_EDWARDS, NULL, NULL);
|
||||
if (!mt)
|
||||
return CKR_HOST_MEMORY;
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
|
||||
mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
|
||||
mt = sc_pkcs11_new_fw_mechanism(CKM_EC_EDWARDS_KEY_PAIR_GEN,
|
||||
&mech_info, CKK_EC_EDWARDS, NULL, NULL);
|
||||
if (!mt)
|
||||
return CKR_HOST_MEMORY;
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_RV register_xeddsa_mechanisms(struct sc_pkcs11_card *p11card, int flags,
|
||||
CK_ULONG min_key_size, CK_ULONG max_key_size)
|
||||
{
|
||||
CK_MECHANISM_INFO mech_info;
|
||||
sc_pkcs11_mechanism_type_t *mt;
|
||||
CK_RV rc;
|
||||
|
||||
mech_info.flags = CKF_HW | CKF_SIGN | CKF_DERIVE;
|
||||
mech_info.ulMinKeySize = min_key_size;
|
||||
mech_info.ulMaxKeySize = max_key_size;
|
||||
|
||||
if (flags & SC_ALGORITHM_XEDDSA_RAW) {
|
||||
mt = sc_pkcs11_new_fw_mechanism(CKM_XEDDSA, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL);
|
||||
if (!mt)
|
||||
return CKR_HOST_MEMORY;
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* ADD ECDH mechanisms */
|
||||
if (flags & SC_ALGORITHM_ECDH_CDH_RAW) {
|
||||
mech_info.flags &= ~CKF_SIGN;
|
||||
mech_info.flags |= CKF_DERIVE;
|
||||
|
||||
/* Montgomery curves derive function is defined only for CKM_ECDH1_DERIVE mechanism */
|
||||
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL);
|
||||
if (!mt)
|
||||
return CKR_HOST_MEMORY;
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
|
||||
mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
|
||||
mt = sc_pkcs11_new_fw_mechanism(CKM_EC_MONTGOMERY_KEY_PAIR_GEN, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL);
|
||||
if (!mt)
|
||||
return CKR_HOST_MEMORY;
|
||||
rc = sc_pkcs11_register_mechanism(p11card, mt);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static int sc_pkcs11_register_aes_mechanisms(struct sc_pkcs11_card *p11card, int flags,
|
||||
CK_ULONG min_key_size, CK_ULONG max_key_size)
|
||||
{
|
||||
|
@ -5866,8 +6079,8 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
|
|||
unsigned long ec_ext_flags;
|
||||
sc_pkcs11_mechanism_type_t *mt;
|
||||
unsigned int num;
|
||||
int rsa_flags = 0, ec_flags = 0, gostr_flags = 0, aes_flags = 0;
|
||||
int ec_found;
|
||||
int rsa_flags = 0, ec_flags = 0, eddsa_flags = 0, xeddsa_flags = 0;
|
||||
int ec_found = 0, gostr_flags = 0, aes_flags = 0;
|
||||
CK_RV rc;
|
||||
|
||||
/* Register generic mechanisms */
|
||||
|
@ -5887,7 +6100,6 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
|
|||
mech_info.ulMaxKeySize = 0;
|
||||
ec_min_key_size = ~0;
|
||||
ec_max_key_size = 0;
|
||||
ec_found = 0;
|
||||
aes_min_key_size = ~0;
|
||||
aes_max_key_size = 0;
|
||||
|
||||
|
@ -5916,6 +6128,12 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
|
|||
ec_ext_flags |= alg_info->u._ec.ext_flags;
|
||||
ec_found = 1;
|
||||
break;
|
||||
case SC_ALGORITHM_EDDSA:
|
||||
eddsa_flags |= alg_info->flags;
|
||||
break;
|
||||
case SC_ALGORITHM_XEDDSA:
|
||||
xeddsa_flags |= alg_info->flags;
|
||||
break;
|
||||
case SC_ALGORITHM_GOSTR3410:
|
||||
gostr_flags |= alg_info->flags;
|
||||
break;
|
||||
|
@ -5941,6 +6159,18 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (eddsa_flags & SC_ALGORITHM_EDDSA_RAW) {
|
||||
rc = register_eddsa_mechanisms(p11card, eddsa_flags, 255, 255);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (xeddsa_flags & (SC_ALGORITHM_XEDDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW)) {
|
||||
rc = register_xeddsa_mechanisms(p11card, xeddsa_flags, 255, 255);
|
||||
if (rc != CKR_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (gostr_flags & (SC_ALGORITHM_GOSTR3410_RAW
|
||||
| SC_ALGORITHM_GOSTR3410_HASH_NONE
|
||||
| SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411)) {
|
||||
|
|
|
@ -504,9 +504,12 @@ sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength)
|
|||
*pLength = (*pLength + 7) / 8;
|
||||
break;
|
||||
case CKK_EC:
|
||||
case CKK_EC_EDWARDS:
|
||||
case CKK_EC_MONTGOMERY:
|
||||
/* TODO: -DEE we should use something other then CKA_MODULUS_BITS... */
|
||||
rv = key->ops->get_attribute(operation->session, key, &attr);
|
||||
*pLength = ((*pLength + 7)/8) * 2 ; /* 2*nLen in bytes */
|
||||
if (rv == CKR_OK)
|
||||
*pLength = ((*pLength + 7)/8) * 2 ; /* 2*nLen in bytes */
|
||||
break;
|
||||
case CKK_GOSTR3410:
|
||||
rv = key->ops->get_attribute(operation->session, key, &attr);
|
||||
|
|
|
@ -279,6 +279,8 @@ static enum_specs ck_key_s[] = {
|
|||
{ CKK_DSA , "CKK_DSA " },
|
||||
{ CKK_DH , "CKK_DH " },
|
||||
{ CKK_EC , "CKK_EC " },
|
||||
{ CKK_EC_EDWARDS , "CKK_EC_EDWARDS " },
|
||||
{ CKK_EC_MONTGOMERY , "CKK_EC_MONTOGMERY " },
|
||||
{ CKK_X9_42_DH , "CKK_X9_42_DH " },
|
||||
{ CKK_KEA , "CKK_KEA " },
|
||||
{ CKK_GENERIC_SECRET, "CKK_GENERIC_SECRET " },
|
||||
|
@ -497,6 +499,8 @@ static enum_specs ck_mec_s[] = {
|
|||
{ CKM_ECDH1_DERIVE , "CKM_ECDH1_DERIVE " },
|
||||
{ CKM_ECDH1_COFACTOR_DERIVE , "CKM_ECDH1_COFACTOR_DERIVE " },
|
||||
{ CKM_ECMQV_DERIVE , "CKM_ECMQV_DERIVE " },
|
||||
{ CKM_EDDSA , "CKM_EDDSA " },
|
||||
{ CKM_XEDDSA , "CKM_XEDDSA " },
|
||||
{ CKM_JUNIPER_KEY_GEN , "CKM_JUNIPER_KEY_GEN " },
|
||||
{ CKM_JUNIPER_ECB128 , "CKM_JUNIPER_ECB128 " },
|
||||
{ CKM_JUNIPER_CBC128 , "CKM_JUNIPER_CBC128 " },
|
||||
|
@ -753,8 +757,8 @@ type_spec ck_attribute_specs[] = {
|
|||
{ CKA_ALWAYS_SENSITIVE , "CKA_ALWAYS_SENSITIVE ", print_boolean, NULL },
|
||||
{ CKA_KEY_GEN_MECHANISM , "CKA_KEY_GEN_MECHANISM", print_boolean, NULL },
|
||||
{ CKA_MODIFIABLE , "CKA_MODIFIABLE ", print_boolean, NULL },
|
||||
{ CKA_ECDSA_PARAMS , "CKA_ECDSA_PARAMS ", print_generic, NULL },
|
||||
{ CKA_EC_PARAMS , "CKA_EC_PARAMS ", print_generic, NULL },
|
||||
{ CKA_ECDSA_PARAMS , "CKA_ECDSA_PARAMS ", print_generic, NULL },
|
||||
{ CKA_EC_POINT , "CKA_EC_POINT ", print_generic, NULL },
|
||||
{ CKA_SECONDARY_AUTH , "CKA_SECONDARY_AUTH ", print_generic, NULL },
|
||||
{ CKA_AUTH_PIN_FLAGS , "CKA_AUTH_PIN_FLAGS ", print_generic, NULL },
|
||||
|
|
|
@ -1249,6 +1249,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|||
|
||||
switch(key_type) {
|
||||
case CKK_EC:
|
||||
case CKK_EC_MONTGOMERY:
|
||||
|
||||
rv = sc_create_object_int(hSession, pTemplate, ulAttributeCount, phKey, 0);
|
||||
if (rv != CKR_OK)
|
||||
|
|
|
@ -543,9 +543,9 @@ C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
|
|||
enter("C_GetMechanismInfo");
|
||||
spy_dump_ulong_in("slotID", slotID);
|
||||
if (name)
|
||||
fprintf(spy_output, "%30s \n", name);
|
||||
fprintf(spy_output, "[in] type = %30s\n", name);
|
||||
else
|
||||
fprintf(spy_output, " Unknown Mechanism (%08lx) \n", type);
|
||||
fprintf(spy_output, "[in] type = Unknown Mechanism (%08lx)\n", type);
|
||||
|
||||
rv = po->C_GetMechanismInfo(slotID, type, pInfo);
|
||||
if(rv == CKR_OK) {
|
||||
|
|
|
@ -370,6 +370,8 @@ typedef unsigned long ck_key_type_t;
|
|||
#define CKK_GOSTR3410 (0x30UL)
|
||||
#define CKK_GOSTR3411 (0x31UL)
|
||||
#define CKK_GOST28147 (0x32UL)
|
||||
#define CKK_EC_EDWARDS (0x40UL)
|
||||
#define CKK_EC_MONTGOMERY (0x41UL)
|
||||
#define CKK_VENDOR_DEFINED (1UL << 31)
|
||||
|
||||
// A mask for new GOST algorithms.
|
||||
|
@ -603,6 +605,18 @@ typedef unsigned long ck_mechanism_type_t;
|
|||
#define CKM_SHA512 (0x270UL)
|
||||
#define CKM_SHA512_HMAC (0x271UL)
|
||||
#define CKM_SHA512_HMAC_GENERAL (0x272UL)
|
||||
#define CKM_SHA3_256 (0x2B0UL)
|
||||
#define CKM_SHA3_256_HMAC (0x2B1UL)
|
||||
#define CKM_SHA3_256_HMAC_GENERAL (0x2B2UL)
|
||||
#define CKM_SHA3_224 (0x2B5UL)
|
||||
#define CKM_SHA3_224_HMAC (0x2B6UL)
|
||||
#define CKM_SHA3_224_HMAC_GENERAL (0x2B7UL)
|
||||
#define CKM_SHA3_384 (0x2C0UL)
|
||||
#define CKM_SHA3_384_HMAC (0x2C1UL)
|
||||
#define CKM_SHA3_384_HMAC_GENERAL (0x2C2UL)
|
||||
#define CKM_SHA3_512 (0x2D0UL)
|
||||
#define CKM_SHA3_512_HMAC (0x2D1UL)
|
||||
#define CKM_SHA3_512_HMAC_GENERAL (0x2D2UL)
|
||||
#define CKM_CAST_KEY_GEN (0x300UL)
|
||||
#define CKM_CAST_ECB (0x301UL)
|
||||
#define CKM_CAST_CBC (0x302UL)
|
||||
|
@ -708,6 +722,9 @@ typedef unsigned long ck_mechanism_type_t;
|
|||
#define CKM_ECDH1_DERIVE (0x1050UL)
|
||||
#define CKM_ECDH1_COFACTOR_DERIVE (0x1051UL)
|
||||
#define CKM_ECMQV_DERIVE (0x1052UL)
|
||||
#define CKM_EC_EDWARDS_KEY_PAIR_GEN (0x1055UL)
|
||||
#define CKM_EC_MONTGOMERY_KEY_PAIR_GEN (0x1056UL)
|
||||
#define CKM_EDDSA (0x1057UL)
|
||||
#define CKM_JUNIPER_KEY_GEN (0x1060UL)
|
||||
#define CKM_JUNIPER_ECB128 (0x1061UL)
|
||||
#define CKM_JUNIPER_CBC128 (0x1062UL)
|
||||
|
@ -762,6 +779,7 @@ typedef unsigned long ck_mechanism_type_t;
|
|||
#define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL)
|
||||
#define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL)
|
||||
#define CKM_AES_KEY_WRAP (0x2109UL)
|
||||
#define CKM_XEDDSA (0x4029UL)
|
||||
#define CKM_VENDOR_DEFINED (1UL << 31)
|
||||
|
||||
|
||||
|
@ -870,6 +888,22 @@ typedef struct CK_GCM_PARAMS {
|
|||
unsigned long ulTagBits;
|
||||
} CK_GCM_PARAMS;
|
||||
|
||||
/* EDDSA */
|
||||
typedef struct CK_EDDSA_PARAMS {
|
||||
unsigned char phFlag;
|
||||
unsigned long ulContextDataLen;
|
||||
unsigned char *pContextData;
|
||||
} CK_EDDSA_PARAMS;
|
||||
|
||||
typedef CK_EDDSA_PARAMS *CK_EDDSA_PARAMS_PTR;
|
||||
|
||||
/* XEDDSA */
|
||||
typedef struct CK_XEDDSA_PARAMS {
|
||||
unsigned long hash;
|
||||
} CK_XEDDSA_PARAMS;
|
||||
|
||||
typedef CK_XEDDSA_PARAMS *CK_XEDDSA_PARAMS_PTR;
|
||||
|
||||
typedef unsigned long ck_rv_t;
|
||||
|
||||
|
||||
|
@ -1580,6 +1614,7 @@ struct ck_c_initialize_args
|
|||
#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120UL)
|
||||
#define CKR_RANDOM_NO_RNG (0x121UL)
|
||||
#define CKR_DOMAIN_PARAMS_INVALID (0x130UL)
|
||||
#define CKR_CURVE_NOT_SUPPORTED (0x140UL)
|
||||
#define CKR_BUFFER_TOO_SMALL (0x150UL)
|
||||
#define CKR_SAVED_STATE_INVALID (0x160UL)
|
||||
#define CKR_INFORMATION_SENSITIVE (0x170UL)
|
||||
|
|
|
@ -165,6 +165,23 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
|||
key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1;
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA keys not supported on this card");
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t));
|
||||
key_info.algorithm = (kinfo->id.value[0] == SC_OPENPGP_KEY_ENCR)
|
||||
? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */
|
||||
: SC_OPENPGP_KEYALGO_EDDSA; /* EdDSA for slot 1 and 3 */
|
||||
key_info.key_id = kinfo->id.value[0];
|
||||
/* TODO Test -- might not work */
|
||||
key_info.u.ec.privateD = key->u.ec.privateD.data;
|
||||
key_info.u.ec.privateD_len = key->u.ec.privateD.len;
|
||||
key_info.u.ec.ecpointQ = key->u.ec.ecpointQ.value;
|
||||
key_info.u.ec.ecpointQ_len = key->u.ec.ecpointQ.len;
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
|
||||
break;
|
||||
default:
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
sc_log(card->ctx, "%s: Key generation failed: Unknown/unsupported key type.", strerror(r));
|
||||
|
@ -367,6 +384,13 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card
|
|||
}
|
||||
r = openpgp_generate_key_ec(card, obj, pubkey);
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EDDSA:
|
||||
if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA is not supported on this card");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
r = openpgp_generate_key_ec(card, obj, pubkey);
|
||||
break;
|
||||
default:
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
sc_log(card->ctx, "%s: Key generation failed: Unknown/unsupported key type.", strerror(r));
|
||||
|
|
|
@ -114,7 +114,7 @@ add_supported_mechs(test_cert_t *o)
|
|||
if (token.num_rsa_mechs > 0 ) {
|
||||
/* Get supported mechanisms by token */
|
||||
o->num_mechs = token.num_rsa_mechs;
|
||||
for (i = 0; i <= token.num_rsa_mechs; i++) {
|
||||
for (i = 0; i < token.num_rsa_mechs; i++) {
|
||||
o->mechs[i].mech = token.rsa_mechs[i].mech;
|
||||
o->mechs[i].result_flags = 0;
|
||||
o->mechs[i].usage_flags =
|
||||
|
@ -131,7 +131,7 @@ add_supported_mechs(test_cert_t *o)
|
|||
} else if (o->type == EVP_PK_EC) {
|
||||
if (token.num_ec_mechs > 0 ) {
|
||||
o->num_mechs = token.num_ec_mechs;
|
||||
for (i = 0; i <= token.num_ec_mechs; i++) {
|
||||
for (i = 0; i < token.num_ec_mechs; i++) {
|
||||
o->mechs[i].mech = token.ec_mechs[i].mech;
|
||||
o->mechs[i].result_flags = 0;
|
||||
o->mechs[i].usage_flags =
|
||||
|
@ -144,6 +144,38 @@ add_supported_mechs(test_cert_t *o)
|
|||
o->mechs[0].result_flags = 0;
|
||||
o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY;
|
||||
}
|
||||
} else if (o->type == EVP_PKEY_ED25519) {
|
||||
if (token.num_ed_mechs > 0 ) {
|
||||
o->num_mechs = token.num_ed_mechs;
|
||||
for (i = 0; i < token.num_ed_mechs; i++) {
|
||||
o->mechs[i].mech = token.ed_mechs[i].mech;
|
||||
o->mechs[i].result_flags = 0;
|
||||
o->mechs[i].usage_flags =
|
||||
token.ed_mechs[i].usage_flags;
|
||||
}
|
||||
} else {
|
||||
/* Use the default list */
|
||||
o->num_mechs = 1;
|
||||
o->mechs[0].mech = CKM_EDDSA;
|
||||
o->mechs[0].result_flags = 0;
|
||||
o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY;
|
||||
}
|
||||
} else if (o->type == EVP_PKEY_X25519) {
|
||||
if (token.num_montgomery_mechs > 0 ) {
|
||||
o->num_mechs = token.num_montgomery_mechs;
|
||||
for (i = 0; i < token.num_ed_mechs; i++) {
|
||||
o->mechs[i].mech = token.montgomery_mechs[i].mech;
|
||||
o->mechs[i].result_flags = 0;
|
||||
o->mechs[i].usage_flags =
|
||||
token.montgomery_mechs[i].usage_flags;
|
||||
}
|
||||
} else {
|
||||
/* Use the default list */
|
||||
o->num_mechs = 1;
|
||||
o->mechs[0].mech = CKM_ECDH1_DERIVE;
|
||||
o->mechs[0].result_flags = 0;
|
||||
o->mechs[0].usage_flags = CKF_DERIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -399,8 +431,127 @@ int callback_public_keys(test_certs_t *objects,
|
|||
EC_KEY_set_group(o->key.ec, ecgroup);
|
||||
o->bits = EC_GROUP_get_degree(ecgroup);
|
||||
}
|
||||
} else if (o->key_type == CKK_EC_EDWARDS
|
||||
|| o->key_type == CKK_EC_MONTGOMERY) {
|
||||
EVP_PKEY *key = NULL;
|
||||
ASN1_PRINTABLESTRING *curve = NULL;
|
||||
ASN1_OBJECT *obj = NULL;
|
||||
const unsigned char *a;
|
||||
ASN1_OCTET_STRING *os;
|
||||
int evp_type;
|
||||
|
||||
a = template[6].pValue;
|
||||
if (d2i_ASN1_PRINTABLESTRING(&curve, &a, (long)template[6].ulValueLen) != NULL) {
|
||||
switch (o->key_type) {
|
||||
case CKK_EC_EDWARDS:
|
||||
if (strcmp((char *)curve->data, "edwards25519")) {
|
||||
debug_print(" [WARN %s ] Unknown curve name. "
|
||||
" expected edwards25519, got %s", o->id_str, curve->data);
|
||||
return -1;
|
||||
}
|
||||
evp_type = EVP_PKEY_ED25519;
|
||||
break;
|
||||
case CKK_EC_MONTGOMERY:
|
||||
if (strcmp((char *)curve->data, "curve25519")) {
|
||||
debug_print(" [WARN %s ] Unknown curve name. "
|
||||
" expected curve25519, got %s", o->id_str, curve->data);
|
||||
return -1;
|
||||
}
|
||||
evp_type = EVP_PKEY_X25519;
|
||||
break;
|
||||
default:
|
||||
debug_print(" [WARN %s ] Unknown key type %lu", o->id_str, o->key_type);
|
||||
return -1;
|
||||
}
|
||||
ASN1_PRINTABLESTRING_free(curve);
|
||||
} else if (d2i_ASN1_OBJECT(&obj, &a, (long)template[6].ulValueLen) != NULL) {
|
||||
int nid = OBJ_obj2nid(obj);
|
||||
switch (o->key_type) {
|
||||
case CKK_EC_EDWARDS:
|
||||
if (nid != NID_ED25519) {
|
||||
debug_print(" [WARN %s ] Unknown OID. "
|
||||
" expected NID_ED25519 (%d), got %d", o->id_str, NID_ED25519, nid);
|
||||
return -1;
|
||||
}
|
||||
evp_type = EVP_PKEY_ED25519;
|
||||
break;
|
||||
case CKK_EC_MONTGOMERY:
|
||||
if (nid != NID_X25519) {
|
||||
debug_print(" [WARN %s ] Unknown OID. "
|
||||
" expected NID_X25519 (%d), got %d", o->id_str, NID_X25519, nid);
|
||||
return -1;
|
||||
}
|
||||
evp_type = EVP_PKEY_X25519;
|
||||
break;
|
||||
default:
|
||||
debug_print(" [WARN %s ] Unknown key type %lu", o->id_str, o->key_type);
|
||||
return -1;
|
||||
}
|
||||
ASN1_OBJECT_free(obj);
|
||||
} else {
|
||||
debug_print(" [WARN %s ] Failed to convert EC_PARAMS"
|
||||
" to curve name or object id", o->id_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
|
||||
a = template[7].pValue;
|
||||
os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)template[7].ulValueLen);
|
||||
if (!os) {
|
||||
debug_print(" [WARN %s ] Can not decode EC_POINT", o->id_str);
|
||||
return -1;
|
||||
}
|
||||
if (os->length != 32) {
|
||||
debug_print(" [WARN %s ] Invalid length of EC_POINT value", o->id_str);
|
||||
return -1;
|
||||
}
|
||||
key = EVP_PKEY_new_raw_public_key(evp_type, NULL,
|
||||
(const uint8_t *)os->data,
|
||||
os->length);
|
||||
if (key == NULL) {
|
||||
debug_print(" [WARN %s ] Out of memory", o->id_str);
|
||||
ASN1_STRING_free(os);
|
||||
return -1;
|
||||
}
|
||||
if (o->key.pkey != NULL) {
|
||||
unsigned char *pub = NULL;
|
||||
size_t publen = 0;
|
||||
|
||||
/* TODO check EVP_PKEY type */
|
||||
|
||||
if (EVP_PKEY_get_raw_public_key(o->key.pkey, NULL, &publen) != 1) {
|
||||
debug_print(" [WARN %s ] Can not get size of the key", o->id_str);
|
||||
ASN1_STRING_free(os);
|
||||
return -1;
|
||||
}
|
||||
pub = malloc(publen);
|
||||
if (pub == NULL) {
|
||||
debug_print(" [WARN %s ] Out of memory", o->id_str);
|
||||
ASN1_STRING_free(os);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_get_raw_public_key(o->key.pkey, pub, &publen) != 1 ||
|
||||
publen != (size_t)os->length ||
|
||||
memcmp(pub, os->data, publen) != 0) {
|
||||
debug_print(" [WARN %s ] Got different public"
|
||||
"key then from the certificate",
|
||||
o->id_str);
|
||||
free(pub);
|
||||
ASN1_STRING_free(os);
|
||||
return -1;
|
||||
}
|
||||
free(pub);
|
||||
EVP_PKEY_free(key);
|
||||
o->verify_public = 1;
|
||||
} else { /* store the public key for future use */
|
||||
o->type = evp_type;
|
||||
o->key.pkey = key;
|
||||
o->bits = 255;
|
||||
}
|
||||
ASN1_STRING_free(os);
|
||||
} else {
|
||||
debug_print(" [WARN %s ] non-RSA, non-EC key. Key type: %02lX",
|
||||
debug_print(" [WARN %s ] unknown key. Key type: %02lX",
|
||||
o->id_str, o->key_type);
|
||||
return -1;
|
||||
}
|
||||
|
@ -577,10 +728,15 @@ void clean_all_objects(test_certs_t *objects) {
|
|||
free(objects->data[i].label);
|
||||
X509_free(objects->data[i].x509);
|
||||
if (objects->data[i].key_type == CKK_RSA &&
|
||||
objects->data[i].key.rsa != NULL)
|
||||
objects->data[i].key.rsa != NULL) {
|
||||
RSA_free(objects->data[i].key.rsa);
|
||||
else if (objects->data[i].key.ec != NULL)
|
||||
} else if (objects->data[i].key_type == CKK_EC &&
|
||||
objects->data[i].key.ec != NULL) {
|
||||
EC_KEY_free(objects->data[i].key.ec);
|
||||
} else if (objects->data[i].key_type == CKK_EC_EDWARDS &&
|
||||
objects->data[i].key.pkey != NULL) {
|
||||
EVP_PKEY_free(objects->data[i].key.pkey);
|
||||
}
|
||||
}
|
||||
free(objects->data);
|
||||
}
|
||||
|
@ -614,6 +770,10 @@ const char *get_mechanism_name(int mech_id)
|
|||
return "ECDSA_SHA384";
|
||||
case CKM_ECDSA_SHA512:
|
||||
return "ECDSA_SHA512";
|
||||
case CKM_EDDSA:
|
||||
return "EDDSA";
|
||||
case CKM_XEDDSA:
|
||||
return "XEDDSA";
|
||||
case CKM_ECDH1_DERIVE:
|
||||
return "ECDH1_DERIVE";
|
||||
case CKM_ECDH1_COFACTOR_DERIVE:
|
||||
|
@ -650,6 +810,10 @@ const char *get_mechanism_name(int mech_id)
|
|||
return "SHA512_HMAC";
|
||||
case CKM_RSA_PKCS_OAEP:
|
||||
return "RSA_PKCS_OAEP";
|
||||
case CKM_RIPEMD160:
|
||||
return "RIPEMD160";
|
||||
case CKM_GOSTR3411:
|
||||
return "GOSTR3411";
|
||||
case CKM_MD5:
|
||||
return "MD5";
|
||||
case CKM_SHA_1:
|
||||
|
@ -662,6 +826,14 @@ const char *get_mechanism_name(int mech_id)
|
|||
return "SHA384";
|
||||
case CKM_SHA512:
|
||||
return "SHA512";
|
||||
case CKM_SHA3_256:
|
||||
return "SHA3_256";
|
||||
case CKM_SHA3_224:
|
||||
return "SHA3_224";
|
||||
case CKM_SHA3_384:
|
||||
return "SHA3_384";
|
||||
case CKM_SHA3_512:
|
||||
return "SHA3_512";
|
||||
default:
|
||||
sprintf(name_buffer, "0x%.8X", mech_id);
|
||||
return name_buffer;
|
||||
|
|
|
@ -36,6 +36,7 @@ typedef struct {
|
|||
union {
|
||||
RSA *rsa;
|
||||
EC_KEY *ec;
|
||||
EVP_PKEY *pkey;
|
||||
} key;
|
||||
CK_OBJECT_HANDLE private_handle;
|
||||
CK_OBJECT_HANDLE public_handle;
|
||||
|
|
|
@ -20,15 +20,14 @@
|
|||
*/
|
||||
#include "p11test_case_ec_derive.h"
|
||||
|
||||
unsigned long pkcs11_derive(test_cert_t *o, token_info_t * info,
|
||||
EC_KEY *key, test_mech_t *mech, unsigned char **secret)
|
||||
size_t
|
||||
pkcs11_derive(test_cert_t *o, token_info_t * info,
|
||||
unsigned char *pub, size_t pub_len, test_mech_t *mech, unsigned char **secret)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_ECDH1_DERIVE_PARAMS params = {CKD_NULL, 0, NULL_PTR, 0, NULL_PTR};
|
||||
CK_MECHANISM mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
const EC_POINT *publickey = NULL;
|
||||
const EC_GROUP *group = NULL;
|
||||
CK_OBJECT_HANDLE newkey;
|
||||
CK_OBJECT_CLASS newkey_class = CKO_SECRET_KEY;
|
||||
CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET;
|
||||
|
@ -47,23 +46,6 @@ unsigned long pkcs11_derive(test_cert_t *o, token_info_t * info,
|
|||
};
|
||||
CK_ATTRIBUTE get_value = {CKA_VALUE, NULL_PTR, 0};
|
||||
CK_ULONG template_len = 9;
|
||||
unsigned char *pub = NULL;
|
||||
size_t pub_len;
|
||||
|
||||
/* Convert the public key to the octet string */
|
||||
group = EC_KEY_get0_group(key);
|
||||
publickey = EC_KEY_get0_public_key(key);
|
||||
pub_len = EC_POINT_point2oct(group, publickey,
|
||||
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
|
||||
if (pub_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
pub = malloc(pub_len);
|
||||
if (pub == NULL) {
|
||||
return 0;
|
||||
}
|
||||
pub_len = EC_POINT_point2oct(group, publickey,
|
||||
POINT_CONVERSION_UNCOMPRESSED, pub, pub_len, NULL);
|
||||
|
||||
params.pSharedData = NULL;
|
||||
params.ulSharedDataLen = 0;
|
||||
|
@ -75,7 +57,6 @@ unsigned long pkcs11_derive(test_cert_t *o, token_info_t * info,
|
|||
|
||||
rv = fp->C_DeriveKey(info->session_handle, &mechanism, o->private_handle,
|
||||
template, template_len, &newkey);
|
||||
free(pub);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_DeriveKey: rv = 0x%.8lX\n", rv);
|
||||
return 0;
|
||||
|
@ -106,12 +87,138 @@ unsigned long pkcs11_derive(test_cert_t *o, token_info_t * info,
|
|||
return get_value.ulValueLen;
|
||||
}
|
||||
|
||||
int test_derive_x25519(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
||||
{
|
||||
unsigned char *secret = NULL, *pkcs11_secret = NULL;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL; /* This is peer key */
|
||||
unsigned char *pub = NULL;
|
||||
size_t pub_len = 0, secret_len = 32, pkcs11_secret_len = 0;
|
||||
int rc;
|
||||
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key", o->id_str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (o->type != EVP_PKEY_X25519) {
|
||||
debug_print(" [ KEY %s ] Skip non-EC key for derive", o->id_str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* First, we need to generate our key */
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
if (pctx == NULL) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_CTX_new_id failed", o->id_str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen_init(pctx);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_keygen_init failed", o->id_str);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_keygen failed", o->id_str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Just here we start with key derivation in OpenSSL */
|
||||
pctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
if (pctx == NULL) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_CTX_new failed", o->id_str);
|
||||
EVP_PKEY_free(pkey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_init(pctx);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_derive_init failed", o->id_str);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_set_peer(pctx, o->key.pkey);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_derive_set_peer failed", o->id_str);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allocate the memory for the shared secret */
|
||||
if ((secret = malloc(secret_len)) == NULL) {
|
||||
debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive(pctx, secret, &secret_len);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_derive failed", o->id_str);
|
||||
EVP_PKEY_free(pkey);
|
||||
free(secret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try to do the same with the card key */
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey, pub, &pub_len);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_get_raw_public_key failed", o->id_str);
|
||||
EVP_PKEY_free(pkey);
|
||||
free(secret);
|
||||
return 1;
|
||||
}
|
||||
pub = malloc(pub_len);
|
||||
if (pub == NULL) {
|
||||
debug_print(" [ KEY %s ] failed to allocate memory", o->id_str);
|
||||
EVP_PKEY_free(pkey);
|
||||
free(secret);
|
||||
return 1;
|
||||
}
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey, pub, &pub_len);
|
||||
if (rc != 1) {
|
||||
debug_print(" [ KEY %s ] EVP_PKEY_get_raw_public_key failed", o->id_str);
|
||||
EVP_PKEY_free(pkey);
|
||||
free(secret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pkcs11_secret_len = pkcs11_derive(o, info, pub, pub_len, mech, &pkcs11_secret);
|
||||
|
||||
if (secret_len == pkcs11_secret_len && memcmp(secret, pkcs11_secret, secret_len) == 0) {
|
||||
mech->result_flags |= FLAGS_DERIVE;
|
||||
debug_print(" [ OK %s ] Derived secrets match", o->id_str);
|
||||
EVP_PKEY_free(pkey);
|
||||
free(secret);
|
||||
free(pkcs11_secret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug_print(" [ KEY %s ] Derived secret does not match", o->id_str);
|
||||
free(pub);
|
||||
EVP_PKEY_free(pkey);
|
||||
free(secret);
|
||||
free(pkcs11_secret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_derive(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
||||
{
|
||||
int nid, field_size, secret_len, pkcs11_secret_len;
|
||||
int nid, field_size;
|
||||
EC_KEY *key = NULL;
|
||||
const EC_POINT *publickey = NULL;
|
||||
const EC_GROUP *group = NULL;
|
||||
unsigned char *secret = NULL, *pkcs11_secret = NULL;
|
||||
unsigned char *pub = NULL;
|
||||
size_t pub_len = 0, secret_len = 0, pkcs11_secret_len = 0;
|
||||
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key", o->id_str);
|
||||
|
@ -124,7 +231,7 @@ int test_derive(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
|||
}
|
||||
|
||||
debug_print(" [ KEY %s ] Trying EC derive using CKM_%s and %lu-bit key",
|
||||
o->id_str, get_mechanism_name(mech->mech), o->bits);
|
||||
o->id_str, get_mechanism_name(mech->mech), o->bits);
|
||||
if (o->bits == 256)
|
||||
nid = NID_X9_62_prime256v1;
|
||||
else if (o->bits == 384)
|
||||
|
@ -150,7 +257,7 @@ int test_derive(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
|||
|
||||
/* Allocate the memory for the shared secret */
|
||||
if ((secret = OPENSSL_malloc(secret_len)) == NULL) {
|
||||
debug_print(" [ KEY %s ] Failed to generate peer private key", o->id_str);
|
||||
debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
|
||||
EC_KEY_free(key);
|
||||
return 1;
|
||||
}
|
||||
|
@ -160,7 +267,37 @@ int test_derive(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
|||
EC_KEY_get0_public_key(o->key.ec), key, NULL);
|
||||
|
||||
/* Try to do the same with the card key */
|
||||
pkcs11_secret_len = pkcs11_derive(o, info, key, mech, &pkcs11_secret);
|
||||
|
||||
/* Convert the public key to the octet string */
|
||||
group = EC_KEY_get0_group(key);
|
||||
publickey = EC_KEY_get0_public_key(key);
|
||||
pub_len = EC_POINT_point2oct(group, publickey,
|
||||
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
|
||||
if (pub_len == 0) {
|
||||
debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
|
||||
EC_KEY_free(key);
|
||||
OPENSSL_free(secret);
|
||||
return 1;
|
||||
}
|
||||
pub = malloc(pub_len);
|
||||
if (pub == NULL) {
|
||||
debug_print(" [ OK %s ] Failed to allocate memory", o->id_str);
|
||||
EC_KEY_free(key);
|
||||
OPENSSL_free(secret);
|
||||
return 1;
|
||||
}
|
||||
pub_len = EC_POINT_point2oct(group, publickey,
|
||||
POINT_CONVERSION_UNCOMPRESSED, pub, pub_len, NULL);
|
||||
if (pub_len == 0) {
|
||||
debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
|
||||
EC_KEY_free(key);
|
||||
OPENSSL_free(secret);
|
||||
free(pub);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pkcs11_secret_len = pkcs11_derive(o, info, pub, pub_len, mech, &pkcs11_secret);
|
||||
free(pub);
|
||||
|
||||
if (secret_len == pkcs11_secret_len && memcmp(secret, pkcs11_secret, secret_len) == 0) {
|
||||
mech->result_flags |= FLAGS_DERIVE;
|
||||
|
@ -197,16 +334,24 @@ void derive_tests(void **state) {
|
|||
if (objects.data[i].private_handle == CK_INVALID_HANDLE)
|
||||
continue;
|
||||
|
||||
/* Skip the non EC keys */
|
||||
if (objects.data[i].key_type != CKK_EC)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < o->num_mechs; j++) {
|
||||
if ((o->mechs[j].usage_flags & CKF_DERIVE) == 0
|
||||
|| ! o->derive_priv)
|
||||
continue;
|
||||
errors += test_derive(&(objects.data[i]), info,
|
||||
&(o->mechs[j]));
|
||||
|
||||
switch (o->key_type) {
|
||||
case CKK_EC:
|
||||
errors += test_derive(&(objects.data[i]), info,
|
||||
&(o->mechs[j]));
|
||||
break;
|
||||
case CKK_EC_MONTGOMERY:
|
||||
errors += test_derive_x25519(&(objects.data[i]), info,
|
||||
&(o->mechs[j]));
|
||||
break;
|
||||
default:
|
||||
/* Other keys do not support derivation */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,14 +363,17 @@ void derive_tests(void **state) {
|
|||
's', "MECHANISM",
|
||||
's', "DERIVE WORKS");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
if (objects.data[i].key_type != CKK_EC)
|
||||
if (objects.data[i].key_type != CKK_EC &&
|
||||
objects.data[i].key_type != CKK_EC_MONTGOMERY)
|
||||
continue;
|
||||
|
||||
test_cert_t *o = &objects.data[i];
|
||||
printf("\n[%-6s] [%s]\n",
|
||||
o->id_str,
|
||||
o->label);
|
||||
printf("[ EC ] [%6lu] [ %s ] [ %s%s ]\n",
|
||||
printf("[ %s ] [%6lu] [ %s ] [ %s%s ]\n",
|
||||
(o->key_type == CKK_EC ? " EC " :
|
||||
o->key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
|
||||
o->bits,
|
||||
o->verify_public == 1 ? " ./ " : " ",
|
||||
o->derive_pub ? "[./]" : "[ ]",
|
||||
|
|
|
@ -102,6 +102,27 @@ void supported_mechanisms_test(void **state) {
|
|||
P11TEST_FAIL(info, "Too many EC mechanisms (%d)", MAX_MECHS);
|
||||
}
|
||||
|
||||
/* We list all known edwards EC curve mechanisms */
|
||||
if (mechanism_list[i] == CKM_EDDSA) {
|
||||
if (token.num_ed_mechs < MAX_MECHS) {
|
||||
mech = &token.ed_mechs[token.num_ed_mechs++];
|
||||
mech->mech = mechanism_list[i];
|
||||
mech->usage_flags = mechanism_info[i].flags;
|
||||
} else
|
||||
P11TEST_FAIL(info, "Too many edwards EC mechanisms (%d)", MAX_MECHS);
|
||||
}
|
||||
|
||||
/* We list all known montgomery EC curve mechanisms */
|
||||
if (mechanism_list[i] == CKM_XEDDSA
|
||||
|| mechanism_list[i] == CKM_ECDH1_DERIVE) {
|
||||
if (token.num_montgomery_mechs < MAX_MECHS) {
|
||||
mech = &token.montgomery_mechs[token.num_montgomery_mechs++];
|
||||
mech->mech = mechanism_list[i];
|
||||
mech->usage_flags = mechanism_info[i].flags;
|
||||
} else
|
||||
P11TEST_FAIL(info, "Too many montgomery EC mechanisms (%d)", MAX_MECHS);
|
||||
}
|
||||
|
||||
if ((mechanism_info[i].flags & CKF_GENERATE_KEY_PAIR) != 0) {
|
||||
if (token.num_keygen_mechs < MAX_MECHS) {
|
||||
mech = &token.keygen_mechs[token.num_keygen_mechs++];
|
||||
|
|
|
@ -77,8 +77,10 @@ void multipart_tests(void **state) {
|
|||
continue;
|
||||
printf("[%-6s] [%s] [%6lu] [ %s ] [%s%s] [%s]\n",
|
||||
objects.data[i].id_str,
|
||||
objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " : " ?? ",
|
||||
(objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " :
|
||||
objects.data[i].key_type == CKK_EC_EDWARDS ? "EC_E" :
|
||||
objects.data[i].key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
|
||||
objects.data[i].bits,
|
||||
objects.data[i].verify_public == 1 ? " ./ " : " ",
|
||||
objects.data[i].sign ? "[./] " : "[ ] ",
|
||||
|
|
|
@ -458,8 +458,34 @@ int verify_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
|||
rv, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
} else if (o->type == EVP_PKEY_ED25519) {
|
||||
/* need to be created even though we do not do any MD */
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
|
||||
rv = EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, o->key.pkey);
|
||||
if (rv != 1) {
|
||||
fprintf(stderr, " [FAIL %s ] EVP_DigestVerifyInit: rv = %lu: %s\n", o->id_str,
|
||||
rv, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = EVP_DigestVerify(ctx, sign, sign_length, message, message_length);
|
||||
if (rv == 1) {
|
||||
debug_print(" [ OK %s ] EdDSA Signature of length %lu is valid.",
|
||||
o->id_str, message_length);
|
||||
mech->result_flags |= FLAGS_SIGN_OPENSSL;
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, " [FAIL %s ] EVP_DigestVerifyInit: rv = %lu: %s\n", o->id_str,
|
||||
rv, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
fprintf(stderr, " [ KEY %s ] Unknown type. Not verifying", o->id_str);
|
||||
fprintf(stderr, " [ KEY %s ] Unknown type. Not verifying\n", o->id_str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -557,7 +583,7 @@ int sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (o->type != EVP_PK_EC && o->type != EVP_PK_RSA) {
|
||||
if (o->type != EVP_PK_EC && o->type != EVP_PK_RSA && o->type != EVP_PKEY_ED25519) {
|
||||
debug_print(" [SKIP %s ] Skip non-RSA and non-EC key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -656,8 +682,10 @@ void readonly_tests(void **state) {
|
|||
o->id_str,
|
||||
o->label);
|
||||
printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s]\n",
|
||||
o->key_type == CKK_RSA ? "RSA " :
|
||||
o->key_type == CKK_EC ? " EC " : " ?? ",
|
||||
(o->key_type == CKK_RSA ? "RSA " :
|
||||
o->key_type == CKK_EC ? " EC " :
|
||||
o->key_type == CKK_EC_EDWARDS ? "EC_E" :
|
||||
o->key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
|
||||
o->bits,
|
||||
o->verify_public == 1 ? " ./ " : " ",
|
||||
o->sign ? "[./] " : "[ ] ",
|
||||
|
|
|
@ -54,9 +54,9 @@ void usage_test(void **state) {
|
|||
fprintf(stderr, " [ ERROR %s ] If Unwrap is set, Wrap should be set too.\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
if (objects.data[i].derive_pub != objects.data[i].derive_priv) {
|
||||
if (objects.data[i].derive_pub) {
|
||||
errors++;
|
||||
fprintf(stderr, " [ ERROR %s ] Derive should be set on both private and public part.\n",
|
||||
fprintf(stderr, " [ ERROR %s ] Derive should not be set on public key\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
|
||||
|
@ -99,8 +99,10 @@ void usage_test(void **state) {
|
|||
continue;
|
||||
|
||||
printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s] [ %s ]\n",
|
||||
objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " : " ?? ",
|
||||
(objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " :
|
||||
objects.data[i].key_type == CKK_EC_EDWARDS ? "EC_E" :
|
||||
objects.data[i].key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
|
||||
objects.data[i].bits,
|
||||
objects.data[i].verify_public == 1 ? " ./ " : " ",
|
||||
objects.data[i].sign ? "[./] " : "[ ] ",
|
||||
|
@ -115,8 +117,10 @@ void usage_test(void **state) {
|
|||
P11TEST_DATA_ROW(info, 14,
|
||||
's', objects.data[i].id_str,
|
||||
's', objects.data[i].label,
|
||||
's', objects.data[i].key_type == CKK_RSA ? "RSA" :
|
||||
objects.data[i].key_type == CKK_EC ? "EC" : "??",
|
||||
's', (objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " :
|
||||
objects.data[i].key_type == CKK_EC_EDWARDS ? "EC_E" :
|
||||
objects.data[i].key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
|
||||
'd', objects.data[i].bits,
|
||||
's', objects.data[i].verify_public == 1 ? "YES" : "",
|
||||
's', objects.data[i].sign ? "YES" : "",
|
||||
|
|
|
@ -80,6 +80,10 @@ typedef struct {
|
|||
size_t num_rsa_mechs;
|
||||
test_mech_t ec_mechs[MAX_MECHS];
|
||||
size_t num_ec_mechs;
|
||||
test_mech_t ed_mechs[MAX_MECHS];
|
||||
size_t num_ed_mechs;
|
||||
test_mech_t montgomery_mechs[MAX_MECHS];
|
||||
size_t num_montgomery_mechs;
|
||||
test_mech_t keygen_mechs[MAX_MECHS];
|
||||
size_t num_keygen_mechs;
|
||||
} token_info_t;
|
||||
|
|
|
@ -29,6 +29,7 @@ function generate_cert() {
|
|||
TYPE="$1"
|
||||
ID="$2"
|
||||
LABEL="$3"
|
||||
CERT="$4" # whether to generate certificate too
|
||||
|
||||
# Generate key pair
|
||||
$PKCS11_TOOL --keypairgen --key-type="$TYPE" --login --pin=$PIN \
|
||||
|
@ -39,104 +40,116 @@ function generate_cert() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
# check type value for the PKCS#11 URI (RHEL7 is using old "object-type")
|
||||
TYPE_KEY="type"
|
||||
p11tool --list-all --provider="$P11LIB" --login | grep "object-type" && \
|
||||
TYPE_KEY="object-type"
|
||||
# We can not do this with EdDSA keys as they are not supported in certtool
|
||||
# We can not do this with curve25519 keys as they do not need to support signatures at all
|
||||
if [[ "$CERT" -ne 0 ]]; then
|
||||
# check type value for the PKCS#11 URI (RHEL7 is using old "object-type")
|
||||
TYPE_KEY="type"
|
||||
p11tool --list-all --provider="$P11LIB" --login | grep "object-type" && \
|
||||
TYPE_KEY="object-type"
|
||||
|
||||
# Generate certificate
|
||||
certtool --generate-self-signed --outfile="$TYPE.cert" --template=cert.cfg \
|
||||
--provider="$P11LIB" --load-privkey "pkcs11:object=$LABEL;$TYPE_KEY=private" \
|
||||
--load-pubkey "pkcs11:object=$LABEL;$TYPE_KEY=public"
|
||||
# convert to DER:
|
||||
openssl x509 -inform PEM -outform DER -in "$TYPE.cert" -out "$TYPE.cert.der"
|
||||
# Write certificate
|
||||
#p11tool --login --write --load-certificate="$TYPE.cert" --label="$LABEL" \
|
||||
# --provider="$P11LIB"
|
||||
$PKCS11_TOOL --write-object "$TYPE.cert.der" --type=cert --id=$ID \
|
||||
--label="$LABEL" --module="$P11LIB"
|
||||
# Generate certificate
|
||||
certtool --generate-self-signed --outfile="$TYPE.cert" --template=cert.cfg \
|
||||
--provider="$P11LIB" --load-privkey "pkcs11:object=$LABEL;$TYPE_KEY=private" \
|
||||
--load-pubkey "pkcs11:object=$LABEL;$TYPE_KEY=public"
|
||||
# convert to DER:
|
||||
openssl x509 -inform PEM -outform DER -in "$TYPE.cert" -out "$TYPE.cert.der"
|
||||
# Write certificate
|
||||
#p11tool --login --write --load-certificate="$TYPE.cert" --label="$LABEL" \
|
||||
# --provider="$P11LIB"
|
||||
$PKCS11_TOOL --write-object "$TYPE.cert.der" --type=cert --id=$ID \
|
||||
--label="$LABEL" --module="$P11LIB"
|
||||
|
||||
rm "$TYPE.cert" "$TYPE.cert.der"
|
||||
rm "$TYPE.cert" "$TYPE.cert.der"
|
||||
fi
|
||||
|
||||
p11tool --login --provider="$P11LIB" --list-all
|
||||
}
|
||||
|
||||
function card_setup() {
|
||||
ECC_KEYS=1
|
||||
case $1 in
|
||||
"softhsm")
|
||||
P11LIB="/usr/lib64/pkcs11/libsofthsm2.so"
|
||||
echo "directories.tokendir = .tokens/" > .softhsm2.conf
|
||||
mkdir ".tokens"
|
||||
export SOFTHSM2_CONF=".softhsm2.conf"
|
||||
# Init token
|
||||
softhsm2-util --init-token --slot 0 --label "SC test" --so-pin="$SOPIN" --pin="$PIN"
|
||||
;;
|
||||
"opencryptoki")
|
||||
# Supports only RSA mechanisms
|
||||
ECC_KEYS=0
|
||||
P11LIB="/usr/lib64/pkcs11/libopencryptoki.so"
|
||||
SO_PIN=87654321
|
||||
SLOT_ID=3 # swtok slot
|
||||
systemctl is-active pkcsslotd > /dev/null
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Opencryptoki needs pkcsslotd running"
|
||||
exit 1
|
||||
fi
|
||||
groups | grep pkcs11 > /dev/null
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Opencryptoki requires the user to be in pkcs11 group"
|
||||
exit 1
|
||||
fi
|
||||
echo "test_swtok" | /usr/sbin/pkcsconf -I -c $SLOT_ID -S $SO_PIN
|
||||
/usr/sbin/pkcsconf -u -c $SLOT_ID -S $SO_PIN -n $PIN
|
||||
;;
|
||||
"readonly")
|
||||
GENERATE_KEYS=0
|
||||
if [[ ! -z "$2" && -f "$2" ]]; then
|
||||
P11LIB="$2"
|
||||
else
|
||||
P11LIB="/usr/lib64/pkcs11/opensc-pkcs11.so"
|
||||
P11LIB="../pkcs11/.libs/opensc-pkcs11.so"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Error: Missing argument."
|
||||
echo " Usage:"
|
||||
echo " runtest.sh [softhsm|opencryptoki|readonly [pkcs-library.so]]"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $GENERATE_KEYS -eq 1 ]]; then
|
||||
# Generate 1024b RSA Key pair
|
||||
generate_cert "RSA:1024" "01" "RSA_auth"
|
||||
# Generate 2048b RSA Key pair
|
||||
generate_cert "RSA:2048" "02" "RSA2048"
|
||||
if [[ $ECC_KEYS -eq 1 ]]; then
|
||||
# Generate 256b ECC Key pair
|
||||
generate_cert "EC:secp256r1" "03" "ECC_auth"
|
||||
# Generate 521b ECC Key pair
|
||||
generate_cert "EC:secp521r1" "04" "ECC521"
|
||||
ECC_KEYS=1
|
||||
EDDSA=1
|
||||
case $1 in
|
||||
"softhsm")
|
||||
P11LIB="/usr/lib64/pkcs11/libsofthsm2.so"
|
||||
echo "directories.tokendir = .tokens/" > .softhsm2.conf
|
||||
mkdir ".tokens"
|
||||
export SOFTHSM2_CONF=".softhsm2.conf"
|
||||
# Init token
|
||||
softhsm2-util --init-token --slot 0 --label "SC test" --so-pin="$SOPIN" --pin="$PIN"
|
||||
;;
|
||||
"opencryptoki")
|
||||
# Supports only RSA mechanisms
|
||||
ECC_KEYS=0
|
||||
EDDSA=0
|
||||
P11LIB="/usr/lib64/pkcs11/libopencryptoki.so"
|
||||
SO_PIN=87654321
|
||||
SLOT_ID=3 # swtok slot
|
||||
systemctl is-active pkcsslotd > /dev/null
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Opencryptoki needs pkcsslotd running"
|
||||
exit 1
|
||||
fi
|
||||
groups | grep pkcs11 > /dev/null
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Opencryptoki requires the user to be in pkcs11 group"
|
||||
exit 1
|
||||
fi
|
||||
echo "test_swtok" | /usr/sbin/pkcsconf -I -c $SLOT_ID -S $SO_PIN
|
||||
/usr/sbin/pkcsconf -u -c $SLOT_ID -S $SO_PIN -n $PIN
|
||||
;;
|
||||
"readonly")
|
||||
GENERATE_KEYS=0
|
||||
if [[ ! -z "$2" && -f "$2" ]]; then
|
||||
P11LIB="$2"
|
||||
else
|
||||
P11LIB="/usr/lib64/pkcs11/opensc-pkcs11.so"
|
||||
P11LIB="../pkcs11/.libs/opensc-pkcs11.so"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Error: Missing argument."
|
||||
echo " Usage:"
|
||||
echo " runtest.sh [softhsm|opencryptoki|readonly [pkcs-library.so]]"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $GENERATE_KEYS -eq 1 ]]; then
|
||||
# Generate 1024b RSA Key pair
|
||||
generate_cert "RSA:1024" "01" "RSA_auth" 1
|
||||
# Generate 2048b RSA Key pair
|
||||
generate_cert "RSA:2048" "02" "RSA2048" 1
|
||||
if [[ $ECC_KEYS -eq 1 ]]; then
|
||||
# Generate 256b ECC Key pair
|
||||
generate_cert "EC:secp256r1" "03" "ECC_auth" 1
|
||||
# Generate 521b ECC Key pair
|
||||
generate_cert "EC:secp521r1" "04" "ECC521" 1
|
||||
fi
|
||||
if [[ $EDDSA -eq 1 ]]; then
|
||||
# Generate Ed25519
|
||||
generate_cert "EC:edwards25519" "05" "EDDSA" 0
|
||||
# Generate curve25519
|
||||
#generate_cert "EC:curve25519" "06" "Curve25519" 0
|
||||
# not supported by softhsm either
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function card_cleanup() {
|
||||
case $1 in
|
||||
"softhsm")
|
||||
rm .softhsm2.conf
|
||||
rm -rf ".tokens"
|
||||
;;
|
||||
esac
|
||||
case $1 in
|
||||
"softhsm")
|
||||
rm .softhsm2.conf
|
||||
rm -rf ".tokens"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
card_setup "$@"
|
||||
|
||||
make p11test || exit
|
||||
if [[ "$PKCS11SPY" -ne "" ]]; then
|
||||
if [[ "$PKCS11SPY" != "" ]]; then
|
||||
export PKCS11SPY="$P11LIB"
|
||||
$VALGRIND ./p11test -m /usr/lib64/pkcs11/pkcs11-spy.so -p $PIN
|
||||
$VALGRIND ./p11test -m ../../pkcs11/.libs/pkcs11-spy.so -p $PIN &> /tmp/spy.log
|
||||
else
|
||||
#bash
|
||||
$VALGRIND ./p11test -m "$P11LIB" -o test.json -p $PIN
|
||||
|
|
|
@ -558,6 +558,41 @@ static void torture_asn1_put_tag_without_data(void **state)
|
|||
assert_ptr_equal(p, out + sizeof(expected));
|
||||
}
|
||||
|
||||
static void torture_asn1_encode_simple(void **state)
|
||||
{
|
||||
sc_context_t *ctx = *state;
|
||||
struct sc_asn1_entry asn1[] = {
|
||||
{ "OctetString", SC_ASN1_OCTET_STRING, 0x05, SC_ASN1_PRESENT, NULL, NULL },
|
||||
{ NULL , 0 , 0 , 0 , NULL , NULL }
|
||||
};
|
||||
u8 expected[] = {0x05, 0x09, 't', 'e', 's', 't', ' ', 'd', 'a', 't', 'a'};
|
||||
char *data = "test data";
|
||||
size_t datalen = strlen(data);
|
||||
u8 *outptr = NULL;
|
||||
size_t outlen = 0;
|
||||
int rv;
|
||||
|
||||
/* NULL arguments should not crash */
|
||||
rv = sc_asn1_encode(NULL, NULL, NULL, NULL);
|
||||
assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
/* NULL asn1 entry should not crash */
|
||||
rv = sc_asn1_encode(ctx, NULL, NULL, NULL);
|
||||
assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
/* Real example of encoding an octet string */
|
||||
asn1[0].parm = data;
|
||||
asn1[0].arg = &datalen;
|
||||
rv = sc_asn1_encode(ctx, asn1, &outptr, &outlen);
|
||||
assert_int_equal(rv, SC_SUCCESS);
|
||||
assert_int_equal(outlen, sizeof(expected));
|
||||
assert_memory_equal(expected, outptr, sizeof(expected));
|
||||
|
||||
/* Context is not needed */
|
||||
rv = sc_asn1_encode(NULL, asn1, &outptr, &outlen);
|
||||
assert_int_equal(rv, SC_SUCCESS);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc;
|
||||
|
@ -625,6 +660,9 @@ int main(void)
|
|||
cmocka_unit_test(torture_asn1_put_tag_without_data),
|
||||
cmocka_unit_test(torture_asn1_put_tag_long_tag),
|
||||
cmocka_unit_test(torture_asn1_put_tag_long_data),
|
||||
/* encode() */
|
||||
cmocka_unit_test_setup_teardown(torture_asn1_encode_simple,
|
||||
setup_sc_context, teardown_sc_context),
|
||||
};
|
||||
|
||||
rc = cmocka_run_group_tests(tests, NULL, NULL);
|
||||
|
|
|
@ -177,7 +177,7 @@ static const struct ef_name_map key_data[] = {
|
|||
};
|
||||
|
||||
static const struct ef_name_map user_data[] = {
|
||||
{ "Account", "OPENGPG_ACCOUNT", "3F00:005E", TYPE_STRING, 0, 0, NULL },
|
||||
{ "Account", "OPENPGP_ACCOUNT", "3F00:005E", TYPE_STRING, 0, 0, NULL },
|
||||
{ "URL", "OPENPGP_URL", "3F00:5F50", TYPE_STRING, 0, 0, NULL },
|
||||
{ "Name", "OPENPGP_NAME", "3F00:0065:005B", TYPE_STRING, 0, 0, prettify_name },
|
||||
{ "Language", "OPENPGP_LANG", "3F00:0065:5F2D", TYPE_STRING, 0, 0, prettify_language },
|
||||
|
@ -847,7 +847,7 @@ int delete_key_openpgp(sc_card_t *card, u8 in_key_id)
|
|||
}
|
||||
}
|
||||
/* TODO: Rewrite Extended Header List.
|
||||
* Not support by OpenGPG v2 yet */
|
||||
* Not support by OpenPGP v2 yet */
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -557,6 +557,7 @@ static int list_algorithms(void)
|
|||
{ SC_ALGORITHM_RSA, "rsa" },
|
||||
{ SC_ALGORITHM_DSA, "dsa" },
|
||||
{ SC_ALGORITHM_EC, "ec" },
|
||||
{ SC_ALGORITHM_EDDSA, "eddsa" },
|
||||
{ SC_ALGORITHM_GOSTR3410, "gostr3410" },
|
||||
{ SC_ALGORITHM_DES, "des" },
|
||||
{ SC_ALGORITHM_3DES, "3des" },
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "pkcs11/pkcs11.h"
|
||||
#include "pkcs11/pkcs11-opensc.h"
|
||||
#include "libopensc/asn1.h"
|
||||
#include "libopensc/log.h"
|
||||
#include "common/compat_strlcat.h"
|
||||
#include "common/compat_strlcpy.h"
|
||||
#include "common/libpkcs11.h"
|
||||
|
@ -85,41 +86,46 @@ extern CK_FUNCTION_LIST_3_0 pkcs11_function_list_3_0;
|
|||
static struct ec_curve_info {
|
||||
const char *name;
|
||||
const char *oid;
|
||||
const char *oid_encoded;
|
||||
const char *ec_params;
|
||||
size_t size;
|
||||
CK_KEY_TYPE mechanism;
|
||||
} ec_curve_infos[] = {
|
||||
{"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
|
||||
{"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
|
||||
{"prime192v2", "1.2.840.10045.3.1.2", "06082A8648CE3D030102", 192},
|
||||
{"prime192v3", "1.2.840.10045.3.1.3", "06082A8648CE3D030103", 192},
|
||||
{"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
|
||||
{"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
|
||||
{"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
|
||||
{"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
|
||||
{"prime192v2", "1.2.840.10045.3.1.2", "06082A8648CE3D030102", 192, 0},
|
||||
{"prime192v3", "1.2.840.10045.3.1.3", "06082A8648CE3D030103", 192, 0},
|
||||
{"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
|
||||
{"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, 0},
|
||||
|
||||
{"secp224r1", "1.3.132.0.33", "06052b81040021", 224},
|
||||
{"nistp224", "1.3.132.0.33", "06052b81040021", 224},
|
||||
{"secp224r1", "1.3.132.0.33", "06052b81040021", 224, 0},
|
||||
{"nistp224", "1.3.132.0.33", "06052b81040021", 224, 0},
|
||||
|
||||
{"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
|
||||
{"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
|
||||
{"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
|
||||
{"frp256v1", "1.2.250.1.223.101.256.1", "060a2a817a01815f65820001", 256},
|
||||
{"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, 0},
|
||||
{"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, 0},
|
||||
{"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, 0},
|
||||
{"frp256v1", "1.2.250.1.223.101.256.1", "060a2a817a01815f65820001", 256, 0},
|
||||
|
||||
{"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
|
||||
{"prime384v1", "1.3.132.0.34", "06052B81040022", 384},
|
||||
{"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384},
|
||||
{"secp384r1", "1.3.132.0.34", "06052B81040022", 384, 0},
|
||||
{"prime384v1", "1.3.132.0.34", "06052B81040022", 384, 0},
|
||||
{"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384, 0},
|
||||
|
||||
{"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
|
||||
{"nistp521", "1.3.132.0.35", "06052B81040023", 521},
|
||||
{"secp521r1", "1.3.132.0.35", "06052B81040023", 521, 0},
|
||||
{"nistp521", "1.3.132.0.35", "06052B81040023", 521, 0},
|
||||
|
||||
{"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192},
|
||||
{"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224},
|
||||
{"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256},
|
||||
{"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320},
|
||||
{"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384},
|
||||
{"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512},
|
||||
{"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192, 0},
|
||||
{"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224, 0},
|
||||
{"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256, 0},
|
||||
{"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320, 0},
|
||||
{"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384, 0},
|
||||
{"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512, 0},
|
||||
|
||||
{"secp192k1", "1.3.132.0.31", "06052B8104001F", 192},
|
||||
{"secp256k1", "1.3.132.0.10", "06052B8104000A", 256},
|
||||
{NULL, NULL, NULL, 0},
|
||||
{"secp192k1", "1.3.132.0.31", "06052B8104001F", 192, 0},
|
||||
{"secp256k1", "1.3.132.0.10", "06052B8104000A", 256, 0},
|
||||
|
||||
{"edwards25519","1.3.6.1.4.1159.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN},
|
||||
{"curve25519", "1.3.6.1.4.3029.1.5.1", "130b63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN},
|
||||
|
||||
{NULL, NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
static const struct sc_aid GOST_HASH2001_PARAMSET_OID = { { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 }, 9 };
|
||||
|
@ -291,7 +297,7 @@ static const char *option_help[] = {
|
|||
"Unlock User PIN (without '--login' unlock in logged in session; otherwise '--login-type' has to be 'context-specific')",
|
||||
"Key pair generation",
|
||||
"Key generation",
|
||||
"Specify the type and length (bytes if symmetric) of the key to create, for example rsa:1024, EC:prime256v1, GOSTR3410-2012-256:B, AES:16 or GENERIC:64",
|
||||
"Specify the type and length (bytes if symmetric) of the key to create, for example rsa:1024, EC:prime256v1, EC:ed25519, EC:curve25519, GOSTR3410-2012-256:B, AES:16 or GENERIC:64",
|
||||
"Specify 'sign' key usage flag (sets SIGN in privkey, sets VERIFY in pubkey)",
|
||||
"Specify 'decrypt' key usage flag (RSA only, set DECRYPT privkey, ENCRYPT in pubkey)",
|
||||
"Specify 'derive' key usage flag (EC only)",
|
||||
|
@ -2461,6 +2467,7 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
|
|||
int n_privkey_attr = 4;
|
||||
unsigned char *ecparams = NULL;
|
||||
size_t ecparams_size;
|
||||
CK_ULONG key_type = CKK_RSA;
|
||||
CK_RV rv;
|
||||
|
||||
if (type != NULL) {
|
||||
|
@ -2505,15 +2512,17 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
|
|||
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_UNWRAP, &_true, sizeof(_true));
|
||||
n_privkey_attr++;
|
||||
}
|
||||
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
|
||||
n_pubkey_attr++;
|
||||
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
|
||||
n_privkey_attr++;
|
||||
}
|
||||
else if (strncmp(type, "EC:", strlen("EC:")) == 0 || strncmp(type, "ec:", strlen("ec:")) == 0) {
|
||||
CK_MECHANISM_TYPE mtypes[] = {CKM_EC_KEY_PAIR_GEN};
|
||||
size_t mtypes_num = sizeof(mtypes)/sizeof(mtypes[0]);
|
||||
int ii;
|
||||
|
||||
if (!opt_mechanism_used)
|
||||
if (!find_mechanism(slot, CKF_GENERATE_KEY_PAIR, mtypes, mtypes_num, &opt_mechanism))
|
||||
util_fatal("Generate EC key mechanism not supported\n");
|
||||
key_type = CKK_EC;
|
||||
|
||||
for (ii=0; ec_curve_infos[ii].name; ii++) {
|
||||
if (!strcmp(ec_curve_infos[ii].name, type + 3))
|
||||
|
@ -2524,12 +2533,38 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
|
|||
if (!ec_curve_infos[ii].name)
|
||||
util_fatal("Unknown EC key params '%s'", type + 3);
|
||||
|
||||
ecparams_size = strlen(ec_curve_infos[ii].oid_encoded) / 2;
|
||||
switch (ec_curve_infos[ii].mechanism) {
|
||||
case CKM_EC_EDWARDS_KEY_PAIR_GEN:
|
||||
/* The Edwards key can not be used for derivation */
|
||||
opt_key_usage_derive = 0;
|
||||
key_type = CKK_EC_EDWARDS;
|
||||
/* This replaces the above default mechanism */
|
||||
if (!opt_mechanism_used) {
|
||||
mtypes[0] = ec_curve_infos[ii].mechanism;
|
||||
}
|
||||
break;
|
||||
case CKM_EC_MONTGOMERY_KEY_PAIR_GEN:
|
||||
key_type = CKK_EC_MONTGOMERY;
|
||||
/* This replaces the above default mechanism */
|
||||
if (!opt_mechanism_used) {
|
||||
mtypes[0] = ec_curve_infos[ii].mechanism;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!opt_mechanism_used) {
|
||||
if (!find_mechanism(slot, CKF_GENERATE_KEY_PAIR, mtypes, mtypes_num,
|
||||
&opt_mechanism)) {
|
||||
util_fatal("Generate EC key mechanism %lx not supported", mtypes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
ecparams_size = strlen(ec_curve_infos[ii].ec_params) / 2;
|
||||
ecparams = malloc(ecparams_size);
|
||||
if (!ecparams)
|
||||
util_fatal("Allocation error", 0);
|
||||
if (!hex_to_bin(ec_curve_infos[ii].oid_encoded, ecparams, &ecparams_size)) {
|
||||
fprintf(stderr, "Cannot convert \"%s\"\n", ec_curve_infos[ii].oid_encoded);
|
||||
if (!hex_to_bin(ec_curve_infos[ii].ec_params, ecparams, &ecparams_size)) {
|
||||
fprintf(stderr, "Cannot convert \"%s\"\n", ec_curve_infos[ii].ec_params);
|
||||
util_print_usage_and_die(app_name, options, option_help, NULL);
|
||||
}
|
||||
|
||||
|
@ -2549,6 +2584,10 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
|
|||
|
||||
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_EC_PARAMS, ecparams, ecparams_size);
|
||||
n_pubkey_attr++;
|
||||
FILL_ATTR(publicKeyTemplate[n_pubkey_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
|
||||
n_pubkey_attr++;
|
||||
FILL_ATTR(privateKeyTemplate[n_privkey_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
|
||||
n_privkey_attr++;
|
||||
}
|
||||
else if (strncmp(type, "GOSTR3410", strlen("GOSTR3410")) == 0 || strncmp(type, "gostr3410", strlen("gostr3410")) == 0) {
|
||||
const struct sc_aid GOST2001_PARAMSET_A_OID = { { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }, 9 };
|
||||
|
@ -4135,6 +4174,58 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case CKK_EC_EDWARDS:
|
||||
case CKK_EC_MONTGOMERY:
|
||||
if (key_type == CKK_EC_EDWARDS) {
|
||||
printf("; EC_EDWARDS");
|
||||
} else {
|
||||
printf("; EC_MONTGOMERY");
|
||||
}
|
||||
if (pub) {
|
||||
unsigned char *bytes = NULL;
|
||||
int ksize;
|
||||
unsigned int n;
|
||||
|
||||
bytes = getEC_POINT(sess, obj, &size);
|
||||
ksize = 255; /* for now, we support only 255b curves */
|
||||
|
||||
printf(" EC_POINT %u bits\n", ksize);
|
||||
if (bytes) {
|
||||
if ((CK_LONG)size > 0) { /* Will print the point here */
|
||||
printf(" EC_POINT: ");
|
||||
for (n = 0; n < size; n++)
|
||||
printf("%02x", bytes[n]);
|
||||
printf("\n");
|
||||
}
|
||||
free(bytes);
|
||||
}
|
||||
bytes = NULL;
|
||||
bytes = getEC_PARAMS(sess, obj, &size);
|
||||
if (bytes){
|
||||
if ((CK_LONG)size > 0) {
|
||||
struct sc_object_id oid;
|
||||
|
||||
printf(" EC_PARAMS: ");
|
||||
for (n = 0; n < size; n++)
|
||||
printf("%02x", bytes[n]);
|
||||
|
||||
sc_init_oid(&oid);
|
||||
if (size > 2 && sc_asn1_decode_object_id(bytes + 2, size - 2, &oid) == SC_SUCCESS) {
|
||||
printf(" (OID %i", oid.value[0]);
|
||||
if (oid.value[0] >= 0)
|
||||
for (n = 1; (n < SC_MAX_OBJECT_ID_OCTETS)
|
||||
&& (oid.value[n] >= 0); n++)
|
||||
printf(".%i", oid.value[n]);
|
||||
printf(")");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
free(bytes);
|
||||
}
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
break;
|
||||
case CKK_EC:
|
||||
printf("; EC");
|
||||
|
@ -4180,7 +4271,7 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
|
|||
free(bytes);
|
||||
}
|
||||
} else
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
break;
|
||||
case CKK_GENERIC_SECRET:
|
||||
case CKK_AES:
|
||||
|
@ -4666,7 +4757,7 @@ static int read_object(CK_SESSION_HANDLE session)
|
|||
const unsigned char *a = params;
|
||||
if (!d2i_ECParameters(&ec, &a, (long)len))
|
||||
util_fatal("cannot parse EC_PARAMS");
|
||||
OPENSSL_free(params);
|
||||
free(params);
|
||||
} else
|
||||
util_fatal("cannot obtain EC_PARAMS");
|
||||
|
||||
|
@ -4689,6 +4780,65 @@ static int read_object(CK_SESSION_HANDLE session)
|
|||
if (!i2d_EC_PUBKEY_bio(pout, ec))
|
||||
util_fatal("cannot convert EC public key to DER");
|
||||
EC_KEY_free(ec);
|
||||
#endif
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
} else if (type == CKK_EC_EDWARDS) {
|
||||
EVP_PKEY *key = NULL;
|
||||
CK_BYTE *params = NULL;
|
||||
const unsigned char *a;
|
||||
ASN1_OCTET_STRING *os;
|
||||
|
||||
if ((params = getEC_PARAMS(session, obj, &len))) {
|
||||
ASN1_PRINTABLESTRING *curve = NULL;
|
||||
ASN1_OBJECT *obj = NULL;
|
||||
|
||||
a = params;
|
||||
if (d2i_ASN1_PRINTABLESTRING(&curve, &a, (long)len) != NULL) {
|
||||
if (strcmp((char *)curve->data, "edwards25519")) {
|
||||
util_fatal("Unknown curve name, expected edwards25519, got %s",
|
||||
curve->data);
|
||||
}
|
||||
ASN1_PRINTABLESTRING_free(curve);
|
||||
} else if (d2i_ASN1_OBJECT(&obj, &a, (long)len) != NULL) {
|
||||
int nid = OBJ_obj2nid(obj);
|
||||
if (nid != NID_ED25519) {
|
||||
util_fatal("Unknown curve OID, expected NID_ED25519 (%d), got %d",
|
||||
NID_ED25519, nid);
|
||||
}
|
||||
ASN1_OBJECT_free(obj);
|
||||
} else {
|
||||
util_fatal("cannot parse curve name from EC_PARAMS");
|
||||
}
|
||||
free(params);
|
||||
} else {
|
||||
util_fatal("cannot obtain EC_PARAMS");
|
||||
}
|
||||
|
||||
|
||||
value = getEC_POINT(session, obj, &len);
|
||||
/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
|
||||
a = value;
|
||||
os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len);
|
||||
if (!os) {
|
||||
util_fatal("cannot decode EC_POINT");
|
||||
}
|
||||
if (os->length != 32) {
|
||||
util_fatal("Invalid length of EC_POINT value");
|
||||
}
|
||||
key = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
|
||||
(const uint8_t *)os->data,
|
||||
os->length);
|
||||
ASN1_STRING_free(os);
|
||||
if (key == NULL) {
|
||||
util_fatal("out of memory");
|
||||
}
|
||||
/* Note, that we write PEM here as there is no "native"
|
||||
* representation of EdDSA public keys to use */
|
||||
if (!PEM_write_bio_PUBKEY(pout, key)) {
|
||||
util_fatal("cannot convert EdDSA public key to PEM");
|
||||
}
|
||||
|
||||
EVP_PKEY_free(key);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -6967,6 +7117,10 @@ static struct mech_info p11_mechanisms[] = {
|
|||
{ CKM_ECDH1_DERIVE, "ECDH1-DERIVE", NULL },
|
||||
{ CKM_ECDH1_COFACTOR_DERIVE,"ECDH1-COFACTOR-DERIVE", NULL },
|
||||
{ CKM_ECMQV_DERIVE, "ECMQV-DERIVE", NULL },
|
||||
{ CKM_EC_EDWARDS_KEY_PAIR_GEN,"EC-EDWARDS-KEY-PAIR-GEN", NULL },
|
||||
{ CKM_EC_MONTGOMERY_KEY_PAIR_GEN,"EC-MONTGOMERY-KEY-PAIR-GEN", NULL },
|
||||
{ CKM_EDDSA, "EDDSA", NULL },
|
||||
{ CKM_XEDDSA, "XEDDSA", NULL },
|
||||
{ CKM_JUNIPER_KEY_GEN, "JUNIPER-KEY-GEN", NULL },
|
||||
{ CKM_JUNIPER_ECB128, "JUNIPER-ECB128", NULL },
|
||||
{ CKM_JUNIPER_CBC128, "JUNIPER-CBC128", NULL },
|
||||
|
|
|
@ -221,7 +221,7 @@ struct _access_rule_text {
|
|||
{0, NULL},
|
||||
};
|
||||
|
||||
static const char *key_types[] = { "", "RSA", "DSA", "GOSTR3410", "EC", "", "", "" };
|
||||
static const char *key_types[] = { "", "RSA", "DSA", "GOSTR3410", "EC", "EDDSA", "XEDDSA", "" };
|
||||
|
||||
static void
|
||||
print_access_rules(const struct sc_pkcs15_accessrule *rules, int num)
|
||||
|
@ -739,7 +739,8 @@ static void print_pubkey_info(const struct sc_pkcs15_object *obj)
|
|||
else if (pubkey->field_length) {
|
||||
printf("\tFieldLength : %lu\n", (unsigned long)pubkey->field_length);
|
||||
}
|
||||
else if (obj->type == SC_PKCS15_TYPE_PUBKEY_EC && have_path) {
|
||||
else if ((obj->type == SC_PKCS15_TYPE_PUBKEY_EC || obj->type == SC_PKCS15_TYPE_PUBKEY_EDDSA)
|
||||
&& have_path) {
|
||||
sc_pkcs15_pubkey_t *pkey = NULL;
|
||||
if (!sc_pkcs15_read_pubkey(p15card, obj, &pkey)) {
|
||||
printf("\tFieldLength : %lu\n", (unsigned long)pkey->u.ec.params.field_length);
|
||||
|
@ -998,6 +999,39 @@ static int read_ssh_key(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (pubkey->algorithm == SC_ALGORITHM_EDDSA) {
|
||||
// SSH supports only ed25519 key now
|
||||
|
||||
char alg[20];
|
||||
/* Large enough to fit the following:
|
||||
* 2 x 4B item length headers
|
||||
* max 11B algorithm name, 32B key data */
|
||||
unsigned char buf[64];
|
||||
unsigned int len, n;
|
||||
|
||||
n = pubkey->u.eddsa.pubkey.len;
|
||||
if (n != 32) {
|
||||
fprintf(stderr, "Wrong public key length\n");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
len = snprintf((char *) buf+4, 20, "ssh-ed25519");
|
||||
memcpy(alg, buf+4, 20);
|
||||
buf[3] = len;
|
||||
len += 4;
|
||||
|
||||
buf[len++] = 0;
|
||||
buf[len++] = 0;
|
||||
buf[len++] = 0;
|
||||
buf[len++] = n & 0xff;
|
||||
memcpy(buf + len, pubkey->u.eddsa.pubkey.value, n);
|
||||
len += n;
|
||||
|
||||
print_ssh_key(outf, alg, obj, buf, len);
|
||||
}
|
||||
if (pubkey->algorithm == SC_ALGORITHM_EC) {
|
||||
// support only for NIST
|
||||
// 'ssh-keygen -t ecdsa' allow only field lengths 256/384/521
|
||||
|
|
|
@ -108,7 +108,7 @@ MD_REGISTRATION minidriver_registration[] = {
|
|||
{TEXT("OpenPGP card v2.x"), {0x3b,0xda,0x18,0xff,0x81,0xb1,0xfe,0x75,0x1f,0x03,0x00,0x31,0xc5,0x73,0xc0,0x01,0x40,0x00,0x90,0x00,0x0c},
|
||||
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
|
||||
{TEXT("Gnuk v1.0.x (OpenPGP v2.0)"), {0x3b,0xda,0x11,0xff,0x81,0xb1,0xfe,0x55,0x1f,0x03,0x00,0x31,0x84,0x73,0x80,0x01,0x80,0x00,0x90,0x00,0xe4},
|
||||
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff}},
|
||||
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0x00}},
|
||||
{TEXT("OpenPGP card v3.x"), {0x3b,0xda,0x18,0xff,0x81,0xb1,0xfe,0x75,0x1f,0x03,0x00,0x31,0xf5,0x73,0xc0,0x01,0x60,0x00,0x90,0x00,0x1c},
|
||||
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
|
||||
/* from card-masktech.c */
|
||||
|
|
Loading…
Reference in New Issue