Merge pull request #1960 from Jakuje/eddsa

Add support for (X)EdDSA keys in OpenPGP driver
This commit is contained in:
Frank Morgner 2021-03-22 15:36:59 +01:00 committed by GitHub
commit 5f9085fedb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1858 additions and 322 deletions

View File

@ -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) {

View File

@ -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)

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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 */

View File

@ -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. */

View File

@ -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 */

View File

@ -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

View File

@ -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,

View File

@ -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 }
};

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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)
{

View File

@ -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 *,

View File

@ -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)

View File

@ -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),

View File

@ -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)) {

View File

@ -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);

View File

@ -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 },

View File

@ -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)

View File

@ -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) {

View File

@ -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)

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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 ? "[./]" : "[ ]",

View File

@ -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++];

View File

@ -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 ? "[./] " : "[ ] ",

View File

@ -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 ? "[./] " : "[ ] ",

View File

@ -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" : "",

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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" },

View File

@ -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 },

View File

@ -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

View File

@ -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 */