diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index 4895a7d8..7e23dd57 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -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: @@ -568,6 +572,7 @@ static int 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; @@ -596,8 +601,9 @@ pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob, 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*/ @@ -623,16 +629,19 @@ pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob, 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)) { + 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 = ec_curves[j].oid; - key_info->u.ec.key_length = ec_curves[j].size; + 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: LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); @@ -790,22 +799,39 @@ pgp_get_card_features(sc_card_t *card) /* 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(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); - sc_log(card->ctx, "DO %zX: Added RSA algorithm, mod_len = %zu" , i, key_info.u.rsa.modulus_len); - } - /* 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)) { + _sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length, + (SC_ALGORITHM_XEDDSA_RAW | 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; @@ -816,8 +842,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); - sc_log(card->ctx, "DO %zX: Added EC algorithm (%d), mod_len = %d" , i, key_info.algorithm, key_info.u.ec.key_length); + &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; } } } @@ -1564,10 +1603,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; @@ -1581,14 +1616,51 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) ((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(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); - } else { - sc_log(card->ctx, "Unable to encode EC curve OID from algorithm info"); + 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 { sc_log(card->ctx, "Unable to find Algorithm Attribute for EC curve OID"); @@ -1598,16 +1670,19 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) } /* 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); @@ -1980,6 +2055,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, @@ -2022,6 +2098,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"); @@ -2146,20 +2225,67 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen, sc_apdu_t apdu; u8 apdu_case = SC_APDU_CASE_4; u8 *temp = NULL; - int r; + int r, extlen = 0; 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 */ + if (!(temp = malloc(inlen + 10))) 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; + extlen = 1; + break; + case SC_ALGORITHM_EC: + case SC_ALGORITHM_XEDDSA: + /* This is 0xA6 Cipher DO with associated length field */ + temp[extlen++] = 0xa6; + if (inlen >= 128) { + temp[extlen++] = 0x81; + temp[extlen++] = inlen + 7; + } else { + temp[extlen++] = inlen + 5; + } + /* Public Key DO (0x7F49) with associated length field */ + temp[extlen++] = 0x7f; + temp[extlen++] = 0x49; + if (inlen >= 128) { + temp[extlen++] = 0x81; + temp[extlen++] = inlen + 3; + } else { + temp[extlen++] = inlen + 2; + } + /* External Public Key (0x86) with associated length */ + temp[extlen++] = 0x86; + if (inlen >= 128) { + temp[extlen++] = 0x81; + } + temp[extlen++] = inlen; + break; + case SC_ALGORITHM_AES: + /* not supported yet */ + /* + temp[0] = 0x02; + extlen = 1; + */ + /* fall through */ + default: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + } + + memcpy(temp + extlen, in, inlen); + in = temp; + inlen += extlen; + + 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"); @@ -2239,7 +2365,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) @@ -2443,7 +2570,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; @@ -2737,6 +2865,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) diff --git a/src/libopensc/card-openpgp.h b/src/libopensc/card-openpgp.h index 00c2f90a..e76ab99c 100644 --- a/src/libopensc/card-openpgp.h +++ b/src/libopensc/card-openpgp.h @@ -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; }; diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c index e461f809..f97546e2 100644 --- a/src/libopensc/pkcs15-openpgp.c +++ b/src/libopensc/pkcs15-openpgp.c @@ -70,6 +70,7 @@ static const pgp_pin_cfg_t pin_cfg_v2[3] = { { "Admin PIN", 0x03, PGP_ADMIN_PIN_FLAGS, 8, 2 } }; +struct sc_object_id curve25519_binary_oid = {{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01, -1}}; #define PGP_SIG_PRKEY_USAGE (SC_PKCS15_PRKEY_USAGE_SIGN \ | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER \ @@ -269,6 +270,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card) 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; @@ -277,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 */ @@ -288,6 +290,9 @@ 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; + int k; + prkey_info.id.len = 1; prkey_info.id.value[0] = i + 1; prkey_info.usage = key_cfg[i].prkey_usage; @@ -299,13 +304,41 @@ 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); - } - if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH - || cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) { + switch (cxdata[0]) { + case SC_OPENPGP_KEYALGO_EDDSA: + /* TODO Store the OID from cxdata + 1 ?? */ + /* assuming Ed25519 as it is the only supported now */ + prkey_info.field_length = 255; + 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 */ + sc_init_oid(&oid); + /* Create copy of oid */ + for (k = 0; k < (cxdata_len-1) && k < SC_MAX_OBJECT_ID_OCTETS; k++) { + oid.value[k] = cxdata[k+1]; /* ignore first byte of blob (algo ID) */ + } + if (sc_compare_oid(&oid, &curve25519_binary_oid)) { + prkey_info.field_length = 255; + r = sc_pkcs15emu_add_xeddsa_prkey(p15card, &prkey_obj, &prkey_info); + break; + } + /* fall through */ + case SC_OPENPGP_KEYALGO_ECDSA: + /* TODO Store the OID from cxdata + 1 ?? */ r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info); + break; + case SC_OPENPGP_KEYALGO_RSA: + if (r >= 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) @@ -319,6 +352,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card) sc_pkcs15_pubkey_info_t pubkey_info; sc_pkcs15_object_t pubkey_obj; u8 cxdata[10]; + int cxdata_len = sizeof(cxdata); char path_template[] = "006E:0073:00Cx"; int j; @@ -327,7 +361,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 */ @@ -338,6 +372,9 @@ 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; + int k; + pubkey_info.id.len = 1; pubkey_info.id.value[0] = i + 1; pubkey_info.usage = key_cfg[i].pubkey_usage; @@ -346,13 +383,41 @@ 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) { + switch (cxdata[0]) { + case SC_OPENPGP_KEYALGO_EDDSA: + /* TODO Store the OID from cxdata + 1 ?? */ + /* assuming Ed25519 as it is the only supported now */ + pubkey_info.field_length = 255; + 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 */ + sc_init_oid(&oid); + /* Create copy of oid */ + for (k = 0; k < (cxdata_len-1) && k < SC_MAX_OBJECT_ID_OCTETS; k++) { + oid.value[k] = cxdata[k+1]; /* ignore first byte of blob (algo ID) */ + } + if (sc_compare_oid(&oid, &curve25519_binary_oid)) { + pubkey_info.field_length = 255; + r = sc_pkcs15emu_add_xeddsa_pubkey(p15card, &pubkey_obj, &pubkey_info); + break; + } + /* fall through */ + case SC_OPENPGP_KEYALGO_ECDSA: + /* TODO Store the OID from cxdata + 1 ?? */ r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info); + break; + case SC_OPENPGP_KEYALGO_RSA: + if (r >= 3) { + pubkey_info.modulus_length = bebytes2ushort(cxdata + 1); + r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); + break; + } + /* Fallthrough */ + default: + sc_log(ctx, "Invalid algorithm identifier %x (length = %d)", + cxdata[0], r); } if (r < 0) diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c index 3740e2bb..6736f8e8 100644 --- a/src/pkcs15init/pkcs15-openpgp.c +++ b/src/pkcs15init/pkcs15-openpgp.c @@ -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));