From cd4dc5a9e7de69c1bdcaeca0ebd2924caf239ef5 Mon Sep 17 00:00:00 2001 From: Peter Marschall Date: Sun, 26 Jan 2020 10:56:03 +0100 Subject: [PATCH] OpenPGP: refactor definitions into header file Factor out constants and structure definitions into a header file so that they can be also used consistently in openpgp-tool. --- src/libopensc/Makefile.am | 3 +- src/libopensc/card-openpgp.c | 216 ++++++----------------------------- src/libopensc/card-openpgp.h | 192 +++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+), 184 deletions(-) create mode 100644 src/libopensc/card-openpgp.h diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 49d12268..2d7b4c95 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -12,7 +12,8 @@ noinst_HEADERS = cards.h ctbcs.h internal.h muscle.h muscle-filesystem.h \ errors.h types.h compression.h itacns.h iso7816.h \ authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \ pace.h cwa14890.h cwa-dnie.h card-gids.h aux-data.h \ - jpki.h sc-ossl-compat.h card-npa.h ccid-types.h reader-tr03119.h \ + jpki.h sc-ossl-compat.h card-npa.h card-openpgp.h \ + ccid-types.h reader-tr03119.h \ card-cac-common.h AM_CPPFLAGS = -D'OPENSC_CONF_PATH="$(sysconfdir)/opensc.conf"' \ diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index 35230ac5..2ca29a9f 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -52,11 +52,15 @@ #include #endif /* ENABLE_OPENSSL */ +#include "card-openpgp.h" + + static const char default_cardname[] = "OpenPGP card"; static const char default_cardname_v1[] = "OpenPGP card v1.x"; static const char default_cardname_v2[] = "OpenPGP card v2.x"; static const char default_cardname_v3[] = "OpenPGP card v3.x"; + static const struct sc_atr_table pgp_atrs[] = { { "3b:fa:13:00:ff:81:31:80:45:00:31:c1:73:c0:01:00:00:90:00:b1", NULL, default_cardname_v1, SC_CARD_TYPE_OPENPGP_V1, 0, NULL }, { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, default_cardname_v2, SC_CARD_TYPE_OPENPGP_V2, 0, NULL }, @@ -72,6 +76,7 @@ static const struct sc_atr_table pgp_atrs[] = { { NULL, NULL, NULL, 0, 0, NULL } }; + static struct sc_card_operations *iso_ops; static struct sc_card_operations pgp_ops; static struct sc_card_driver pgp_drv = { @@ -81,84 +86,8 @@ static struct sc_card_driver pgp_drv = { NULL, 0, NULL }; -/* - * The OpenPGP card doesn't have a file system, instead everything - * is stored in data objects that are accessed through GET/PUT. - * - * However, much inside OpenSC's pkcs15 implementation is based on - * the assumption that we have a file system. So we fake one here. - * - * Selecting the MF causes us to select the OpenPGP AID. - * - * Everything else is mapped to "file" IDs. - */ -enum _type { /* DO type */ - SIMPLE = SC_FILE_TYPE_WORKING_EF, - CONSTRUCTED = SC_FILE_TYPE_DF -}; - -enum _version { /* 2-byte BCD-alike encoded version number */ - OPENPGP_CARD_1_0 = 0x0100, - OPENPGP_CARD_1_1 = 0x0101, - OPENPGP_CARD_2_0 = 0x0200, - OPENPGP_CARD_2_1 = 0x0201, - OPENPGP_CARD_2_2 = 0x0202, - OPENPGP_CARD_3_0 = 0x0300, - OPENPGP_CARD_3_1 = 0x0301, - OPENPGP_CARD_3_2 = 0x0302, - OPENPGP_CARD_3_3 = 0x0303, - OPENPGP_CARD_3_4 = 0x0304, -}; - -enum _access { /* access flags for the respective DO/file */ - READ_NEVER = 0x0010, - READ_PIN1 = 0x0011, - READ_PIN2 = 0x0012, - READ_PIN3 = 0x0014, - READ_ALWAYS = 0x0018, - READ_MASK = 0x00FF, - WRITE_NEVER = 0x1000, - WRITE_PIN1 = 0x1100, - WRITE_PIN2 = 0x1200, - WRITE_PIN3 = 0x1400, - WRITE_ALWAYS = 0x1800, - WRITE_MASK = 0x1F00 -}; - -enum _ext_caps { /* extended capabilities/features: bit flags */ - EXT_CAP_ALG_ATTR_CHANGEABLE = 0x0004, - EXT_CAP_PRIVATE_DO = 0x0008, - EXT_CAP_C4_CHANGEABLE = 0x0010, - EXT_CAP_KEY_IMPORT = 0x0020, - EXT_CAP_GET_CHALLENGE = 0x0040, - EXT_CAP_SM = 0x0080, - EXT_CAP_LCS = 0x0100, - EXT_CAP_CHAINING = 0x1000, - EXT_CAP_APDU_EXT = 0x2000, - EXT_CAP_MSE = 0x4000 -}; - -enum _card_state { - CARD_STATE_UNKNOWN = 0x00, - CARD_STATE_INITIALIZATION = 0x03, - CARD_STATE_ACTIVATED = 0x05 -}; - -enum _sm_algo { - SM_ALGO_NONE = 0, /* SM not supported */ - SM_ALGO_AES128 = 1, - SM_ALGO_AES256 = 2, - SM_ALGO_SCP11b = 3, - SM_ALGO_3DES = 256, /* 2.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[] = { +static pgp_ec_curves_t 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, @@ -174,11 +103,7 @@ static struct pgp_supported_ec_curves { {{{-1}}, 0, {{0x0}}} /* This entry must not be touched. */ }; -static struct pgp_supported_ec_curves_gnuk { - struct sc_object_id oid; - size_t size; - struct sc_object_id oid_binary; -} ec_curves_gnuk[] = { +static pgp_ec_curves_t ec_curves_gnuk[] = { {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, {{0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, -1}}}, /* ansiX9p256r1 */ {{{1, 3, 132, 0, 10, -1}}, 256, @@ -190,33 +115,18 @@ static struct pgp_supported_ec_curves_gnuk { {{{-1}}, 0, {{0x0}}} /* This entry must not be touched. */ }; -typedef struct pgp_blob { - struct pgp_blob * next; /* pointer to next sibling */ - struct pgp_blob * parent; /* pointer to parent */ - struct do_info *info; - sc_file_t * file; - unsigned int id; - int status; - - unsigned char * data; - unsigned int len; - struct pgp_blob * files; /* pointer to 1st child */ -} pgp_blob_t; - -struct do_info { - unsigned int id; /* ID of the DO in question */ - - enum _type type; /* constructed DO or not */ - enum _access access; /* R/W access levels for the DO */ - - /* function to get the DO from the card: - * only != NULL is DO if readable and not only a part of a constructed DO */ - int (*get_fn)(sc_card_t *, unsigned int, u8 *, size_t); - /* function to write the DO to the card: - * only != NULL if DO is writeable under some conditions */ - int (*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t); -}; +/* + * The OpenPGP card doesn't have a file system, instead everything + * is stored in data objects that are accessed through GET/PUT. + * + * However, much inside OpenSC's pkcs15 implementation is based on + * the assumption that we have a file system. So we fake one here. + * + * Selecting the MF causes us to select the OpenPGP AID. + * + * Everything else is mapped to "file" IDs. + */ static int pgp_get_card_features(sc_card_t *card); static int pgp_finish(sc_card_t *card); @@ -224,50 +134,13 @@ static void pgp_iterate_blobs(pgp_blob_t *, int, void (*func)()); static int pgp_get_blob(sc_card_t *card, pgp_blob_t *blob, unsigned int id, pgp_blob_t **ret); -static pgp_blob_t * pgp_new_blob(sc_card_t *, pgp_blob_t *, unsigned int, sc_file_t *); +static pgp_blob_t *pgp_new_blob(sc_card_t *, pgp_blob_t *, unsigned int, sc_file_t *); static void pgp_free_blob(pgp_blob_t *); -static int pgp_get_pubkey(sc_card_t *, unsigned int, - u8 *, size_t); -static int pgp_get_pubkey_pem(sc_card_t *, unsigned int, - u8 *, size_t); - -/* The DO holding X.509 certificate is constructed but does not contain a child DO. - * We should notice this when building fake file system later. */ -#define DO_CERT 0x7f21 -/* Control Reference Template of private keys. Ref: Section 4.3.3.7 of OpenPGP card v2 spec. - * Here we treat them as DOs just for convenience */ -#define DO_SIGN 0xb600 -#define DO_ENCR 0xb800 -#define DO_AUTH 0xa400 -/* These DOs do not exist. They are defined and used just for ease of implementation */ -#define DO_SIGN_SYM 0xb601 -#define DO_ENCR_SYM 0xb801 -#define DO_AUTH_SYM 0xa401 -/* Private DOs */ -#define DO_PRIV1 0x0101 -#define DO_PRIV2 0x0102 -#define DO_PRIV3 0x0103 -#define DO_PRIV4 0x0104 -/* Cardholder information DOs */ -#define DO_CARDHOLDER 0x65 -#define DO_NAME 0x5b -#define DO_LANG_PREF 0x5f2d -#define DO_SEX 0x5f35 +static int pgp_get_pubkey(sc_card_t *, unsigned int, u8 *, size_t); +static int pgp_get_pubkey_pem(sc_card_t *, unsigned int, u8 *, size_t); -/* Maximum length for response buffer when reading pubkey. - * This value is calculated with 4096-bit key length */ -#define MAXLEN_RESP_PUBKEY 527 -/* Gnuk only supports 1 key length (2048 bit) */ -#define MAXLEN_RESP_PUBKEY_GNUK 271 - -/* Maximal size of a DO: - * v2.0+: max. certificate size it at bytes 5-6 of Extended Capabilities DO 00C0 - * v3.0+: max. special DO size is at bytes 7-8 of Extended Capabilities DO 00C0 - * Theoretically we should have the 64k, but we currently limit to 8k. */ -#define MAX_OPENPGP_DO_SIZE 8192 - -static struct do_info pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ +static pgp_do_info_t pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ { 0x004f, SIMPLE, READ_ALWAYS | WRITE_NEVER, NULL, NULL }, { 0x005b, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x005e, SIMPLE, READ_ALWAYS | WRITE_PIN3, sc_get_data, sc_put_data }, @@ -316,7 +189,7 @@ static struct do_info pgp1x_objects[] = { /* OpenPGP card spec 1.1 */ { 0, 0, 0, NULL, NULL }, }; -static struct do_info pgp34_objects[] = { /**** OpenPGP card spec 3.4 ****/ +static pgp_do_info_t pgp34_objects[] = { /**** OpenPGP card spec 3.4 ****/ { 0x00d9, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x00da, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, { 0x00db, SIMPLE, READ_ALWAYS | WRITE_PIN3, NULL, sc_put_data }, @@ -400,31 +273,10 @@ static struct do_info pgp34_objects[] = { /**** OpenPGP card spec 3.4 ****/ { 0, 0, 0, NULL, NULL }, }; -static struct do_info *pgp33_objects = pgp34_objects + 9; -static struct do_info *pgp30_objects = pgp34_objects + 10; -static struct do_info *pgp21_objects = pgp34_objects + 15; -static struct do_info *pgp20_objects = pgp34_objects + 16; - - -#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data)) - -struct pgp_priv_data { - pgp_blob_t *mf; - pgp_blob_t *current; /* currently selected file */ - - enum _version bcd_version; - struct do_info *pgp_objects; - - enum _card_state state; /* card state */ - enum _ext_caps ext_caps; /* extended capabilities */ - - enum _sm_algo sm_algo; /* Secure Messaging algorithm */ - - size_t max_challenge_size; - size_t max_cert_size; - - sc_security_env_t sec_env; -}; +static pgp_do_info_t *pgp33_objects = pgp34_objects + 9; +static pgp_do_info_t *pgp30_objects = pgp34_objects + 10; +static pgp_do_info_t *pgp21_objects = pgp34_objects + 15; +static pgp_do_info_t *pgp20_objects = pgp34_objects + 16; /** @@ -445,8 +297,6 @@ get_full_pgp_aid(sc_card_t *card, sc_file_t *file) } -#define BCD2UCHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F)) - /** * ABI: check if card's ATR matches one of driver's * or if the OpenPGP application is present on the card. @@ -515,7 +365,7 @@ pgp_init(sc_card_t *card) struct pgp_priv_data *priv; sc_path_t path; sc_file_t *file = NULL; - struct do_info *info; + pgp_do_info_t *info; int r, i; LOG_FUNC_CALLED(card->ctx); @@ -1019,7 +869,7 @@ pgp_set_blob(pgp_blob_t *blob, const u8 *data, size_t len) * The Access Control is derived from the DO access permission. **/ static void -pgp_attach_acl(sc_card_t *card, sc_file_t *file, struct do_info *info) +pgp_attach_acl(sc_card_t *card, sc_file_t *file, pgp_do_info_t *info) { unsigned int method = SC_AC_NONE; unsigned long key_ref = SC_AC_KEY_REF_NONE; @@ -1096,7 +946,7 @@ pgp_new_blob(sc_card_t *card, pgp_blob_t *parent, unsigned int file_id, if ((blob = calloc(1, sizeof(pgp_blob_t))) != NULL) { struct pgp_priv_data *priv = DRVDATA(card); - struct do_info *info; + pgp_do_info_t *info; blob->file = file; @@ -1406,11 +1256,11 @@ pgp_find_blob(sc_card_t *card, unsigned int tag) /** * Internal: get info for a specific tag. */ -static struct do_info * +static pgp_do_info_t * pgp_get_info_by_tag(sc_card_t *card, unsigned int tag) { struct pgp_priv_data *priv = DRVDATA(card); - struct do_info *info; + pgp_do_info_t *info; for (info = priv->pgp_objects; (info != NULL) && (info->id > 0); info++) if (tag == info->id) @@ -1876,7 +1726,7 @@ pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len) { struct pgp_priv_data *priv = DRVDATA(card); pgp_blob_t *affected_blob = NULL; - struct do_info *dinfo = NULL; + pgp_do_info_t *dinfo = NULL; int r; LOG_FUNC_CALLED(card->ctx); diff --git a/src/libopensc/card-openpgp.h b/src/libopensc/card-openpgp.h new file mode 100644 index 00000000..f13e3be6 --- /dev/null +++ b/src/libopensc/card-openpgp.h @@ -0,0 +1,192 @@ +/* + * card-openpgp.h: Support for OpenPGP card + * + * Copyright (C) 2020 Peter Marschall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CARD_OPENPGP_H +#define _CARD_OPENPGP_H + +/* + * The OpenPGP card doesn't have a file system, instead everything + * is stored in data objects that are accessed through GET/PUT. + * + * However, much inside OpenSC's pkcs15 implementation is based on + * the assumption that we have a file system. So we fake one here. + * + * Selecting the MF causes us to select the OpenPGP AID. + * + * Everything else is mapped to "file" IDs. + */ + +typedef enum _pgp_do_type { /* DO type */ + SIMPLE = SC_FILE_TYPE_WORKING_EF, + CONSTRUCTED = SC_FILE_TYPE_DF +} pgp_do_type_t; + +typedef enum _pgp_version { /* 2-byte BCD-alike encoded version number */ + OPENPGP_CARD_1_0 = 0x0100, + OPENPGP_CARD_1_1 = 0x0101, + OPENPGP_CARD_2_0 = 0x0200, + OPENPGP_CARD_2_1 = 0x0201, + OPENPGP_CARD_2_2 = 0x0202, + OPENPGP_CARD_3_0 = 0x0300, + OPENPGP_CARD_3_1 = 0x0301, + OPENPGP_CARD_3_2 = 0x0302, + OPENPGP_CARD_3_3 = 0x0303, + OPENPGP_CARD_3_4 = 0x0304, +} pgp_version_t; + +typedef enum _pgp_access { /* access flags for the respective DO/file */ + READ_NEVER = 0x0010, + READ_PIN1 = 0x0011, + READ_PIN2 = 0x0012, + READ_PIN3 = 0x0014, + READ_ALWAYS = 0x0018, + READ_MASK = 0x00FF, + WRITE_NEVER = 0x1000, + WRITE_PIN1 = 0x1100, + WRITE_PIN2 = 0x1200, + WRITE_PIN3 = 0x1400, + WRITE_ALWAYS = 0x1800, + WRITE_MASK = 0x1F00 +} pgp_access_t; + +typedef enum _pgp_ext_caps { /* extended capabilities/features: bit flags */ + EXT_CAP_ALG_ATTR_CHANGEABLE = 0x0004, + EXT_CAP_PRIVATE_DO = 0x0008, + EXT_CAP_C4_CHANGEABLE = 0x0010, + EXT_CAP_KEY_IMPORT = 0x0020, + EXT_CAP_GET_CHALLENGE = 0x0040, + EXT_CAP_SM = 0x0080, + EXT_CAP_LCS = 0x0100, + EXT_CAP_CHAINING = 0x1000, + EXT_CAP_APDU_EXT = 0x2000, + EXT_CAP_MSE = 0x4000 +} pgp_ext_caps_t; + +typedef enum _pgp_card_state { + CARD_STATE_UNKNOWN = 0x00, + CARD_STATE_INITIALIZATION = 0x03, + CARD_STATE_ACTIVATED = 0x05 +} pgp_card_state_t; + +typedef enum _pgp_sm_algo { + SM_ALGO_NONE = 0, /* SM not supported */ + SM_ALGO_AES128 = 1, + SM_ALGO_AES256 = 2, + SM_ALGO_SCP11b = 3, + SM_ALGO_3DES = 256, /* 2.x: coded as 0 in DO C0 */ + SM_ALGO_UNKNOWN = 257 /* 3.x: coded as 0 in DO C0 */ +} pgp_sm_algo_t; + +typedef struct _pgp_do_info { + unsigned int id; /* ID of the DO in question */ + + pgp_do_type_t type; /* constructed DO or not */ + pgp_access_t access; /* R/W access levels for the DO */ + + /* function to get the DO from the card: + * only != NULL is DO if readable and not only a part of a constructed DO */ + int (*get_fn)(sc_card_t *, unsigned int, u8 *, size_t); + /* function to write the DO to the card: + * only != NULL if DO is writeable under some conditions */ + int (*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t); +} pgp_do_info_t; + +typedef struct pgp_blob { + struct pgp_blob *next; /* pointer to next sibling */ + struct pgp_blob *parent; /* pointer to parent */ + pgp_do_info_t *info; + + sc_file_t *file; + unsigned int id; + int status; + + unsigned char *data; + unsigned int len; + struct pgp_blob *files; /* pointer to 1st child */ +} pgp_blob_t; + + +/* The DO holding X.509 certificate is constructed but does not contain a child DO. + * We should notice this when building fake file system later. */ +#define DO_CERT 0x7f21 +/* Control Reference Template of private keys. Ref: Section 4.3.3.7 of OpenPGP card v2 spec. + * Here we treat them as DOs just for convenience */ +#define DO_SIGN 0xb600 +#define DO_ENCR 0xb800 +#define DO_AUTH 0xa400 +/* These DOs do not exist. They are defined and used just for ease of implementation */ +#define DO_SIGN_SYM 0xb601 +#define DO_ENCR_SYM 0xb801 +#define DO_AUTH_SYM 0xa401 +/* Private DOs */ +#define DO_PRIV1 0x0101 +#define DO_PRIV2 0x0102 +#define DO_PRIV3 0x0103 +#define DO_PRIV4 0x0104 +/* Cardholder information DOs */ +#define DO_CARDHOLDER 0x65 +#define DO_NAME 0x5b +#define DO_LANG_PREF 0x5f2d +#define DO_SEX 0x5f35 + + +/* Maximum length for response buffer when reading pubkey. + * This value is calculated with 4096-bit key length */ +#define MAXLEN_RESP_PUBKEY 527 +/* Gnuk only supports 1 key length (2048 bit) */ +#define MAXLEN_RESP_PUBKEY_GNUK 271 + +/* Maximal size of a DO: + * v2.0+: max. certificate size it at bytes 5-6 of Extended Capabilities DO 00C0 + * v3.0+: max. special DO size is at bytes 7-8 of Extended Capabilities DO 00C0 + * Theoretically we should have the 64k, but we currently limit to 8k. */ +#define MAX_OPENPGP_DO_SIZE 8192 + + +typedef struct _pgp_ec_curves { + struct sc_object_id oid; + size_t size; + struct sc_object_id oid_binary; +} pgp_ec_curves_t; + + +#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data)) + +struct pgp_priv_data { + pgp_blob_t *mf; + pgp_blob_t *current; /* currently selected file */ + + pgp_version_t bcd_version; + pgp_do_info_t *pgp_objects; + + pgp_card_state_t state; /* card state */ + pgp_ext_caps_t ext_caps; /* extended capabilities */ + + pgp_sm_algo_t sm_algo; /* Secure Messaging algorithm */ + + size_t max_challenge_size; + size_t max_cert_size; + + sc_security_env_t sec_env; +}; + +#define BCD2UCHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F)) + +#endif