From d6aa8bcbbbec65eed157fbda6e6987c811a002cf Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 4 Sep 2020 12:46:51 +0900 Subject: scd: Parse "Algorithm Information" data object in scdaemon. * scd/app-openpgp.c (data_objects): 0x00FA for binary data. (do_getattr): Parse the data and send it in status lines. (get_algorithm_attribute_string): New. -- Signed-off-by: NIIBE Yutaka Backported-from-master: eba2563dabbb4f61537900289fbe3ae113904733 Backported-from-master: 43bbc25b0f57dec24412886ff46041e0b1f3de26 --- doc/DETAILS | 14 +++++++ scd/app-openpgp.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/doc/DETAILS b/doc/DETAILS index 8e8552136..1ca35c54c 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1174,6 +1174,20 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: name of the manufacturer is also given as ; spaces are not escaped. For PKCS#15 cards is TokenInfo.manufactorerID. +*** KEY-STATUS + This is the response from scdaemon on GETATTR KEY-STATUS for + OpenPGP cards. is the usual keyref (e.g. OPENPGP.1 or + OPENPGP.129) and is an integer describing the status of + the key: 0 = key is not present, 1 = key generated on card, 2 = + key imported. See section 4.4.3.8 of the OpenPGP Smart Card + Application V3.4. + +*** KEY-ATTR-INFO + This is the response from scdaemon on GETATTR KEY-ATTR-INFO for + OpenPGP cards. is the usual keyref (e.g. OPENPGP.1 or + OPENPGP.129) and is the algoritm or curve name, which + is available for the key. + * Format of the --attribute-fd output When --attribute-fd is set, during key listings (--list-keys, diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1e282fac1..114a89c0b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -115,6 +115,7 @@ static struct { { 0x7F74, 0, 0, 1, 0, 0, 0, 0, "General Feature Management"}, { 0x00D5, 0, 0, 1, 0, 0, 0, 0, "AES key data"}, { 0x00F9, 0, 0, 1, 0, 0, 0, 0, "KDF data object"}, + { 0x00FA, 0, 0, 1, 0, 0, 0, 2, "Algorithm Information"}, { 0 } }; @@ -253,6 +254,8 @@ static gpg_error_t do_auth (app_t app, ctrl_t ctrl, const char *keyidstr, void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); +static const char *get_algorithm_attribute_string (const unsigned char *buffer, + size_t buflen); static gpg_error_t parse_algorithm_attribute (app_t app, int keyno); static gpg_error_t change_keyattr_from_string (app_t app, @@ -1169,6 +1172,86 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0); } + else if (table[idx].special == 6) + { + for (i=0,rc=0; !rc && i+1 < valuelen; i += 2) + rc = send_status_printf (ctrl, table[idx].name, "OPENPGP.%u %u", + value[i], value[i+1]); + if (gpg_err_code (rc) == GPG_ERR_NO_OBJ) + rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + } + else if (table[idx].special == 7) + { + const unsigned char *p = value; + int tag; + size_t len; + + if (valuelen < 2) + return gpg_error (GPG_ERR_INV_OBJ); + + tag = *p++; + len = *p++; + + /* Does it comes tag+len at the head? */ + if (tag == 0x00FA) + { + p += 2; + + if (len == 0x81) + { + if (valuelen < 3) + return gpg_error (GPG_ERR_INV_OBJ); + len = *p++; + } + else if (len == 0x82) + { + if (valuelen < 4) + return gpg_error (GPG_ERR_INV_OBJ); + len = *p++; + len = (len << 8) | *p++; + } + + valuelen -= (p - value); + value = (unsigned char *)p; + + if (valuelen != len) + { + if (opt.verbose) + log_info ("Yubikey bug: length %zu != %zu", valuelen, len); + + if (APP_CARD(app)->cardtype != CARDTYPE_YUBIKEY) + return gpg_error (GPG_ERR_INV_OBJ); + } + } + + for (; p < value + valuelen; p += len) + { + const char *key_algo_str; + int keyrefno; + + if (p + 2 > value + valuelen) + break; + + tag = *p++; + len = *p++; + + if (tag < 0xc1) + continue; + + if (tag == 0xda) + keyrefno = 0x81; + else + keyrefno = tag - 0xc1 + 1; + + if (p + len > value + valuelen) + break; + + key_algo_str = get_algorithm_attribute_string (p, len); + + send_status_printf (ctrl, table[idx].name, "OPENPGP.%u %s", + keyrefno, key_algo_str); + } + } else send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0); @@ -5289,7 +5372,7 @@ parse_historical (struct app_local_s *apploc, * The constant string is not allocated dynamically, never free it. */ static const char * -ecc_curve (unsigned char *buf, size_t buflen) +ecc_curve (const unsigned char *buf, size_t buflen) { gcry_mpi_t oid; char *oidstr; @@ -5320,6 +5403,39 @@ ecc_curve (unsigned char *buf, size_t buflen) } +static const char * +get_algorithm_attribute_string (const unsigned char *buffer, + size_t buflen) +{ + enum gcry_pk_algos galgo; + const char *curve; + unsigned int nbits = 0; + + galgo = map_openpgp_pk_to_gcry (*buffer); + nbits = 0; + curve = NULL; + + if (*buffer == PUBKEY_ALGO_RSA && (buflen == 5 || buflen == 6)) + nbits = (buffer[1]<<8 | buffer[2]); + else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA + || *buffer == PUBKEY_ALGO_EDDSA) + { + int oidlen = buflen - 1; + + if (buffer[buflen-1] == 0x00 || buffer[buflen-1] == 0xff) + { /* Found "pubkey required"-byte for private key template. */ + oidlen--; + } + + curve = ecc_curve (buffer + 1, oidlen); + } + else if (opt.verbose) + log_printhex (buffer, buflen, ""); + + return get_keyalgo_string (galgo, nbits, curve); +} + + /* Parse and optionally show the algorithm attributes for KEYNO. KEYNO must be in the range 0..2. */ static gpg_error_t -- cgit v1.2.3