From fccc42295dea04fcf8d3df7adef2faaa53007c78 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Fri, 5 Jan 2018 11:08:14 +0100 Subject: [PATCH] OpenPGP: Added basic support for OpenPGP card V3 partially implements https://github.com/OpenSC/OpenSC/issues/1215 Refactored OpenPGP code so that future versions of the card will be accessed using the logic for OpenPGP V2. We hope that backward compatibility of the standard will keep the new versions functional. --- src/libopensc/card-openpgp.c | 75 ++++++++++++++++++++-------------- src/libopensc/cards.h | 1 + src/libopensc/pkcs15-openpgp.c | 11 +++-- src/tools/openpgp-tool.c | 16 +++----- 4 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index 177f9e3b..94a48320 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -49,6 +49,7 @@ static struct sc_atr_table pgp_atrs[] = { { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, "CryptoStick v1.2 (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, { "3b:da:11:ff:81:b1:fe:55:1f:03:00:31:84:73:80:01:80:00:90:00:e4", NULL, "Gnuk v1.0.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL }, { "3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1", NULL, "Yubikey NEO (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, + { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:f5:73:c0:01:60:00:90:00:1c", NULL, "OpenPGP card V3", SC_CARD_TYPE_OPENPGP_V3, 0, NULL }, { NULL, NULL, NULL, 0, 0, NULL } }; @@ -332,7 +333,6 @@ pgp_match_card(sc_card_t *card) } else { sc_path_t partial_aid; - unsigned char aid[16]; sc_file_t *file = NULL; /* select application "OpenPGP" */ @@ -340,26 +340,28 @@ pgp_match_card(sc_card_t *card) partial_aid.type = SC_PATH_TYPE_DF_NAME; /* OpenPGP card only supports selection *with* requested FCI */ i = iso_ops->select_file(card, &partial_aid, &file); - sc_file_free(file); if (SC_SUCCESS == i) { - /* read information from AID */ - i = sc_get_data(card, 0x004F, aid, sizeof aid); - if (i == 16) { - switch ((aid[6] << 8) | aid[7]) { /* BCD-coded bytes */ - case 0x0101: - card->type = SC_CARD_TYPE_OPENPGP_V1; - sc_log(card->ctx, "OpenPGPv1-type card found"); - return 1; - case 0x0200: - case 0x0201: - card->type = SC_CARD_TYPE_OPENPGP_V2; - sc_log(card->ctx, "OpenPGPv2-type card found"); - return 1; - default: - sc_log(card->ctx, "unsupported OpenPGP-type card found"); - /* fall through */ + static char card_name[SC_MAX_APDU_BUFFER_SIZE] = "OpenPGP card"; + card->type = SC_CARD_TYPE_OPENPGP_BASE; + card->name = card_name; + if (file->namelen == 16) { + unsigned char major = file->name[6]; + unsigned char minor = file->name[7]; + switch (major) { + case 1: + card->type = SC_CARD_TYPE_OPENPGP_V1; + break; + case 2: + card->type = SC_CARD_TYPE_OPENPGP_V2; + break; + case 3: + card->type = SC_CARD_TYPE_OPENPGP_V3; + break; } + snprintf(card_name, sizeof card_name, "OpenPGP card V%u.%u", major, minor); } + sc_file_free(file); + return 1; } } return 0; @@ -390,14 +392,6 @@ pgp_init(sc_card_t *card) card->cla = 0x00; - /* set pointer to correct list of card objects */ - priv->pgp_objects = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK) - ? pgp2_objects : pgp1_objects; - - /* set detailed card version */ - priv->bcd_version = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK) - ? OPENPGP_CARD_2_0 : OPENPGP_CARD_1_1; - /* select application "OpenPGP" */ sc_format_path("D276:0001:2401", &aid); aid.type = SC_PATH_TYPE_DF_NAME; @@ -432,6 +426,27 @@ pgp_init(sc_card_t *card) /* kludge: get card's serial number from manufacturer ID + serial number */ memcpy(card->serialnr.value, file->name + 8, 6); card->serialnr.len = 6; + } else { + /* set detailed card version */ + switch (card->type) { + case SC_CARD_TYPE_OPENPGP_V3: + priv->bcd_version = OPENPGP_CARD_3_0; + break; + case SC_CARD_TYPE_OPENPGP_GNUK: + case SC_CARD_TYPE_OPENPGP_V2: + priv->bcd_version = OPENPGP_CARD_2_0; + break; + default: + priv->bcd_version = OPENPGP_CARD_1_1; + break; + } + } + + /* set pointer to correct list of card objects */ + if (priv->bcd_version < OPENPGP_CARD_2_0) { + priv->pgp_objects = pgp1_objects; + } else { + priv->pgp_objects = pgp2_objects; } /* change file path to MF for re-use in MF */ @@ -527,9 +542,9 @@ pgp_get_card_features(sc_card_t *card) /* get "extended capabilities" DO */ if ((pgp_get_blob(card, blob73, 0x00c0, &blob) >= 0) && (blob->data != NULL) && (blob->len > 0)) { - /* in v2.0 bit 0x04 in first byte means "algorithm attributes changeable */ + /* in v2.0 bit 0x04 in first byte means "algorithm attributes changeable" */ if ((blob->data[0] & 0x04) && - (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)) + (priv->bcd_version >= OPENPGP_CARD_2_0)) priv->ext_caps |= EXT_CAP_ALG_ATTR_CHANGEABLE; /* bit 0x08 in first byte means "support for private use DOs" */ if (blob->data[0] & 0x08) @@ -547,7 +562,7 @@ pgp_get_card_features(sc_card_t *card) } /* in v2.0 bit 0x80 in first byte means "support Secure Messaging" */ if ((blob->data[0] & 0x80) && - (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)) + (priv->bcd_version >= OPENPGP_CARD_2_0)) priv->ext_caps |= EXT_CAP_SM; if ((priv->bcd_version >= OPENPGP_CARD_2_0) && (blob->len >= 10)) { @@ -993,7 +1008,7 @@ pgp_seek_blob(sc_card_t *card, pgp_blob_t *root, unsigned int id, for (child = root->files; child; child = child->next) { /* The DO of SIMPLE type or the DO holding certificate * does not contain children */ - if (child->info->type == SIMPLE || child->id == DO_CERT) + if ((child->info && child->info->type == SIMPLE) || child->id == DO_CERT) continue; r = pgp_seek_blob(card, child, id, ret); if (r == 0) diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index 0cc7650e..41514532 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -106,6 +106,7 @@ enum { SC_CARD_TYPE_OPENPGP_BASE = 9000, SC_CARD_TYPE_OPENPGP_V1, SC_CARD_TYPE_OPENPGP_V2, + SC_CARD_TYPE_OPENPGP_V3, SC_CARD_TYPE_OPENPGP_GNUK, /* jcop driver */ diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c index 2505e079..26077d52 100644 --- a/src/libopensc/pkcs15-openpgp.c +++ b/src/libopensc/pkcs15-openpgp.c @@ -159,8 +159,8 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card) u8 c4data[10]; u8 c5data[70]; int r, i; - const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK) - ? pin_cfg_v2 : pin_cfg_v1; + const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V1) + ? pin_cfg_v1 : pin_cfg_v2; sc_path_t path; sc_file_t *file; @@ -430,8 +430,11 @@ sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *p15card) static int openpgp_detect_card(sc_pkcs15_card_t *p15card) { - if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2 - || p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK) + if (p15card->card->type == SC_CARD_TYPE_OPENPGP_BASE + || p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 + || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2 + || p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK + || p15card->card->type == SC_CARD_TYPE_OPENPGP_V3) return SC_SUCCESS; else return SC_ERROR_WRONG_CARD; diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c index 53bc5b64..86664d18 100644 --- a/src/tools/openpgp-tool.c +++ b/src/tools/openpgp-tool.c @@ -572,14 +572,8 @@ int do_delete_key(sc_card_t *card, u8 key_id) int do_erase(sc_card_t *card) { - int r; - /* Check card version */ - if (card->type != SC_CARD_TYPE_OPENPGP_V2) { - printf("Do not erase card which is not OpenPGP v2\n"); - } printf("Erase card\n"); - r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); - return r; + return sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); } int main(int argc, char **argv) @@ -619,9 +613,11 @@ int main(int argc, char **argv) } /* check card type */ - if ((card->type != SC_CARD_TYPE_OPENPGP_V1) && - (card->type != SC_CARD_TYPE_OPENPGP_V2) && - (card->type != SC_CARD_TYPE_OPENPGP_GNUK)) { + if ((card->type != SC_CARD_TYPE_OPENPGP_BASE) && + (card->type != SC_CARD_TYPE_OPENPGP_V1) && + (card->type != SC_CARD_TYPE_OPENPGP_V2) && + (card->type != SC_CARD_TYPE_OPENPGP_V3) && + (card->type != SC_CARD_TYPE_OPENPGP_GNUK)) { util_error("not an OpenPGP card"); fprintf(stderr, "Card type %X\n", card->type); exit_status = EXIT_FAILURE;