Skip to content

Commit 3ef24f9

Browse files
committed
card-piv.c,pkcs15-piv.c,piv-tool.c - Support for RSA 4096 and 25519
Yubikey with firmware >= 5.7 supports RSA 4096, and EDDSA and XEDDSA which is non standard PIV. WIP Only tested with 9A key and self signed certificate created by Yubic-piv-tool. Signature created with: ./pkcs11-tool -m EDDSA --login --sign --id 01 --input-file /tmp/data.txt --output-file /tmp/YK11-9A-signature.der and signature verified via openssl 3.3.1 ./openssl pkeyutl -verify -pubin -inkey /tmp/YK11-9A-pub.pem -rawin -in /tmp/data.txt -sigfile /tmp/YK11-9A-signature.der On branch X25519-improvements-2 Changes to be committed: modified: libopensc/card-piv.c modified: libopensc/pkcs15-piv.c modified: tools/piv-tool.c
1 parent f9bae64 commit 3ef24f9

File tree

3 files changed

+119
-14
lines changed

3 files changed

+119
-14
lines changed

src/libopensc/card-piv.c

+67-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* card-default.c: Support for cards with no driver
44
*
55
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
6-
* Copyright (C) 2005-2023 Douglas E. Engert <deengert@gmail.com>
6+
* Copyright (C) 2005-2024 Douglas E. Engert <deengert@gmail.com>
77
* Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com>
88
* Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com>
99
*
@@ -544,10 +544,13 @@ static const struct sc_atr_table piv_atrs[] = {
544544
static struct piv_supported_ec_curves {
545545
struct sc_object_id oid;
546546
size_t size;
547+
unsigned int key_type;
547548
} ec_curves[] = {
548-
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* secp256r1, nistp256, prime256v1, ansiX9p256r1 */
549-
{{{1, 3, 132, 0, 34, -1}}, 384}, /* secp384r1, nistp384, prime384v1, ansiX9p384r1 */
550-
{{{-1}}, 0} /* This entry must not be touched. */
549+
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* secp256r1, nistp256, prime256v1, ansiX9p256r1 */
550+
{{{1, 3, 132, 0, 34, -1}}, 384, SC_ALGORITHM_EC}, /* secp384r1, nistp384, prime384v1, ansiX9p384r1 */
551+
{{{1, 3, 101, 112, -1}}, 255, SC_ALGORITHM_EDDSA}, /* RFC8410 OID equivalent to ed25519 */
552+
{{{1, 3, 101, 110, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* RFC8410 OID equivalent to curve25519 */
553+
{{{-1}}, 0, 0} /* This entry must not be touched. */
551554
};
552555

553556
/* all have same AID */
@@ -573,6 +576,8 @@ static struct piv_aid piv_aids[] = {
573576
#define CI_NO_RSA2048 0x00010000U /* does not have RSA 2048 */
574577
#define CI_NO_EC384 0x00020000U /* does not have EC 384 */
575578
#define CI_NO_EC 0x00040000U /* No EC at all */
579+
#define CI_RSA_4096 0x00080000U /* Card supports rsa 4096 */
580+
#define CI_25519 0x00100000U /* Card supports ED25519 and X25519 */
576581

577582
/*
578583
* Flags in the piv_object:
@@ -2720,14 +2725,21 @@ static int piv_generate_key(sc_card_t *card,
27202725
case 0x05: keydata->key_bits = 3072; break;
27212726
case 0x06: keydata->key_bits = 1024; break;
27222727
case 0x07: keydata->key_bits = 2048; break;
2728+
case 0x16: keydata->key_bits = 4096; break;
27232729
case 0x11: keydata->key_bits = 0;
2724-
keydata->ecparam = 0; /* we only support prime256v1 for 11 */
2730+
keydata->ecparam = 0; /* we only support prime256v1 */
27252731
keydata->ecparam_len =0;
27262732
break;
27272733
case 0x14: keydata->key_bits = 0;
27282734
keydata->ecparam = 0; /* we only support secp384r1 */
27292735
keydata->ecparam_len = 0;
27302736
break;
2737+
case 0xE0:
2738+
case 0xE1:
2739+
keydata->key_bits = 0;
2740+
keydata->ecparam = 0;
2741+
keydata->ecparam_len = 0;
2742+
break;
27312743
default:
27322744
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
27332745
}
@@ -2780,8 +2792,11 @@ static int piv_generate_key(sc_card_t *card,
27802792
keydata->pubkey_len = taglen;
27812793
memcpy (keydata->pubkey, tag, taglen);
27822794
}
2783-
}
2784-
else { /* must be EC */
2795+
// } else if (keydata->key_algid == 0xE0 || keydata->key_algid == 0xE1) {
2796+
// /* TODO DEE need to look at what gets returned */
2797+
/* TODO assume same as EC with tag 86 */
2798+
2799+
} else { /* must be EC */
27852800
tag = sc_asn1_find_tag(card->ctx, cp, in_len, 0x86, &taglen);
27862801
if (tag != NULL && taglen > 0) {
27872802
keydata->ecpoint = malloc(taglen);
@@ -2793,7 +2808,8 @@ static int piv_generate_key(sc_card_t *card,
27932808
}
27942809

27952810
/* TODO: -DEE Could add key to cache so could use engine to generate key,
2796-
* and sign req in single operation */
2811+
* and sign req in single operation or write temporary selfsigned
2812+
* certificate with new public key */
27972813
r = 0;
27982814
}
27992815

@@ -4512,6 +4528,12 @@ piv_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num)
45124528
}
45134529
} else
45144530
r = SC_ERROR_NO_CARD_SUPPORT;
4531+
} else if (env->algorithm == SC_ALGORITHM_EDDSA) {
4532+
priv->alg_id = 0xE0;
4533+
priv->key_size = 255;
4534+
} else if (env->algorithm == SC_ALGORITHM_XEDDSA) {
4535+
priv->alg_id = 0xE1;
4536+
priv->key_size = 255;
45154537
} else
45164538
r = SC_ERROR_NO_CARD_SUPPORT;
45174539
priv->key_ref = env->key_ref[0];
@@ -4541,6 +4563,7 @@ static int piv_validate_general_authentication(sc_card_t *card,
45414563
unsigned int cla, tag;
45424564
unsigned int real_alg_id, op_tag;
45434565

4566+
/* TODO check for 4096 keys */
45444567
u8 sbuf[4096]; /* needs work. for 3072 keys, needs 384+10 or so */
45454568
size_t sbuflen = sizeof(sbuf);
45464569
u8 rbuf[4096];
@@ -4561,6 +4584,7 @@ static int piv_validate_general_authentication(sc_card_t *card,
45614584
}
45624585
if (priv->operation == SC_SEC_OPERATION_DERIVE
45634586
&& priv->algorithm == SC_ALGORITHM_EC) {
4587+
/* TODO add code for X25519 */
45644588
op_tag = 0x85;
45654589
} else {
45664590
op_tag = 0x81;
@@ -4583,11 +4607,12 @@ static int piv_validate_general_authentication(sc_card_t *card,
45834607
case 128: real_alg_id = 0x06; break;
45844608
case 256: real_alg_id = 0x07; break;
45854609
case 384: real_alg_id = 0x05; break;
4610+
case 512: real_alg_id = 0x16; break;
45864611
default:
45874612
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NO_CARD_SUPPORT);
45884613
}
45894614
}
4590-
/* EC alg_id was already set */
4615+
/* EC and ED alg_id was already set */
45914616

45924617
r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref,
45934618
sbuf, p - sbuf, rbuf, sizeof rbuf);
@@ -4649,6 +4674,18 @@ piv_compute_signature(sc_card_t *card, const u8 * data, size_t datalen,
46494674
goto err;
46504675

46514676
r = sc_asn1_decode_ecdsa_signature(card->ctx, rbuf, r, nLen, &out, outlen);
4677+
/* Yubikey 5.7.x supports ED25519 */
4678+
} else if (priv->alg_id == 0xE0) {
4679+
nLen = (priv->key_size + 7) / 8;
4680+
if (outlen < nLen) {
4681+
sc_log(card->ctx,
4682+
" output too small for ED signature %"SC_FORMAT_LEN_SIZE_T"u < %"SC_FORMAT_LEN_SIZE_T"u",
4683+
outlen, nLen);
4684+
r = SC_ERROR_INVALID_DATA;
4685+
goto err;
4686+
}
4687+
r = piv_validate_general_authentication(card, data, datalen, out, outlen);
4688+
46524689
} else { /* RSA is all set */
46534690
r = piv_validate_general_authentication(card, data, datalen, out, outlen);
46544691
}
@@ -5493,7 +5530,7 @@ static int piv_match_card_continued(sc_card_t *card)
54935530
apdu.resplen = sizeof(yubico_version_buf);
54945531
apdu.le = apdu.resplen;
54955532
r2 = sc_transmit_apdu(card, &apdu); /* on error yubico_version == 0 */
5496-
if (r2 >= 3) {
5533+
if (apdu.resplen == 3) {
54975534
priv->yubico_version = (yubico_version_buf[0]<<16) | (yubico_version_buf[1] <<8) | yubico_version_buf[2];
54985535
sc_log(card->ctx, "Yubico card->type=%d, r=0x%08x version=0x%08x", card->type, r, priv->yubico_version);
54995536
}
@@ -5608,6 +5645,9 @@ static int piv_match_card_continued(sc_card_t *card)
56085645
| CI_LEAKS_FILE_NOT_FOUND;
56095646
if (priv->yubico_version < 0x00040302)
56105647
priv->card_issues |= CI_VERIFY_LC0_FAIL;
5648+
/* TODO may need to relocate when I get card to test */
5649+
if (priv->yubico_version >= 0x00050700)
5650+
priv->card_issues |= CI_RSA_4096 | CI_25519;
56115651
break;
56125652

56135653
case SC_CARD_TYPE_PIV_II_GI_DE:
@@ -5691,6 +5731,8 @@ static int piv_init(sc_card_t *card)
56915731
int r = 0;
56925732
piv_private_data_t * priv = PIV_DATA(card);
56935733
unsigned long flags;
5734+
unsigned long flags_eddsa;
5735+
unsigned long flags_xeddsa;
56945736
unsigned long ext_flags;
56955737

56965738
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@@ -5739,15 +5781,28 @@ static int piv_init(sc_card_t *card)
57395781
_sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */
57405782
_sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */
57415783
_sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */
5784+
if (priv->card_issues & CI_RSA_4096)
5785+
_sc_card_add_rsa_alg(card, 4096, flags, 0); /* some Yubikeys support this */
57425786

57435787
if (!(priv->card_issues & CI_NO_EC)) {
57445788
int i;
57455789
flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE;
57465790
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
5791+
flags_eddsa = SC_ALGORITHM_EDDSA_RAW;
5792+
flags_xeddsa = SC_ALGORITHM_XEDDSA_RAW;
57475793

57485794
for (i = 0; ec_curves[i].oid.value[0] >= 0; i++) {
5749-
if (!(priv->card_issues & CI_NO_EC384 && ec_curves[i].size == 384))
5750-
_sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].oid);
5795+
if (ec_curves[i].key_type == SC_ALGORITHM_EC) {
5796+
if (!(priv->card_issues & CI_NO_EC384 && ec_curves[i].size == 384))
5797+
_sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].oid);
5798+
5799+
} else if (priv->card_issues & CI_25519) {
5800+
if (ec_curves[i].key_type == SC_ALGORITHM_EDDSA) {
5801+
_sc_card_add_eddsa_alg(card, ec_curves[i].size, flags_eddsa, ext_flags, &ec_curves[i].oid);
5802+
} else if (ec_curves[i].key_type == SC_ALGORITHM_XEDDSA) {
5803+
_sc_card_add_xeddsa_alg(card, ec_curves[i].size, flags_xeddsa, ext_flags, &ec_curves[i].oid);
5804+
}
5805+
}
57515806
}
57525807
}
57535808

src/libopensc/pkcs15-piv.c

+23-2
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,8 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
900900
break;
901901

902902
case SC_ALGORITHM_EC:
903+
case SC_ALGORITHM_EDDSA:
904+
case SC_ALGORITHM_XEDDSA:
903905
ckis[i].pubkey_len = cert_out->key->u.ec.params.field_length;
904906
if (ckis[i].cert_keyUsage_present) {
905907
if (ckis[i].cert_keyUsage & SC_X509_DIGITAL_SIGNATURE) {
@@ -1099,7 +1101,9 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
10991101
ckis[i].pubkey_from_file = 1;
11001102
break;
11011103
case SC_ALGORITHM_EC:
1102-
ckis[i].key_alg = SC_ALGORITHM_EC;
1104+
case SC_ALGORITHM_EDDSA:
1105+
case SC_ALGORITHM_XEDDSA:
1106+
ckis[i].key_alg = p15_key->algorithm;
11031107
ckis[i].pubkey_len = p15_key->u.ec.params.field_length;
11041108
ckis[i].pubkey_found = 1;
11051109
ckis[i].pubkey_from_file = 1;
@@ -1138,6 +1142,8 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
11381142
ckis[i].pubkey_found = 1;
11391143
break;
11401144
case SC_ALGORITHM_EC:
1145+
case SC_ALGORITHM_EDDSA:
1146+
case SC_ALGORITHM_XEDDSA:
11411147
if (ckis[i].cert_keyUsage_present) {
11421148
pubkey_info.usage = ckis[i].pub_usage;
11431149
} else {
@@ -1148,7 +1154,14 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
11481154
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
11491155

11501156
/* should not fail */
1151-
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
1157+
1158+
if (ckis[i].key_alg == SC_ALGORITHM_EDDSA)
1159+
r = sc_pkcs15emu_add_eddsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
1160+
else if (ckis[i].key_alg == SC_ALGORITHM_XEDDSA)
1161+
r = sc_pkcs15emu_add_xeddsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
1162+
else
1163+
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
1164+
11521165
LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add EC pubkey");
11531166

11541167
ckis[i].pubkey_found = 1;
@@ -1219,6 +1232,8 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
12191232
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
12201233
break;
12211234
case SC_ALGORITHM_EC:
1235+
case SC_ALGORITHM_EDDSA:
1236+
case SC_ALGORITHM_XEDDSA:
12221237
if (ckis[i].cert_keyUsage_present) {
12231238
prkey_info.usage |= ckis[i].priv_usage;
12241239
/* If retired key and non gov cert has NONREPUDIATION, treat as user_consent */
@@ -1231,6 +1246,12 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
12311246
prkey_info.field_length = ckis[i].pubkey_len;
12321247
sc_log(card->ctx, "DEE added key_alg %2.2lx prkey_obj.flags %8.8x",
12331248
ckis[i].key_alg, prkey_obj.flags);
1249+
1250+
if (ckis[i].key_alg == SC_ALGORITHM_EDDSA)
1251+
r = sc_pkcs15emu_add_eddsa_prkey(p15card, &prkey_obj, &prkey_info);
1252+
else if (ckis[i].key_alg == SC_ALGORITHM_XEDDSA)
1253+
r = sc_pkcs15emu_add_xeddsa_prkey(p15card, &prkey_obj, &prkey_info);
1254+
else
12341255
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
12351256
break;
12361257
default:

src/tools/piv-tool.c

+29
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,14 @@ static int gen_key(const char * key_info)
320320
case 0x14: keydata.key_bits = 0;
321321
nid = NID_secp384r1;
322322
break;
323+
case 0xE0:
324+
keydata.key_bits = 0;
325+
nid = NID_ED25519;
326+
break;
327+
case 0xE1:
328+
keydata.key_bits = 0;
329+
nid = NID_X25519;
330+
break;
323331
#endif
324332
default:
325333
fprintf(stderr, "<keyref>:<algid> algid=RSA - 05, 06, 07 for 3072, 1024, 2048;EC - 11, 14 for 256, 384\n");
@@ -443,6 +451,27 @@ static int gen_key(const char * key_info)
443451
EVP_PKEY_CTX_free(cctx);
444452
OSSL_PARAM_free(params);
445453
#endif
454+
455+
#ifdef EVP_PKEY_ED25519
456+
} else if (nid == NID_ED25519 || nid == NID_X25519) {
457+
#if OPENSSL_VERSION_NUMBER < 0x30000000L
458+
fprintf(stderr, "This build of OpenSSL does not support ED25519 or X25519 keys\n");
459+
return -1;
460+
#else
461+
evpkey = EVP_PKEY_new_raw_public_key(nid, NULL, keydata.ecpoint, keydata.ecpoint_len);
462+
if (!evpkey) {
463+
sc_log_openssl(ctx);
464+
fprintf(stderr, "gen key failed ti copy 25519 pubkey\n");
465+
return -1;
466+
}
467+
468+
if (verbose)
469+
EVP_PKEY_print_public_fp(stdout, evpkey, 0, NULL);
470+
#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
471+
#else
472+
fprintf(stderr, "This build of OpenSSL does not support ED25519 or X25519 keys\n");
473+
return -1;
474+
#endif /* EVP_PKEY_ED25519 */
446475
} else { /* EC key */
447476
#if !defined(OPENSSL_NO_EC)
448477
int i;

0 commit comments

Comments
 (0)