OpenPGP Card v3 ECC support (#1506)

* pgp: initialize ecc keys for OPC3

* Add supported ECC algorithms by card version

* Add tasks identified so far

* pgp: Recognize ECC set on card

* pgp: get_pubkey_pem read ECC pubkey from card

* pgp: minor code changes for ECC compatibility

* pgp: expand sc_cardctl_openpgp_keygen_info to hold ec info

* Fix segfault problem in pkcs15-pubkey.c

* pgp: enable key generation with pkcs15-init and ECC

* pgp: adapt calculate_and_store_fingerprint to accept ECC

* pgp: adapt rest of pgp_gen_key and subfunctions to accept ECC

* pgp: add kdf parameters for ECDH fingerprint calculation

* pgp: enable key import with pkcs15-init and ECC

* pkcs15-pubkey: fix_ec_parameters onlz accpets explicit data or named_curve

* Fix some mistakes during merge

* More clean up for PR

* Fix some ugly alignments

* Improve code readability

* Prevent unitialized variable by using FUNC_RETURN

* OpenPGP: add length check

* pgp: save exponent length in bits for sc_cardctl_openpgp_keystore_info_t

* pgp: length checks and reallocations

* pgp: oid init added

* OpenPGP: slightly re-factor pgp_update_new_algo_attr()

* replace loop copy with memcpy()
* use ushort2bebytes() to set RSA modulus & exponent
* use symbolic name SC_OPENPGP_KEYFORMAT_RSA_STD for the key import format

* OpenPGP: slighly re-factor pgp_parse_and_set_pubkey_output()

* check for RSA modulus & exponent lengths not being a multiple of 8
* make sure RSA modulus & exponent lengths are always set
* remove a left-over RSA setting from the EC code

* pgp: adding BYTES4BITS

* pgp: initialization of values in pgp_build_extended_header_list based on key type

* pgp: add BYTES4BITS and remove unnecessary tests

* Fix broken pgp_update_new_algo_attr

* pgp: fix the ecpoint_len variable
This commit is contained in:
Alexander Paetzelt 2019-01-30 22:00:36 +01:00 committed by Frank Morgner
parent 7a7ff50422
commit 09a594d0f0
7 changed files with 733 additions and 307 deletions

View File

@ -151,6 +151,26 @@ enum _sm_algo {
SM_ALGO_UNKNOWN = 257 /* 3.x: coded as 0 in DO C0 */ SM_ALGO_UNKNOWN = 257 /* 3.x: coded as 0 in DO C0 */
}; };
static struct pgp_supported_ec_curves {
struct sc_object_id oid;
size_t size;
struct sc_object_id oid_binary;
} ec_curves[] = {
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256,
{{0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, -1}}}, /* ansiX9p256r1 */
{{{1, 3, 132, 0, 34, -1}}, 384,
{{0x2b, 0x81, 0x04, 0x00, 0x22, -1}}}, /* ansiX9p384r1 */
{{{1, 3, 132, 0, 35, -1}}, 512,
{{0x2b, 0x81, 0x04, 0x00, 0x23, -1}}}, /* ansiX9p512r1 */
{{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256,
{{0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07, -1}}}, /* brainpoolP256r1 */
{{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384,
{{0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0b, -1}}}, /* brainpoolP384r1 */
{{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512,
{{0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d, -1}}}, /* brainpoolP512r1 */
{{{-1}}, 0, {{0x0}}} /* This entry must not be touched. */
};
typedef struct pgp_blob { typedef struct pgp_blob {
struct pgp_blob * next; /* pointer to next sibling */ struct pgp_blob * next; /* pointer to next sibling */
struct pgp_blob * parent; /* pointer to parent */ struct pgp_blob * parent; /* pointer to parent */
@ -463,7 +483,7 @@ pgp_init(sc_card_t *card)
sc_path_t path; sc_path_t path;
sc_file_t *file = NULL; sc_file_t *file = NULL;
struct do_info *info; struct do_info *info;
int r; int r, i;
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
@ -587,22 +607,32 @@ pgp_init(sc_card_t *card)
* add supported algorithms based on specification for pkcs15-init */ * add supported algorithms based on specification for pkcs15-init */
if ((priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) && if ((priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) &&
(strcmp(card->ctx->app_name, "pkcs15-init") == 0)) { (strcmp(card->ctx->app_name, "pkcs15-init") == 0)) {
unsigned long flags_rsa, flags_ecc, ext_flags;
/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 / v3.x section 7.2.11 & 7.2.12 */ /* 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 | flags_rsa = SC_ALGORITHM_RSA_PAD_PKCS1|
SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_NONE|
SC_ALGORITHM_ONBOARD_KEY_GEN; /* key gen. on card */ SC_ALGORITHM_ONBOARD_KEY_GEN;
flags_ecc = SC_ALGORITHM_ECDSA_RAW|
SC_ALGORITHM_ECDH_CDH_RAW|
SC_ALGORITHM_ECDSA_HASH_NONE|
SC_ALGORITHM_ONBOARD_KEY_GEN;
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE;
switch (card->type) { switch (card->type) {
case SC_CARD_TYPE_OPENPGP_V3: case SC_CARD_TYPE_OPENPGP_V3:
/* RSA 1024 was removed for v3+ */ /* RSA 1024 was removed for v3+ */
_sc_card_add_rsa_alg(card, 2048, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 3072, flags, 0); _sc_card_add_rsa_alg(card, 3072, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 4096, flags, 0); _sc_card_add_rsa_alg(card, 4096, flags_rsa, 0);
/* TODO add ECC /* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
* 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; break;
case SC_CARD_TYPE_OPENPGP_GNUK: case SC_CARD_TYPE_OPENPGP_GNUK:
_sc_card_add_rsa_alg(card, 2048, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
/* TODO add ECC for more recent Gnuk (1.2.x) /* TODO add ECC for more recent Gnuk (1.2.x)
* these are not include in SC_CARD_TYPE_OPENPGP_GNUK, but * these are not include in SC_CARD_TYPE_OPENPGP_GNUK, but
* are treated like SC_CARD_TYPE_OPENPGP_V2 * are treated like SC_CARD_TYPE_OPENPGP_V2
@ -610,10 +640,10 @@ pgp_init(sc_card_t *card)
break; break;
case SC_CARD_TYPE_OPENPGP_V2: case SC_CARD_TYPE_OPENPGP_V2:
default: default:
_sc_card_add_rsa_alg(card, 1024, flags, 0); _sc_card_add_rsa_alg(card, 1024, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 3072, flags, 0); _sc_card_add_rsa_alg(card, 3072, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 4096, flags, 0); _sc_card_add_rsa_alg(card, 4096, flags_rsa, 0);
break; break;
} }
} }
@ -657,6 +687,9 @@ pgp_parse_hist_bytes(sc_card_t *card, u8 *ctlv, size_t ctlv_len)
static int 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(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_t *key_info)
{ {
struct sc_object_id oid;
unsigned int j;
if (blob == NULL || blob->data == NULL || blob->len == 0 || if (blob == NULL || blob->data == NULL || blob->len == 0 ||
blob->id < 0x00c1 || blob->id > 0x00c3 || key_info == NULL) blob->id < 0x00c1 || blob->id > 0x00c3 || key_info == NULL)
return SC_ERROR_INCORRECT_PARAMETERS; return SC_ERROR_INCORRECT_PARAMETERS;
@ -669,13 +702,34 @@ pgp_parse_algo_attr_blob(const pgp_blob_t *blob, sc_cardctl_openpgp_keygen_info_
return SC_ERROR_INCORRECT_PARAMETERS; return SC_ERROR_INCORRECT_PARAMETERS;
key_info->algorithm = SC_OPENPGP_KEYALGO_RSA; key_info->algorithm = SC_OPENPGP_KEYALGO_RSA;
key_info->rsa.modulus_len = bebytes2ushort(blob->data + 1); key_info->u.rsa.modulus_len = bebytes2ushort(blob->data + 1);
key_info->rsa.exponent_len = bebytes2ushort(blob->data + 3); key_info->u.rsa.exponent_len = bebytes2ushort(blob->data + 3);
key_info->rsa.keyformat = (blob->len > 5) key_info->u.rsa.keyformat = (blob->len > 5)
? blob->data[5] ? blob->data[5]
: SC_OPENPGP_KEYFORMAT_RSA_STD; : SC_OPENPGP_KEYFORMAT_RSA_STD;
break; break;
case SC_OPENPGP_KEYALGO_ECDH:
case SC_OPENPGP_KEYALGO_ECDSA:
/* SC_OPENPGP_KEYALGO_ECDH || SC_OPENPGP_KEYALGO_ECDSA */
key_info->algorithm = blob->data[0];
sc_init_oid(&oid);
/* Create copy of oid from blob */
for (j=0; j < (blob->len-1); j++) {
oid.value[j] = blob->data[j+1]; /* ignore first byte of blob (algo ID) */
}
/* 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_binary, &oid)){
key_info->u.ec.oid = ec_curves[j].oid;
key_info->u.ec.key_length = ec_curves[j].size;
break;
}
}
break;
default: default:
return SC_ERROR_NOT_IMPLEMENTED; return SC_ERROR_NOT_IMPLEMENTED;
} }
@ -818,19 +872,37 @@ pgp_get_card_features(sc_card_t *card)
* see OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */ * see OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */
for (i = 0x00c1; i <= 0x00c3; i++) { for (i = 0x00c1; i <= 0x00c3; i++) {
sc_cardctl_openpgp_keygen_info_t key_info; sc_cardctl_openpgp_keygen_info_t key_info;
/* 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 */
/* OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */ /* 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) && if ((pgp_get_blob(card, blob73, i, &blob) >= 0) &&
(pgp_parse_algo_attr_blob(blob, &key_info) >= 0)) { (pgp_parse_algo_attr_blob(blob, &key_info) >= 0)) {
if (key_info.algorithm == SC_OPENPGP_KEYALGO_RSA) /* RFC 4880: RSA */ /* RSA [RFC 4880] */
_sc_card_add_rsa_alg(card, key_info.rsa.modulus_len, flags, 0); if (key_info.algorithm == 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) {
/* TODO v3.0+: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */ unsigned long flags, ext_flags;
if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDH)
flags = SC_ALGORITHM_ECDH_CDH_RAW;
if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDSA)
flags = SC_ALGORITHM_ECDSA_RAW;
flags |= SC_ALGORITHM_ECDSA_HASH_NONE;
flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
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);
}
} }
} }
@ -1555,7 +1627,7 @@ static int
pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
{ {
struct pgp_priv_data *priv = DRVDATA(card); struct pgp_priv_data *priv = DRVDATA(card);
pgp_blob_t *blob, *mod_blob, *exp_blob; pgp_blob_t *blob, *mod_blob, *exp_blob, *pubkey_blob;
sc_pkcs15_pubkey_t pubkey; sc_pkcs15_pubkey_t pubkey;
u8 *data; u8 *data;
size_t len; size_t len;
@ -1564,19 +1636,35 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
sc_log(card->ctx, "called, tag=%04x\n", tag); sc_log(card->ctx, "called, tag=%04x\n", tag);
if ((r = pgp_get_blob(card, priv->mf, tag & 0xFFFE, &blob)) < 0 if ((r = pgp_get_blob(card, priv->mf, tag & 0xFFFE, &blob)) < 0
|| (r = pgp_get_blob(card, blob, 0x7F49, &blob)) < 0 || (r = pgp_get_blob(card, blob, 0x7F49, &blob)) < 0)
|| (r = pgp_get_blob(card, blob, 0x0081, &mod_blob)) < 0
|| (r = pgp_get_blob(card, blob, 0x0082, &exp_blob)) < 0
|| (r = pgp_read_blob(card, mod_blob)) < 0
|| (r = pgp_read_blob(card, exp_blob)) < 0)
LOG_TEST_RET(card->ctx, r, "error getting elements"); LOG_TEST_RET(card->ctx, r, "error getting elements");
/* RSA */
if ((r = pgp_get_blob(card, blob, 0x0081, &mod_blob)) == 0
&& (r = pgp_get_blob(card, blob, 0x0082, &exp_blob)) == 0
&& (r = pgp_read_blob(card, mod_blob)) == 0
&& (r = pgp_read_blob(card, exp_blob)) == 0) {
memset(&pubkey, 0, sizeof(pubkey)); memset(&pubkey, 0, sizeof(pubkey));
pubkey.algorithm = SC_ALGORITHM_RSA; pubkey.algorithm = SC_ALGORITHM_RSA;
pubkey.u.rsa.modulus.data = mod_blob->data; pubkey.u.rsa.modulus.data = mod_blob->data;
pubkey.u.rsa.modulus.len = mod_blob->len; pubkey.u.rsa.modulus.len = mod_blob->len;
pubkey.u.rsa.exponent.data = exp_blob->data; pubkey.u.rsa.exponent.data = exp_blob->data;
pubkey.u.rsa.exponent.len = exp_blob->len; pubkey.u.rsa.exponent.len = exp_blob->len;
}
/* ECC */
else if ((r = pgp_get_blob(card, blob, 0x0086, &pubkey_blob)) == 0
&& (r = pgp_read_blob(card, pubkey_blob)) == 0) {
memset(&pubkey, 0, sizeof(pubkey));
pubkey.algorithm = SC_ALGORITHM_EC;
pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
pubkey.u.ec.ecpointQ.len = pubkey_blob->len;
}
else
LOG_TEST_RET(card->ctx, r, "error getting elements");
r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len); r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len);
LOG_TEST_RET(card->ctx, r, "public key encoding failed"); LOG_TEST_RET(card->ctx, r, "public key encoding failed");
@ -1957,7 +2045,9 @@ pgp_set_security_env(sc_card_t *card,
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
if ((env->flags & SC_SEC_ENV_ALG_PRESENT) && (env->algorithm != SC_ALGORITHM_RSA)) if ((env->flags & SC_SEC_ENV_ALG_PRESENT)
&& (env->algorithm != SC_ALGORITHM_RSA)
&& (priv->bcd_version < OPENPGP_CARD_3_0))
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
"only RSA algorithm supported"); "only RSA algorithm supported");
@ -2119,8 +2209,8 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
/* padding according to OpenPGP card spec 1.1 & 2.x section 7.2.9 / 3.x section 7.2.11 */ /* 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))) if (!(temp = malloc(inlen + 1)))
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
/* padding byte: 0x00 = RSA; 0x02 = AES [v2.1+ only] */ /* padding byte: 0xa6 = ECC; 0x00 = RSA; 0x02 = AES */
temp[0] = 0x00; (env->algorithm == SC_ALGORITHM_EC) ? (temp[0] = 0xa6) : (temp[0] = 0x00);
memcpy(temp + 1, in, inlen); memcpy(temp + 1, in, inlen);
in = temp; in = temp;
inlen += 1; inlen += 1;
@ -2191,61 +2281,63 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_
{ {
struct pgp_priv_data *priv = DRVDATA(card); struct pgp_priv_data *priv = DRVDATA(card);
pgp_blob_t *algo_blob; pgp_blob_t *algo_blob;
unsigned int old_modulus_len; /* measured in bits */
unsigned int old_exponent_len;
const unsigned int tag = 0x00C0 | key_info->key_id; const unsigned int tag = 0x00C0 | key_info->key_id;
u8 changed = 0; u8 *data;
int data_len;
int r = SC_SUCCESS; int r = SC_SUCCESS;
unsigned int i;
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
/* temporary workaround: protect v3 cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* get old algorithm attributes */
r = pgp_seek_blob(card, priv->mf, tag, &algo_blob); r = pgp_seek_blob(card, priv->mf, tag, &algo_blob);
LOG_TEST_RET(card->ctx, r, "Cannot get old algorithm attributes"); LOG_TEST_RET(card->ctx, r, "Cannot get old algorithm attributes");
old_modulus_len = bebytes2ushort(algo_blob->data + 1); /* modulus length is coded in byte 2 & 3 */
sc_log(card->ctx,
"Old modulus length %d, new %"SC_FORMAT_LEN_SIZE_T"u.",
old_modulus_len, key_info->rsa.modulus_len);
old_exponent_len = bebytes2ushort(algo_blob->data + 3); /* exponent length is coded in byte 3 & 4 */
sc_log(card->ctx,
"Old exponent length %d, new %"SC_FORMAT_LEN_SIZE_T"u.",
old_exponent_len, key_info->rsa.exponent_len);
/* Modulus */ /* ECDSA and ECDH */
/* If passed modulus_len is zero, it means using old key size */ if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
if (key_info->rsa.modulus_len == 0) { || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
sc_log(card->ctx, "Use old modulus length (%d).", old_modulus_len); data_len = key_info->u.ec.oid_len+1;
key_info->rsa.modulus_len = old_modulus_len; data = malloc(data_len);
if (!data)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
data[0] = key_info->algorithm;
/* oid.value is type int, therefore we need to loop over the values */
for (i=0; i < key_info->u.ec.oid_len; i++){
data[i+1] = key_info->u.ec.oid.value[i];
} }
/* To generate key with new key size */
else if (old_modulus_len != key_info->rsa.modulus_len) {
algo_blob->data[1] = (unsigned char)(key_info->rsa.modulus_len >> 8);
algo_blob->data[2] = (unsigned char)key_info->rsa.modulus_len;
changed = 1;
} }
/* Exponent */ /* RSA */
if (key_info->rsa.exponent_len == 0) { else if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){
sc_log(card->ctx, "Use old exponent length (%d).", old_exponent_len);
key_info->rsa.exponent_len = old_exponent_len; /* We can not rely on previous key attributes anymore, as it might be ECC */
if (key_info->u.rsa.exponent_len == 0 || key_info->u.rsa.modulus_len == 0)
LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS);
data_len = 6;
data = malloc(data_len);
if (!data)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
data[0] = key_info->algorithm;
ushort2bebytes(data+1, key_info->u.rsa.modulus_len);
/* OpenPGP Card only accepts 32bit as exponent lenght field,
* although you can import keys with smaller exponent;
* thus we don't change rsa.exponent_len, but ignore it here */
ushort2bebytes(data+3, SC_OPENPGP_MAX_EXP_BITS);
/* Import-Format of private key (e,p,q) */
data[5] = SC_OPENPGP_KEYFORMAT_RSA_STD;
} }
else if (old_exponent_len != key_info->rsa.exponent_len) { else {
algo_blob->data[3] = (unsigned char)(key_info->rsa.exponent_len >> 8); sc_log(card->ctx, "Unknown algorithm id");
algo_blob->data[4] = (unsigned char)key_info->rsa.exponent_len; LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
changed = 1;
} }
/* If the key to-be-generated has different size, pgp_set_blob(algo_blob, data, data_len);
* set this new value for GENERATE ASYMMETRIC KEY PAIR to work */ free(data);
if (changed) { r = pgp_put_data(card, tag, algo_blob->data, data_len);
r = pgp_put_data(card, tag, algo_blob->data, 6);
/* Note: Don't use pgp_set_blob to set data, because it won't touch the real DO */ /* Note: Don't use pgp_set_blob to set data, because it won't touch the real DO */
LOG_TEST_RET(card->ctx, r, "Cannot set new algorithm attributes"); LOG_TEST_RET(card->ctx, r, "Cannot set new algorithm attributes");
}
LOG_FUNC_RETURN(card->ctx, r); LOG_FUNC_RETURN(card->ctx, r);
} }
@ -2297,19 +2389,14 @@ pgp_store_creationtime(sc_card_t *card, u8 key_id, time_t *outtime)
/** /**
* Internal: calculate PGP fingerprints. * Internal: calculate and store PGP fingerprints.
* Reference: GnuPG, app-openpgp.c. * Reference: GnuPG, app-openpgp.c.
* modulus and exponent are passed separately from key_info
* because key_info->exponent may be null.
**/ **/
static int static int
pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
u8* modulus, u8* exponent,
sc_cardctl_openpgp_keygen_info_t *key_info) sc_cardctl_openpgp_keygen_info_t *key_info)
{ {
u8 fingerprint[SHA_DIGEST_LENGTH]; u8 fingerprint[SHA_DIGEST_LENGTH];
size_t mlen = key_info->rsa.modulus_len >> 3; /* 1/8 */
size_t elen = key_info->rsa.exponent_len >> 3; /* 1/8 */
u8 *fp_buffer = NULL; /* fingerprint buffer, not hashed */ u8 *fp_buffer = NULL; /* fingerprint buffer, not hashed */
size_t fp_buffer_len; size_t fp_buffer_len;
u8 *p; /* use this pointer to set fp_buffer content */ u8 *p; /* use this pointer to set fp_buffer content */
@ -2321,29 +2408,65 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
/* temporary workaround: protect v3 cards against non-RSA */ /* constructing public-key packet length */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA) /* RSA */
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA) {
if (modulus == NULL || mlen == 0) if (key_info->u.rsa.modulus == NULL
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Modulus missing"); || key_info->u.rsa.exponent == NULL
if (exponent == NULL || elen == 0) || (key_info->u.rsa.modulus_len) == 0
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Exponent missing"); || (key_info->u.rsa.exponent_len) == 0) {
/* http://tools.ietf.org/html/rfc4880 page 41, 72 */ sc_log(card->ctx, "Null data (modulus or exponent)");
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
/* https://tools.ietf.org/html/rfc4880 page 41, 72 */
pk_packet_len = 1 /* version number */ pk_packet_len = 1 /* version number */
+ 4 /* creation time */ + 4 /* creation time */
+ 1 /* algorithm */ + 1 /* algorithm */
+ 2 /* algorithm-specific fields: RSA modulus+exponent */ + 2 /* algorithm-specific fields: RSA modulus+exponent */
+ mlen + (BYTES4BITS(key_info->u.rsa.modulus_len))
+ 2 + 2
+ elen; + (BYTES4BITS(key_info->u.rsa.exponent_len));
}
/* ECC */
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
if (key_info->u.ec.ecpoint == NULL || (key_info->u.ec.ecpoint_len) == 0) {
sc_log(card->ctx, "Error: ecpoint required!");
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
/* https://tools.ietf.org/html/rfc4880 page 41, 72
* and https://tools.ietf.org/html/rfc6637 section 9 (page 8 and 9) */
pk_packet_len = 1 /* version number */
+ 4 /* creation time */
+ 1 /* algorithm */
+ 1 /* oid len */
+ (key_info->u.ec.oid_len) /* oid */
+ (key_info->u.ec.ecpoint_len); /* ecpoint */
/* KDF parameters for ECDH */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH) {
/* https://tools.ietf.org/html/rfc6637#section-8 */
pk_packet_len += 1 /* number of bytes */
+ 1 /* version number */
+ 1 /* KDF algo */
+ 1; /* KEK algo */
}
}
else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
sc_log(card->ctx, "pk_packet_len is %lu", pk_packet_len);
fp_buffer_len = 3 + pk_packet_len; fp_buffer_len = 3 + pk_packet_len;
p = fp_buffer = calloc(fp_buffer_len, 1); p = fp_buffer = calloc(fp_buffer_len, 1);
if (p == NULL) if (p == NULL)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
/* constructing public-key packet */
p[0] = 0x99; /* http://tools.ietf.org/html/rfc4880 page 71 */ p[0] = 0x99; /* http://tools.ietf.org/html/rfc4880 page 71 */
ushort2bebytes(++p, (unsigned short)pk_packet_len); ushort2bebytes(++p, (unsigned short)pk_packet_len);
/* start pk_packet */ /* start pk_packet */
@ -2351,15 +2474,57 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
*p = 4; /* Version 4 key */ *p = 4; /* Version 4 key */
ulong2bebytes(++p, (unsigned long)ctime); /* Creation time */ ulong2bebytes(++p, (unsigned long)ctime); /* Creation time */
p += 4; p += 4;
*p = 1; /* RSA */
/* algorithm-specific fields */ /* RSA */
ushort2bebytes(++p, (unsigned short)key_info->rsa.modulus_len); if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA) {
*p = 1; /* Algorithm ID, RSA */
p += 1;
ushort2bebytes(p, (unsigned short)key_info->u.rsa.modulus_len);
p += 2; p += 2;
memcpy(p, modulus, mlen); memcpy(p, key_info->u.rsa.modulus, (BYTES4BITS(key_info->u.rsa.modulus_len)));
p += mlen; p += (key_info->u.rsa.modulus_len >> 3);
ushort2bebytes(++p, (unsigned short)key_info->rsa.exponent_len); ushort2bebytes(++p, (unsigned short)key_info->u.rsa.exponent_len);
p += 2; p += 2;
memcpy(p, exponent, elen); memcpy(p, key_info->u.rsa.exponent, (BYTES4BITS(key_info->u.rsa.exponent_len)));
}
/* ECC */
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
/* Algorithm ID, see https://tools.ietf.org/html/rfc6637#section-5 */
*p = key_info->algorithm + 6;
p += 1;
*p = key_info->u.ec.oid_len;
p += 1;
memcpy(p, key_info->u.ec.oid.value, key_info->u.ec.oid_len);
p += key_info->u.ec.oid_len;
memcpy(p, key_info->u.ec.ecpoint, key_info->u.ec.ecpoint_len);
/* KDF parameters for ECDH */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH) {
/* https://tools.ietf.org/html/rfc6637#section-8
* This is copied from GnuPG's ecdh_params() function in app-openpgp.c */
p += key_info->u.ec.ecpoint_len;
*p = 0x03; /* number of bytes following */
p += 1;
*p = 0x01; /* version of this format */
p += 1;
if (key_info->u.ec.ecpoint_len <= 256){ /* ec bit size <= 256 */
*p = 0x08; /* KDF algo */
*(p+1) = 0x07; /* KEK algo */
}
else if (key_info->u.ec.ecpoint_len <= 384) { /* ec bit size <= 384 */
*p = 0x09; /* KDF algo */
*(p+1) = 0x08; /* KEK algo */
}
else { /* ec bit size = 512 */
*p = 0x0a; /* KDF algo */
*(p+1) = 0x09; /* KEK algo */
}
}
}
else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
p = NULL; p = NULL;
/* hash with SHA-1 */ /* hash with SHA-1 */
@ -2402,8 +2567,7 @@ err:
* Note that modulus_len, exponent_len is measured in bit. * Note that modulus_len, exponent_len is measured in bit.
**/ **/
static int static int
pgp_update_pubkey_blob(sc_card_t *card, u8* modulus, size_t modulus_len, pgp_update_pubkey_blob(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
u8* exponent, size_t exponent_len, u8 key_id)
{ {
struct pgp_priv_data *priv = DRVDATA(card); struct pgp_priv_data *priv = DRVDATA(card);
pgp_blob_t *pk_blob; pgp_blob_t *pk_blob;
@ -2415,11 +2579,11 @@ pgp_update_pubkey_blob(sc_card_t *card, u8* modulus, size_t modulus_len,
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
if (key_id == SC_OPENPGP_KEY_SIGN) if (key_info->key_id == SC_OPENPGP_KEY_SIGN)
blob_id = DO_SIGN_SYM; blob_id = DO_SIGN_SYM;
else if (key_id == SC_OPENPGP_KEY_ENCR) else if (key_info->key_id == SC_OPENPGP_KEY_ENCR)
blob_id = DO_ENCR_SYM; blob_id = DO_ENCR_SYM;
else if (key_id == SC_OPENPGP_KEY_AUTH) else if (key_info->key_id == SC_OPENPGP_KEY_AUTH)
blob_id = DO_AUTH_SYM; blob_id = DO_AUTH_SYM;
else { else {
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
@ -2431,12 +2595,25 @@ pgp_update_pubkey_blob(sc_card_t *card, u8* modulus, size_t modulus_len,
LOG_TEST_RET(card->ctx, r, "Cannot get the blob"); LOG_TEST_RET(card->ctx, r, "Cannot get the blob");
/* encode pubkey */ /* encode pubkey */
/* RSA */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){
memset(&pubkey, 0, sizeof(pubkey)); memset(&pubkey, 0, sizeof(pubkey));
pubkey.algorithm = SC_ALGORITHM_RSA; pubkey.algorithm = SC_ALGORITHM_RSA;
pubkey.u.rsa.modulus.data = modulus; pubkey.u.rsa.modulus.data = key_info->u.rsa.modulus;
pubkey.u.rsa.modulus.len = modulus_len >> 3; /* 1/8 */ pubkey.u.rsa.modulus.len = BYTES4BITS(key_info->u.rsa.modulus_len);
pubkey.u.rsa.exponent.data = exponent; pubkey.u.rsa.exponent.data = key_info->u.rsa.exponent;
pubkey.u.rsa.exponent.len = exponent_len >> 3; pubkey.u.rsa.exponent.len = BYTES4BITS(key_info->u.rsa.exponent_len);
}
/* ECC */
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
memset(&pubkey, 0, sizeof(pubkey));
pubkey.algorithm = SC_ALGORITHM_EC;
pubkey.u.ec.ecpointQ.value = key_info->u.ec.ecpoint;
pubkey.u.ec.ecpointQ.len = key_info->u.ec.ecpoint_len;
}
else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len); r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len);
LOG_TEST_RET(card->ctx, r, "Cannot encode pubkey"); LOG_TEST_RET(card->ctx, r, "Cannot encode pubkey");
@ -2457,8 +2634,6 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
{ {
time_t ctime = 0; time_t ctime = 0;
u8 *in = data; u8 *in = data;
u8 *modulus = NULL;
u8 *exponent = NULL;
int r; int r;
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
@ -2473,9 +2648,7 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
u8 *part = in; u8 *part = in;
/* parse TLV structure */ /* parse TLV structure */
r = sc_asn1_read_tag((const u8**)&part, r = sc_asn1_read_tag((const u8**)&part, data_len - (in - data), &cla, &tag, &len);
data_len - (in - data),
&cla, &tag, &len);
if (part == NULL) if (part == NULL)
r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; r = SC_ERROR_ASN1_OBJECT_NOT_FOUND;
LOG_TEST_RET(card->ctx, r, "Unexpected end of contents"); LOG_TEST_RET(card->ctx, r, "Unexpected end of contents");
@ -2485,25 +2658,49 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
} }
tag |= cla; tag |= cla;
/* RSA modulus */
if (tag == 0x0081) { if (tag == 0x0081) {
/* set the output data */ if ((BYTES4BITS(key_info->u.rsa.modulus_len) < len) /* modulus_len is in bits */
if (key_info->rsa.modulus) { || key_info->u.rsa.modulus == NULL) {
memcpy(key_info->rsa.modulus, part, len);
free(key_info->u.rsa.modulus);
key_info->u.rsa.modulus = malloc(len);
if (key_info->u.rsa.modulus == NULL)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
} }
/* always set output for modulus_len */
key_info->rsa.modulus_len = len*8; /* set values */
/* remember the modulus to calculate fingerprint later */ memcpy(key_info->u.rsa.modulus, part, len);
modulus = part; key_info->u.rsa.modulus_len = len * 8; /* store length in bits */
} }
/* RSA public exponent */
else if (tag == 0x0082) { else if (tag == 0x0082) {
/* set the output data */ if ((BYTES4BITS(key_info->u.rsa.exponent_len) < len) /* exponent_len is in bits */
if (key_info->rsa.exponent) { || key_info->u.rsa.exponent == NULL) {
memcpy(key_info->rsa.exponent, part, len);
free(key_info->u.rsa.exponent);
key_info->u.rsa.exponent = malloc(len);
if (key_info->u.rsa.exponent == NULL)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
} }
/* always set output for exponent_len */
key_info->rsa.exponent_len = len*8; /* set values */
/* remember the exponent to calculate fingerprint later */ memcpy(key_info->u.rsa.exponent, part, len);
exponent = part; key_info->u.rsa.exponent_len = len * 8; /* store length in bits */
}
/* ECC public key */
else if (tag == 0x0086) {
/* set the output data */
/* len is ecpoint length + format byte
* see section 7.2.14 of 3.3.1 specs */
if ((key_info->u.ec.ecpoint_len) != (len - 1)
|| key_info->u.ec.ecpoint == NULL) {
free(key_info->u.ec.ecpoint);
key_info->u.ec.ecpoint = malloc(len);
if (key_info->u.ec.ecpoint == NULL)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
}
memcpy(key_info->u.ec.ecpoint, part + 1, len - 1);
} }
/* go to next part to parse */ /* go to next part to parse */
@ -2513,12 +2710,11 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
/* calculate and store fingerprint */ /* calculate and store fingerprint */
sc_log(card->ctx, "Calculate and store fingerprint"); sc_log(card->ctx, "Calculate and store fingerprint");
r = pgp_calculate_and_store_fingerprint(card, ctime, modulus, exponent, key_info); r = pgp_calculate_and_store_fingerprint(card, ctime, key_info);
LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint"); LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint");
/* update pubkey blobs (B601,B801, A401) */ /* update pubkey blobs (B601, B801, A401) */
sc_log(card->ctx, "Update blobs holding pubkey info."); sc_log(card->ctx, "Update blobs holding pubkey info.");
r = pgp_update_pubkey_blob(card, modulus, key_info->rsa.modulus_len, r = pgp_update_pubkey_blob(card, key_info);
exponent, key_info->rsa.exponent_len, key_info->key_id);
LOG_FUNC_RETURN(card->ctx, r); LOG_FUNC_RETURN(card->ctx, r);
} }
@ -2534,8 +2730,9 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
/* temporary workaround: protect v3 cards against non-RSA */ /* protect older cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA) if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
&& card->type < SC_CARD_TYPE_OPENPGP_V3)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
if (id > card->algorithm_count) { if (id > card->algorithm_count) {
@ -2547,17 +2744,25 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke
/* get the algorithm corresponding to the key ID */ /* get the algorithm corresponding to the key ID */
algo = card->algorithms + (id - 1); algo = card->algorithms + (id - 1);
/* update new key length attribute */ /* update new key attribute */
algo->key_length = (unsigned int)key_info->rsa.modulus_len; if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA) {
algo->algorithm = SC_ALGORITHM_RSA;
algo->key_length = (unsigned int)key_info->u.rsa.modulus_len;
}
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
algo->algorithm = SC_ALGORITHM_EC;
algo->key_length = (unsigned int)((key_info->u.ec.ecpoint_len));
}
else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
} }
/** /**
* ABI (card ctl): GENERATE ASYMMETRIC KEY PAIR * ABI (card ctl): GENERATE ASYMMETRIC KEY PAIR
* Set key_info->modulus_len to zero if want to use old key size.
* Similarly for exponent length.
* key_info->modulus_len and key_info->exponent_len will be returned with new values.
**/ **/
static int static int
pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info) pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
@ -2572,8 +2777,9 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
/* temporary workaround: protect v3 cards against non-RSA */ /* protect older cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA) if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
&& card->type < SC_CARD_TYPE_OPENPGP_V3)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* set Control Reference Template for key */ /* set Control Reference Template for key */
@ -2588,7 +2794,7 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
"Invalid key ID; must be 1, 2, or 3"); "Invalid key ID; must be 1, 2, or 3");
} }
if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && key_info->rsa.modulus_len != 2048) if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && key_info->u.rsa.modulus_len != 2048)
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
"Gnuk only supports generating keys up to 2048-bit"); "Gnuk only supports generating keys up to 2048-bit");
@ -2600,7 +2806,7 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
* arbitrary modulus length which for sure fits into a short APDU. * arbitrary modulus length which for sure fits into a short APDU.
* This idea is borrowed from GnuPG code. */ * This idea is borrowed from GnuPG code. */
if (card->caps & SC_CARD_CAP_APDU_EXT if (card->caps & SC_CARD_CAP_APDU_EXT
&& key_info->rsa.modulus_len > 1900 && key_info->u.rsa.modulus_len > 1900
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK) { && card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
/* We won't store to apdu variable yet, because it will be reset in /* We won't store to apdu variable yet, because it will be reset in
* sc_format_apdu() */ * sc_format_apdu() */
@ -2726,7 +2932,7 @@ set_taglength_tlv(u8 *buffer, unsigned int tag, size_t length)
/** /**
* Internal: build Extended Header list (sec 4.3.3.7 - OpenPGP card spec v.2) * Internal: build Extended Header list (sec 4.3.3.9 - OpenPGP card spec v.3)
**/ **/
static int static int
pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info, pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info,
@ -2754,63 +2960,98 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info
u8 *data = NULL; u8 *data = NULL;
size_t len = 0; size_t len = 0;
u8 *p = NULL; u8 *p = NULL;
u8 *components[] = {key_info->rsa.e, key_info->rsa.p, key_info->rsa.q, key_info->rsa.n}; u8 *components[4];
size_t componentlens[] = {key_info->rsa.e_len, key_info->rsa.p_len, size_t componentlens[4];
key_info->rsa.q_len, key_info->rsa.n_len}; unsigned int componenttags[4];
unsigned int componenttags[] = {0x91, 0x92, 0x93, 0x97}; char *componentnames[4];
char *componentnames[] = { size_t comp_to_add;
"public exponent",
"prime p",
"prime q",
"modulus"
};
size_t comp_to_add = 3;
size_t req_e_len = 0; /* The exponent length specified in Algorithm Attributes */
pgp_blob_t *alat_blob;
u8 i; u8 i;
int r; int r;
LOG_FUNC_CALLED(ctx); LOG_FUNC_CALLED(ctx);
/* temporary workaround: protect v3 cards against non-RSA */ /* RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA) if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
if (key_info->rsa.keyformat == SC_OPENPGP_KEYFORMAT_RSA_STDN components[0] = key_info->u.rsa.e;
|| key_info->rsa.keyformat == SC_OPENPGP_KEYFORMAT_RSA_CRTN) components[1] = key_info->u.rsa.p;
components[2] = key_info->u.rsa.q;
componentlens[0] = key_info->u.rsa.e_len;
componentlens[1] = key_info->u.rsa.p_len;
componentlens[2] = key_info->u.rsa.q_len;
componenttags[0] = 0x91;
componenttags[1] = 0x92;
componenttags[2] = 0x93;
componentnames[0] = "public exponent";
componentnames[1] = "prime p";
componentnames[2] = "prime q";
comp_to_add = 3;
/* The maximum exponent length is 32 bit, as set on card
* we use this variable to check against actual exponent_len */
size_t max_e_len_bytes = BYTES4BITS(SC_OPENPGP_MAX_EXP_BITS);
size_t e_len_bytes = BYTES4BITS(key_info->u.rsa.e_len);
if (key_info->u.rsa.keyformat == SC_OPENPGP_KEYFORMAT_RSA_STDN
|| key_info->u.rsa.keyformat == SC_OPENPGP_KEYFORMAT_RSA_CRTN){
components[3] = key_info->u.rsa.n;
componentlens[3] = key_info->u.rsa.n_len;
componenttags[3] = 0x97;
componentnames[3] = "modulus";
comp_to_add = 4; comp_to_add = 4;
}
/* validate */ /* validate */
if (comp_to_add == 4 && (key_info->rsa.n == NULL || key_info->rsa.n_len == 0)) if (comp_to_add == 4 && (key_info->u.rsa.n == NULL || key_info->u.rsa.n_len == 0)){
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Modulus required"); sc_log(ctx, "Error: Modulus required!");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
/* Cardholder private key template's data part */ /* Cardholder private key template's data part */
memset(pritemplate, 0, max_prtem_len); memset(pritemplate, 0, max_prtem_len);
/* get required exponent length */ /* maximum 32 bit exponent length allowed on OpenPGP Card */
alat_blob = pgp_find_blob(card, 0x00C0 | key_info->key_id); assert(key_info->u.rsa.e_len <= SC_OPENPGP_MAX_EXP_BITS);
if (alat_blob == NULL)
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND,
"Cannot read Algorithm Attributes");
req_e_len = bebytes2ushort(alat_blob->data + 3) >> 3; /* 1/8 */ /* We need to right justify the exponent with allowed exponent length,
assert(key_info->rsa.e_len <= req_e_len);
/* We need to right justify the exponent with required length,
* e.g. from '01 00 01' to '00 01 00 01' */ * e.g. from '01 00 01' to '00 01 00 01' */
if (key_info->rsa.e_len < req_e_len) { if (key_info->u.rsa.e_len < SC_OPENPGP_MAX_EXP_BITS) {
/* create new buffer */ /* create new buffer */
p = calloc(req_e_len, 1); p = calloc(max_e_len_bytes, 1);
if (p == NULL) if (!p)
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
memcpy(p + req_e_len - key_info->rsa.e_len, key_info->rsa.e, key_info->rsa.e_len);
key_info->rsa.e_len = req_e_len; memcpy(p + (max_e_len_bytes - e_len_bytes), key_info->u.rsa.e, e_len_bytes);
/* set key_info->e to new buffer */ /* set key_info->u.rsa.e to new buffer */
free(key_info->rsa.e); free(key_info->u.rsa.e);
key_info->rsa.e = p; key_info->u.rsa.e = p;
components[0] = p; components[0] = p;
componentlens[0] = req_e_len; key_info->u.rsa.e_len = SC_OPENPGP_MAX_EXP_BITS; /* we store info in bits */
componentlens[0] = max_e_len_bytes; /* ... but in bytes for header list */
} }
}
/* ECC */
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
components[0] = key_info->u.ec.privateD;
componentlens[0] = key_info->u.ec.privateD_len;
componenttags[0] = 0x92;
componentnames[0] = "private key";
comp_to_add = 1;
/* TODO ECC import with public key, if necessary as denoted in algorithm caps*/
/* validate */
if ((key_info->u.ec.ecpoint == NULL || key_info->u.ec.ecpoint_len == 0)){
sc_log(ctx, "Error: ecpoint required!");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
/* Cardholder private key template's data part */
memset(pritemplate, 0, max_prtem_len);
}
else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* start from beginning of pritemplate */ /* start from beginning of pritemplate */
p = pritemplate; p = pritemplate;
@ -2895,8 +3136,9 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
/* temporary workaround: protect v3 cards against non-RSA */ /* protect older cards against non-RSA */
if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA) if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
&& card->type < SC_CARD_TYPE_OPENPGP_V3)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* Validate */ /* Validate */
@ -2905,7 +3147,7 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
"Invalid key ID; must be 1, 2, or 3"); "Invalid key ID; must be 1, 2, or 3");
/* we just support standard key format */ /* we just support standard key format */
switch (key_info->rsa.keyformat) { switch (key_info->u.rsa.keyformat) {
case SC_OPENPGP_KEYFORMAT_RSA_STD: case SC_OPENPGP_KEYFORMAT_RSA_STD:
case SC_OPENPGP_KEYFORMAT_RSA_STDN: case SC_OPENPGP_KEYFORMAT_RSA_STDN:
break; break;
@ -2918,23 +3160,46 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
} }
/* set algorithm attributes */
/* RSA */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){
/* we only support exponent of maximum 32 bits */ /* we only support exponent of maximum 32 bits */
if (key_info->rsa.e_len > 4) { if (key_info->u.rsa.e_len > SC_OPENPGP_MAX_EXP_BITS) {
sc_log(card->ctx, sc_log(card->ctx,
"Exponent %"SC_FORMAT_LEN_SIZE_T"u-bit (>32) is not supported.", "Exponent %"SC_FORMAT_LEN_SIZE_T"u-bit (>32) is not supported.",
key_info->rsa.e_len * 8); key_info->u.rsa.e_len);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
} }
/* set algorithm attributes */
memset(&pubkey, 0, sizeof(pubkey)); memset(&pubkey, 0, sizeof(pubkey));
pubkey.key_id = key_info->key_id; pubkey.key_id = key_info->key_id;
if (key_info->rsa.n && key_info->rsa.n_len) { pubkey.algorithm = key_info->algorithm;
pubkey.rsa.modulus = key_info->rsa.n; if (key_info->u.rsa.n && key_info->u.rsa.n_len
pubkey.rsa.modulus_len = 8*key_info->rsa.n_len; && key_info->u.rsa.e && key_info->u.rsa.e_len) {
/* We won't update exponent length, because smaller exponent length pubkey.u.rsa.modulus = key_info->u.rsa.n;
* will be padded later */ pubkey.u.rsa.modulus_len = key_info->u.rsa.n_len;
pubkey.u.rsa.exponent = key_info->u.rsa.e;
pubkey.u.rsa.exponent_len = key_info->u.rsa.e_len;
} }
else
LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS);
}
/* ECC */
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
memset(&pubkey, 0, sizeof(pubkey));
pubkey.key_id = key_info->key_id;
pubkey.algorithm = key_info->algorithm;
if (key_info->u.ec.ecpoint && key_info->u.ec.ecpoint_len){
pubkey.u.ec.ecpoint = key_info->u.ec.ecpoint;
pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpoint_len;
}
else
LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS);
}
else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
r = pgp_update_new_algo_attr(card, &pubkey); r = pgp_update_new_algo_attr(card, &pubkey);
LOG_TEST_RET(card->ctx, r, "Failed to update new algorithm attributes"); LOG_TEST_RET(card->ctx, r, "Failed to update new algorithm attributes");
@ -2952,15 +3217,13 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
/* calculate and store fingerprint */ /* calculate and store fingerprint */
sc_log(card->ctx, "Calculate and store fingerprint"); sc_log(card->ctx, "Calculate and store fingerprint");
r = pgp_calculate_and_store_fingerprint(card, key_info->creationtime, r = pgp_calculate_and_store_fingerprint(card, key_info->creationtime, &pubkey);
key_info->rsa.n, key_info->rsa.e, &pubkey);
LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint"); LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint");
/* update pubkey blobs (B601,B801, A401) */ /* update pubkey blobs (B601,B801, A401) */
sc_log(card->ctx, "Update blobs holding pubkey info."); sc_log(card->ctx, "Update blobs holding pubkey info.");
r = pgp_update_pubkey_blob(card, key_info->rsa.n, 8*key_info->rsa.n_len, r = pgp_update_pubkey_blob(card, &pubkey);
key_info->rsa.e, 8*key_info->rsa.e_len, key_info->key_id);
sc_log(card->ctx, "Update card algorithms."); sc_log(card->ctx, "Update card algorithms");
pgp_update_card_algorithms(card, &pubkey); pgp_update_card_algorithms(card, &pubkey);
err: err:

View File

@ -944,38 +944,45 @@ typedef struct sc_cardctl_piv_genkey_info_st {
#define SC_OPENPGP_KEY_AUTH 3 #define SC_OPENPGP_KEY_AUTH 3
#define SC_OPENPGP_KEYALGO_RSA 0x01 #define SC_OPENPGP_KEYALGO_RSA 0x01
#define SC_OPENPGP_KEYALGO_ECDH 0x12
#define SC_OPENPGP_KEYALGO_ECDSA 0x13
#define SC_OPENPGP_KEYFORMAT_RSA_STD 0 /* See 4.3.3.6 Algorithm Attributes */ #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 */ #define SC_OPENPGP_KEYFORMAT_RSA_STDN 1 /* OpenPGP card spec v2 */
#define SC_OPENPGP_KEYFORMAT_RSA_CRT 2 #define SC_OPENPGP_KEYFORMAT_RSA_CRT 2
#define SC_OPENPGP_KEYFORMAT_RSA_CRTN 3 #define SC_OPENPGP_KEYFORMAT_RSA_CRTN 3
#define SC_OPENPGP_MAX_EXP_BITS 0x20 /* maximum exponent length supported in bits */
typedef struct sc_cardctl_openpgp_keygen_info { typedef struct sc_cardctl_openpgp_keygen_info {
u8 key_id; /* SC_OPENPGP_KEY_... */ u8 key_id; /* SC_OPENPGP_KEY_... */
u8 algorithm; /* SC_OPENPGP_KEYALGO_... */ u8 algorithm; /* SC_OPENPGP_KEYALGO_... */
union { /* anonymous union */ union {
struct { struct {
u8 *modulus; /* New-generated pubkey info responded from the card */ u8 *modulus; /* New-generated pubkey info responded from the card */
size_t modulus_len; /* Length of modulus in bit */ size_t modulus_len; /* Length of modulus in bit */
u8 *exponent; u8 *exponent;
size_t exponent_len; size_t exponent_len; /* Length of exponent in bit */
u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */ u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */
} rsa; } rsa;
struct { struct {
u8 dummy; /* placeholder */ u8 *ecpoint;
// TODO: replace placeholder with real attributes size_t ecpoint_len;
struct sc_object_id oid;
u8 oid_len;
unsigned int key_length;
} ec; } ec;
}; } u;
} sc_cardctl_openpgp_keygen_info_t; } sc_cardctl_openpgp_keygen_info_t;
typedef struct sc_cardctl_openpgp_keystore_info { typedef struct sc_cardctl_openpgp_keystore_info {
u8 key_id; /* SC_OPENPGP_KEY_... */ u8 key_id; /* SC_OPENPGP_KEY_... */
u8 algorithm; /* SC_OPENPGP_KEYALGO_... */ u8 algorithm; /* SC_OPENPGP_KEYALGO_... */
union { /* anonymous union */ union {
struct { struct {
u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */ u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */
u8 *e; u8 *e;
size_t e_len; size_t e_len; /* Length of exponent in bit */
u8 *p; u8 *p;
size_t p_len; size_t p_len;
u8 *q; u8 *q;
@ -984,10 +991,12 @@ typedef struct sc_cardctl_openpgp_keystore_info {
size_t n_len; size_t n_len;
} rsa; } rsa;
struct { struct {
u8 dummy; /* placeholder */ u8 *privateD;
// TODO: replace placeholder with real attributes size_t privateD_len;
u8 *ecpoint;
size_t ecpoint_len;
} ec; } ec;
}; } u;
time_t creationtime; time_t creationtime;
} sc_cardctl_openpgp_keystore_info_t; } sc_cardctl_openpgp_keystore_info_t;

View File

@ -118,6 +118,8 @@ unsigned short bebytes2ushort(const u8 *buf);
*/ */
unsigned short lebytes2ushort(const u8 *buf); unsigned short lebytes2ushort(const u8 *buf);
#define BYTES4BITS(num) (((num) + 7) / 8) /* number of bytes necessary to hold 'num' bits */
/* Returns an scconf_block entry with matching ATR/ATRmask to the ATR specified, /* Returns an scconf_block entry with matching ATR/ATRmask to the ATR specified,
* NULL otherwise. Additionally, if card driver is not specified, search through * NULL otherwise. Additionally, if card driver is not specified, search through
* all card drivers user configured ATRs. */ * all card drivers user configured ATRs. */

View File

@ -268,20 +268,17 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
sc_pkcs15_prkey_info_t prkey_info; sc_pkcs15_prkey_info_t prkey_info;
sc_pkcs15_object_t prkey_obj; sc_pkcs15_object_t prkey_obj;
u8 cxdata[10]; u8 cxdata[12];
char path_template[] = "006E:0073:00Cx"; char path_template[] = "006E:0073:00Cx";
int j; int j;
memset(&prkey_info, 0, sizeof(prkey_info)); memset(&prkey_info, 0, sizeof(prkey_info));
memset(&prkey_obj, 0, sizeof(prkey_obj)); memset(&prkey_obj, 0, sizeof(prkey_obj));
memset(&cxdata, 0, sizeof(cxdata));
path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */ 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 ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
goto failed; goto failed;
if (r != 6) {
sc_log(ctx, "Key info bytes have unexpected length (expected 6, got %d)\n", r);
return SC_ERROR_INTERNAL;
}
/* check validity using finger prints */ /* check validity using finger prints */
for (j = 19; j >= 0; j--) { for (j = 19; j >= 0; j--) {
@ -296,14 +293,21 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
prkey_info.usage = key_cfg[i].prkey_usage; prkey_info.usage = key_cfg[i].prkey_usage;
prkey_info.native = 1; prkey_info.native = 1;
prkey_info.key_reference = i; prkey_info.key_reference = i;
prkey_info.modulus_length = bebytes2ushort(cxdata + 1);
strlcpy(prkey_obj.label, key_cfg[i].label, sizeof(prkey_obj.label)); strlcpy(prkey_obj.label, key_cfg[i].label, sizeof(prkey_obj.label));
prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE; prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE;
prkey_obj.auth_id.len = 1; prkey_obj.auth_id.len = 1;
prkey_obj.auth_id.value[0] = key_cfg[i].prkey_pin; 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); r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
}
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH
|| cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) {
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
}
if (r < 0) if (r < 0)
return SC_ERROR_INTERNAL; return SC_ERROR_INTERNAL;
} }
@ -318,14 +322,11 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
memset(&pubkey_info, 0, sizeof(pubkey_info)); memset(&pubkey_info, 0, sizeof(pubkey_info));
memset(&pubkey_obj, 0, sizeof(pubkey_obj)); memset(&pubkey_obj, 0, sizeof(pubkey_obj));
memset(&cxdata, 0, sizeof(cxdata));
path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */ 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 ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
goto failed; goto failed;
if (r != 6) {
sc_log(ctx, "Key info bytes have unexpected length (expected 6, got %d)\n", r);
return SC_ERROR_INTERNAL;
}
/* check validity using finger prints */ /* check validity using finger prints */
for (j = 19; j >= 0; j--) { for (j = 19; j >= 0; j--) {
@ -337,14 +338,21 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
if (j >= 0 && cxdata[0] != 0) { if (j >= 0 && cxdata[0] != 0) {
pubkey_info.id.len = 1; pubkey_info.id.len = 1;
pubkey_info.id.value[0] = i + 1; pubkey_info.id.value[0] = i + 1;
pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
pubkey_info.usage = key_cfg[i].pubkey_usage; pubkey_info.usage = key_cfg[i].pubkey_usage;
sc_format_path(key_cfg[i].pubkey_path, &pubkey_info.path); sc_format_path(key_cfg[i].pubkey_path, &pubkey_info.path);
strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label)); strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label));
pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE; 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); r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
}
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH
|| cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) {
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
}
if (r < 0) if (r < 0)
return SC_ERROR_INTERNAL; return SC_ERROR_INTERNAL;
} }

View File

@ -1074,6 +1074,8 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
u8* alg; u8* alg;
size_t alglen; size_t alglen;
LOG_FUNC_CALLED(ctx);
if (!key || !out) { if (!key || !out) {
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
} }
@ -1132,9 +1134,15 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
memcpy(pubkey->u.ec.params.der.value, key->u.ec.params.der.value, key->u.ec.params.der.len); memcpy(pubkey->u.ec.params.der.value, key->u.ec.params.der.value, key->u.ec.params.der.len);
pubkey->u.ec.params.der.len = key->u.ec.params.der.len; pubkey->u.ec.params.der.len = key->u.ec.params.der.len;
if (key->u.ec.params.named_curve){
pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve); pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve);
if (!pubkey->u.ec.params.named_curve) if (!pubkey->u.ec.params.named_curve)
rv = SC_ERROR_OUT_OF_MEMORY; rv = SC_ERROR_OUT_OF_MEMORY;
}
else {
sc_log(ctx, "named_curve parameter missing");
rv = SC_ERROR_NOT_SUPPORTED;
}
break; break;
default: default:
@ -1557,9 +1565,8 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecp
LOG_TEST_RET(ctx, rv, "Cannot encode object ID"); LOG_TEST_RET(ctx, rv, "Cannot encode object ID");
} }
} }
else if (sc_valid_oid(&ecparams->id)) { else
LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "EC parameters has to be presented as a named curve or explicit data"); LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "EC parameters has to be presented as a named curve or explicit data");
}
LOG_FUNC_RETURN(ctx, SC_SUCCESS); LOG_FUNC_RETURN(ctx, SC_SUCCESS);
} }

View File

@ -26,6 +26,7 @@
#include "libopensc/opensc.h" #include "libopensc/opensc.h"
#include "libopensc/cardctl.h" #include "libopensc/cardctl.h"
#include "libopensc/internal.h"
#include "libopensc/log.h" #include "libopensc/log.h"
#include "libopensc/cards.h" #include "libopensc/cards.h"
#include "libopensc/asn1.h" #include "libopensc/asn1.h"
@ -104,7 +105,7 @@ static int openpgp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
} }
/** /**
* Stores an external (RSA) on the card. * Stores an external key on the card.
* @param profile profile information for this card * @param profile profile information for this card
* @param card sc_card_t object to use * @param card sc_card_t object to use
* @param obj sc_pkcs15_object_t object with pkcs15 information * @param obj sc_pkcs15_object_t object with pkcs15 information
@ -116,45 +117,61 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
{ {
sc_card_t *card = p15card->card; sc_card_t *card = p15card->card;
sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
struct sc_pkcs15_prkey_rsa *rsa = &(key->u.rsa);
sc_cardctl_openpgp_keystore_info_t key_info; sc_cardctl_openpgp_keystore_info_t key_info;
int r; int r;
LOG_FUNC_CALLED(card->ctx); LOG_FUNC_CALLED(card->ctx);
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { switch(obj->type)
sc_log(card->ctx, "only RSA is currently supported"); {
return SC_ERROR_NOT_SUPPORTED; case SC_PKCS15_TYPE_PRKEY_RSA:
}
memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t)); memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t));
key_info.key_id = kinfo->id.value[0];
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA; key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
key_info.rsa.e = rsa->exponent.data; key_info.key_id = kinfo->id.value[0];
key_info.rsa.e_len = rsa->exponent.len; key_info.u.rsa.e = key->u.rsa.exponent.data;
key_info.rsa.p = rsa->p.data; key_info.u.rsa.e_len = key->u.rsa.exponent.len * 8; /* use bits instead of bytes */
key_info.rsa.p_len = rsa->p.len; key_info.u.rsa.p = key->u.rsa.p.data;
key_info.rsa.q = rsa->q.data; key_info.u.rsa.p_len = key->u.rsa.p.len;
key_info.rsa.q_len = rsa->q.len; key_info.u.rsa.q = key->u.rsa.q.data;
key_info.rsa.n = rsa->modulus.data; key_info.u.rsa.q_len = key->u.rsa.q.len;
key_info.rsa.n_len = rsa->modulus.len; key_info.u.rsa.n = key->u.rsa.modulus.data;
key_info.u.rsa.n_len = key->u.rsa.modulus.len * 8; /* use bits instead of bytes */
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info); r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
break;
case SC_PKCS15_TYPE_PRKEY_EC:
if (card->type < SC_CARD_TYPE_OPENPGP_V3) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "only RSA is 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_ECDSA; /* ECDSA for slot 1 and 3 */
key_info.key_id = kinfo->id.value[0];
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.ecpoint = key->u.ec.ecpointQ.value;
key_info.u.ec.ecpoint_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));
}
LOG_FUNC_RETURN(card->ctx, r); LOG_FUNC_RETURN(card->ctx, r);
} }
/** /**
* Generates a new (RSA) key pair using an existing key file. * Generates a new RSA key pair on card.
* @param profile IN profile information for this card
* @param card IN sc_card_t object to use * @param card IN sc_card_t object to use
* @param obj IN sc_pkcs15_object_t object with pkcs15 information * @param obj IN sc_pkcs15_object_t object with pkcs15 information
* @param pukkey OUT the newly created public key * @param pukkey OUT the newly created public key
* @return SC_SUCCESS on success and an error code otherwise * @return SC_SUCCESS on success and an error code otherwise
**/ **/
static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, static int openpgp_generate_key_rsa(sc_card_t *card, sc_pkcs15_object_t *obj,
sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) sc_pkcs15_pubkey_t *pubkey)
{ {
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx; sc_context_t *ctx = card->ctx;
sc_cardctl_openpgp_keygen_info_t key_info; sc_cardctl_openpgp_keygen_info_t key_info;
sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data; sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data;
@ -185,46 +202,165 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
} }
/* Prepare buffer */
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA; key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
key_info.rsa.modulus_len = required->modulus_length;
key_info.rsa.modulus = calloc(required->modulus_length >> 3, 1); /* Prepare buffer */
if (key_info.rsa.modulus == NULL) key_info.u.rsa.modulus_len = required->modulus_length;
key_info.u.rsa.modulus = calloc(required->modulus_length >> 3, 1);
if (key_info.u.rsa.modulus == NULL)
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
/* The OpenPGP supports only 32-bit exponent. */ /* The OpenPGP supports only 32-bit exponent. */
key_info.rsa.exponent_len = 32; key_info.u.rsa.exponent_len = 32;
key_info.rsa.exponent = calloc(key_info.rsa.exponent_len>>3, 1); /* 1/8 */ key_info.u.rsa.exponent = calloc(BYTES4BITS(key_info.u.rsa.exponent_len), 1);
if (key_info.rsa.exponent == NULL) { if (key_info.u.rsa.exponent == NULL) {
free(key_info.rsa.modulus); free(key_info.u.rsa.modulus);
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
} }
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info); r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
if (r < 0) LOG_TEST_GOTO_ERR(card->ctx, r, "on-card EC key generation failed");
goto out;
pubkey->algorithm = SC_ALGORITHM_RSA; pubkey->algorithm = SC_ALGORITHM_RSA;
sc_log(ctx, "Set output modulus info"); sc_log(ctx, "Set output modulus info");
pubkey->u.rsa.modulus.len = key_info.rsa.modulus_len; pubkey->u.rsa.modulus.len = key_info.u.rsa.modulus_len;
pubkey->u.rsa.modulus.data = calloc(key_info.rsa.modulus_len, 1); pubkey->u.rsa.modulus.data = calloc(key_info.u.rsa.modulus_len, 1);
if (pubkey->u.rsa.modulus.data == NULL) if (pubkey->u.rsa.modulus.data == NULL)
goto out; goto err;
memcpy(pubkey->u.rsa.modulus.data, key_info.rsa.modulus, key_info.rsa.modulus_len); memcpy(pubkey->u.rsa.modulus.data, key_info.u.rsa.modulus, key_info.u.rsa.modulus_len);
sc_log(ctx, "Set output exponent info"); sc_log(ctx, "Set output exponent info");
pubkey->u.rsa.exponent.len = key_info.rsa.exponent_len; pubkey->u.rsa.exponent.len = key_info.u.rsa.exponent_len;
pubkey->u.rsa.exponent.data = calloc(key_info.rsa.exponent_len>>3, 1); /* 1/8 */ pubkey->u.rsa.exponent.data = calloc(BYTES4BITS(key_info.u.rsa.exponent_len), 1);
if (pubkey->u.rsa.exponent.data == NULL) if (pubkey->u.rsa.exponent.data == NULL)
goto out; goto err;
memcpy(pubkey->u.rsa.exponent.data, key_info.rsa.exponent, key_info.rsa.exponent_len>>3); /* 1/8 */ memcpy(pubkey->u.rsa.exponent.data, key_info.u.rsa.exponent, BYTES4BITS(key_info.u.rsa.exponent_len));
err:
free(key_info.u.rsa.modulus);
free(key_info.u.rsa.exponent);
LOG_FUNC_RETURN(ctx, r);
}
/**
* Generates a new ECC key pair on card.
* @param card IN sc_card_t object to use
* @param obj IN sc_pkcs15_object_t object with pkcs15 information
* @param pukkey OUT the newly created public key
* @return SC_SUCCESS on success and an error code otherwise
**/
static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj,
sc_pkcs15_pubkey_t *pubkey)
{
sc_context_t *ctx = card->ctx;
sc_cardctl_openpgp_keygen_info_t key_info;
sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data;
sc_pkcs15_id_t *kid = &(required->id);
const struct sc_ec_parameters *info_ec =
(struct sc_ec_parameters *) required->params.data;
unsigned int i;
int r;
LOG_FUNC_CALLED(ctx);
memset(&key_info, 0, sizeof(key_info));
sc_log(ctx, "Key ID to be generated: %s", sc_dump_hex(kid->value, kid->len));
/* Accept KeyID = 45, which is default value set by pkcs15init */
if (kid->len == 1 && kid->value[0] == 0x45) {
/* Default key is authentication key. We choose this because the common use
* is to generate from PKCS#11 (Firefox/Thunderbird) */
sc_log(ctx, "Authentication key is to be generated.");
key_info.key_id = 3;
}
if (!key_info.key_id && (kid->len > 1 || kid->value[0] > 3)) {
sc_log(ctx, "Key ID must be 1, 2 or 3!");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
if (!key_info.key_id)
key_info.key_id = kid->value[0];
/* set algorithm id based on key reference */
key_info.algorithm = (key_info.key_id == SC_OPENPGP_KEY_ENCR)
? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */
: SC_OPENPGP_KEYALGO_ECDSA; /* ECDSA for slot 1 and 3 */
/* extract oid the way we need to import it to OpenPGP Card */
if (info_ec->der.len > 2)
key_info.u.ec.oid_len = info_ec->der.value[1];
else
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
for (i=0; (i < key_info.u.ec.oid_len) && (i+2 < info_ec->der.len); i++){
key_info.u.ec.oid.value[i] = info_ec->der.value[i+2];
}
key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1;
/* Prepare buffer */
key_info.u.ec.ecpoint_len = required->field_length;
key_info.u.ec.ecpoint = malloc(key_info.u.ec.ecpoint_len);
if (key_info.u.ec.ecpoint == NULL)
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
/* generate key on card */
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
LOG_TEST_GOTO_ERR(card->ctx, r, "on-card EC key generation failed");
/* set pubkey according to response of card */
sc_log(ctx, "Set output ecpoint info");
pubkey->algorithm = SC_ALGORITHM_EC;
pubkey->u.ec.ecpointQ.len = key_info.u.ec.ecpoint_len;
pubkey->u.ec.ecpointQ.value = malloc(key_info.u.ec.ecpoint_len);
if (pubkey->u.ec.ecpointQ.value == NULL)
goto err;
memcpy(pubkey->u.ec.ecpointQ.value, key_info.u.ec.ecpoint, key_info.u.ec.ecpoint_len);
err:
if (key_info.u.ec.ecpoint)
free(key_info.u.ec.ecpoint);
LOG_FUNC_RETURN(ctx, r);
}
/**
* Generates a new key pair using an existing key file.
* @param profile IN profile information for this card
* @param card IN sc_card_t object to use
* @param obj IN sc_pkcs15_object_t object with pkcs15 information
* @param pukkey OUT the newly created public key
* @return SC_SUCCESS on success and an error code otherwise
**/
static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
{
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
int r;
LOG_FUNC_CALLED(ctx);
switch(obj->type)
{
case SC_PKCS15_TYPE_PRKEY_RSA:
r = openpgp_generate_key_rsa(card, obj, pubkey);
break;
case SC_PKCS15_TYPE_PRKEY_EC:
if (card->type < SC_CARD_TYPE_OPENPGP_V3) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "only RSA is 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));
}
out:
if (key_info.rsa.modulus)
free(key_info.rsa.modulus);
if (key_info.rsa.exponent)
free(key_info.rsa.exponent);
LOG_FUNC_RETURN(ctx, r); LOG_FUNC_RETURN(ctx, r);
} }

View File

@ -41,6 +41,7 @@
#include "libopensc/opensc.h" #include "libopensc/opensc.h"
#include "libopensc/asn1.h" #include "libopensc/asn1.h"
#include "libopensc/cards.h" #include "libopensc/cards.h"
#include "libopensc/internal.h"
#include "libopensc/cardctl.h" #include "libopensc/cardctl.h"
#include "libopensc/log.h" #include "libopensc/log.h"
#include "libopensc/errors.h" #include "libopensc/errors.h"
@ -703,11 +704,11 @@ int do_genkey(sc_card_t *card, u8 in_key_id, const char *keytype)
/* set key_info */ /* set key_info */
key_info.key_id = in_key_id; key_info.key_id = in_key_id;
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA; key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
key_info.rsa.modulus_len = keylen; key_info.u.rsa.modulus_len = keylen;
key_info.rsa.modulus = malloc((keylen + 7) / 8); key_info.u.rsa.modulus = malloc(BYTES4BITS(keylen));
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info); r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
free(key_info.rsa.modulus); free(key_info.u.rsa.modulus);
if (r < 0) { if (r < 0) {
util_error("failed to generate key: %s", sc_strerror(r)); util_error("failed to generate key: %s", sc_strerror(r));
return EXIT_FAILURE; return EXIT_FAILURE;