diff --git a/NEWS b/NEWS index 551f117d..c2b812a7 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ Noteworthy changes in version 1.1.9 gpgme_op_assuan_transact_start NEW. gpgme_op_assuan_transact NEW. gpgme_op_assuan_result NEW. + gpgme_subkey_t EXTENDED: New fields is_cardkey, card_number. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/ChangeLog b/src/ChangeLog index bf272bca..f98e1a3c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2009-02-03 Werner Koch + + * gpgme.h.in (struct _gpgme_subkey): Add fields IS_CARDKEY and + CARD_NUMBER.. + * key.c (gpgme_key_unref): Release field CARD_NUMBER. + * keylist.c (keylist_colon_handler): Factor common code out to ... + (parse_sec_field15): New. Set card number. + 2009-01-26 Werner Koch * opassuan.c, dirinfo.c, engine-assuan.c: New. diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 4b68d801..e83b1fb1 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -519,8 +519,11 @@ struct _gpgme_subkey /* True if subkey is qualified for signatures according to German law. */ unsigned int is_qualified : 1; + /* True if the secret key is stored on a smart card. */ + unsigned int is_cardkey : 1; + /* Internal to GPGME, do not use. */ - unsigned int _unused : 22; + unsigned int _unused : 21; /* Public key algorithm supported by this subkey. */ gpgme_pubkey_algo_t pubkey_algo; @@ -542,6 +545,9 @@ struct _gpgme_subkey /* The expiration timestamp, 0 if the subkey does not expire. */ long int expires; + + /* The serial number of a smart card holding this key or NULL. */ + char *card_number; }; typedef struct _gpgme_subkey *gpgme_subkey_t; diff --git a/src/key.c b/src/key.c index c9f48f87..468946fe 100644 --- a/src/key.c +++ b/src/key.c @@ -327,6 +327,8 @@ gpgme_key_unref (gpgme_key_t key) gpgme_subkey_t next = subkey->next; if (subkey->fpr) free (subkey->fpr); + if (subkey->card_number) + free (subkey->card_number); free (subkey); subkey = next; } diff --git a/src/keylist.c b/src/keylist.c index 69b0dc9e..2ee34b81 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -1,7 +1,7 @@ /* keylist.c - Listing keys. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, - 2008 g10 Code GmbH + 2008, 2009 g10 Code GmbH This file is part of GPGME. @@ -351,6 +351,38 @@ set_ownertrust (gpgme_key_t key, const char *src) } +/* Parse field 15 of a secret key or subkey. This fields holds a + reference to smartcards. FIELD is the content of the field and we + are allowed to modify it. */ +static gpg_error_t +parse_sec_field15 (gpgme_subkey_t subkey, char *field) +{ + if (!*field) + ; /* Empty. */ + else if (*field == '#') + { + /* This is a stub for an offline key. We reset the SECRET flag + of the subkey here. Note that the secret flag of the entire + key will be true even then. */ + subkey->secret = 0; + } + else if (strchr ("01234567890ABCDEFabcdef", *field)) + { + /* Fields starts with a hex digit; thus it is a serial number. */ + subkey->is_cardkey = 1; + subkey->card_number = strdup (field); + if (!subkey->card_number) + return gpg_error_from_syserror (); + } + else + { + /* RFU. */ + } + + return 0; +} + + /* We have read an entire key into tmp_key and should now finish it. It is assumed that this releases tmp_key. */ static void @@ -533,12 +565,13 @@ keylist_colon_handler (void *priv, char *line) if (fields >= 12) set_mainkey_capability (key, field[11]); - /* Field 15 carries special flags of a secret key. We reset the - SECRET flag of a subkey here if the key is actually only a - stub. The SECRET flag of the key will be true even then. */ + /* Field 15 carries special flags of a secret key. */ if (fields >= 15 && key->secret) - if (*field[14] == '#') - subkey->secret = 0; + { + err = parse_sec_field15 (subkey, field[14]); + if (err) + return err; + } break; case RT_SUB: @@ -596,8 +629,11 @@ keylist_colon_handler (void *priv, char *line) /* Field 15 carries special flags of a secret key. */ if (fields >= 15 && key->secret) - if (*field[14] == '#') - subkey->secret = 0; + { + err = parse_sec_field15 (subkey, field[14]); + if (err) + return err; + } break; case RT_UID: diff --git a/tests/ChangeLog b/tests/ChangeLog index 1248a8f2..efd756c4 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,8 @@ +2009-02-03 Werner Koch + + * gpg/t-keylist.c (main): Check that new fields is_cardkey and + card_number are not set. + 2009-01-26 Werner Koch * opassuan/: New. diff --git a/tests/gpg/t-keylist.c b/tests/gpg/t-keylist.c index c8c71d0c..e536b47a 100644 --- a/tests/gpg/t-keylist.c +++ b/tests/gpg/t-keylist.c @@ -270,6 +270,16 @@ main (int argc, char **argv) fprintf (stderr, "Primary key unexpectedly secret\n"); exit (1); } + if (key->subkeys->is_cardkey) + { + fprintf (stderr, "Public key marked as card key\n"); + exit (1); + } + if (key->subkeys->card_number) + { + fprintf (stderr, "Public key with card number set\n"); + exit (1); + } if (key->subkeys->pubkey_algo != GPGME_PK_DSA) { fprintf (stderr, "Primary key has unexpected public key algo: %s\n", @@ -342,6 +352,16 @@ main (int argc, char **argv) fprintf (stderr, "Secondary key unexpectedly secret\n"); exit (1); } + if (key->subkeys->next->is_cardkey) + { + fprintf (stderr, "Secondary public key marked as card key\n"); + exit (1); + } + if (key->subkeys->next->card_number) + { + fprintf (stderr, "Secondary public key with card number set\n"); + exit (1); + } if (key->subkeys->next->pubkey_algo != GPGME_PK_ELG_E) { fprintf (stderr, "Secondary key has unexpected public key algo: %s\n",