diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c index 2e8fee8f4..340646362 100644 --- a/tools/card-call-scd.c +++ b/tools/card-call-scd.c @@ -677,7 +677,10 @@ learn_status_cb (void *opaque, const char *line) log_assert (no >= 0 && no <= 2); data = unescape_status_string (line); - parm->uif[no] = (data[0] != 0xff); + /* I am not sure why we test for 0xff but we better keep + * that in case of bogus card versions which did not + * initialize that DO correctly. */ + parm->uif[no] = (data[0] == 0xff)? 0 : data[0]; xfree (data); } break; @@ -692,6 +695,7 @@ learn_status_cb (void *opaque, const char *line) { char *p, *p2, *buf; int abool; + unsigned long number; buf = p = unescape_status_string (line); if (buf) @@ -713,6 +717,39 @@ learn_status_cb (void *opaque, const char *line) parm->extcap.kdf = abool; else if (!strcmp (p, "si")) parm->status_indicator = strtoul (p2, NULL, 10); + else if (!strcmp (p, "pd")) + parm->extcap.private_dos = abool; + else if (!strcmp (p, "mcl3")) + parm->extcap.mcl3 = strtoul (p2, NULL, 10); + else if (!strcmp (p, "sm")) + { + /* Unfortunately this uses OpenPGP algorithm + * ids so that we need to map them to Gcrypt + * ids. The mapping is limited to what + * OpenPGP cards support. Other cards + * should use a different tag than "sm". */ + parm->extcap.sm = 1; + number = strtoul (p2, NULL, 10); + switch (number) + { + case CIPHER_ALGO_3DES: + parm->extcap.smalgo = GCRY_CIPHER_3DES; + break; + case CIPHER_ALGO_AES: + parm->extcap.smalgo = GCRY_CIPHER_AES; + break; + case CIPHER_ALGO_AES192: + parm->extcap.smalgo = GCRY_CIPHER_AES192; + break; + case CIPHER_ALGO_AES256: + parm->extcap.smalgo = GCRY_CIPHER_AES256; + break; + default: + /* Unknown algorithm; dont claim SM support. */ + parm->extcap.sm = 0; + break; + } + } } } xfree (buf); diff --git a/tools/gpg-card.c b/tools/gpg-card.c index deb9ead0e..86ff8b111 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -839,6 +839,18 @@ list_openpgp (card_info_t info, estream_t fp, int no_key_lookup) tty_fprintf (fp, "PIN retry counter : %d %d %d\n", info->chvinfo[0], info->chvinfo[1], info->chvinfo[2]); tty_fprintf (fp, "Signature counter : %lu\n", info->sig_counter); + tty_fprintf (fp, "Capabilities .....:"); + if (info->extcap.ki) + tty_fprintf (fp, " key-import"); + if (info->extcap.aac) + tty_fprintf (fp, " algo-change"); + if (info->extcap.bt) + tty_fprintf (fp, " button"); + if (info->extcap.sm) + tty_fprintf (fp, " sm(%s)", gcry_cipher_algo_name (info->extcap.smalgo)); + if (info->extcap.private_dos) + tty_fprintf (fp, " priv-data"); + tty_fprintf (fp, "\n"); if (info->extcap.kdf) { tty_fprintf (fp, "KDF setting ......: %s\n", @@ -847,8 +859,9 @@ list_openpgp (card_info_t info, estream_t fp, int no_key_lookup) if (info->extcap.bt) { tty_fprintf (fp, "UIF setting ......: Sign=%s Decrypt=%s Auth=%s\n", - info->uif[0] ? "on" : "off", info->uif[1] ? "on" : "off", - info->uif[2] ? "on" : "off"); + info->uif[0] ? (info->uif[0]==2? "permanent": "on") : "off", + info->uif[1] ? (info->uif[0]==2? "permanent": "on") : "off", + info->uif[2] ? (info->uif[0]==2? "permanent": "on") : "off"); } list_all_kinfo (info, keyinfolabels, fp, no_key_lookup); @@ -2956,6 +2969,10 @@ cmd_uif (card_info_t info, char *argstr) { gpg_error_t err; int keyno; + char name[50]; + unsigned char data[2]; + char *answer = NULL; + int opt_yes; if (!info) return print_help @@ -2963,6 +2980,14 @@ cmd_uif (card_info_t info, char *argstr) "Change the User Interaction Flag. N must in the range 1 to 3.", APP_TYPE_OPENPGP, APP_TYPE_PIV, 0); + if (!info->extcap.bt) + { + log_error (_("This command is not supported by this card\n")); + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + goto leave; + } + + opt_yes = has_leading_option (argstr, "--yes"); argstr = skip_options (argstr); if (digitp (argstr)) @@ -2982,10 +3007,68 @@ cmd_uif (card_info_t info, char *argstr) goto leave; } + if ( !strcmp (argstr, "off") ) + data[0] = 0x00; + else if ( !strcmp (argstr, "on") ) + data[0] = 0x01; + else if ( !strcmp (argstr, "permanent") ) + data[0] = 0x02; + else + { + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + data[1] = 0x20; - err = GPG_ERR_NOT_IMPLEMENTED; + + log_assert (keyno - 1 < DIM(info->uif)); + if (info->uif[keyno-1] == 2) + { + log_info (_("User Interaction Flag is set to \"%s\" - can't change\n"), + "permanent"); + err = gpg_error (GPG_ERR_INV_STATE); + goto leave; + } + + if (data[0] == 0x02) + { + if (opt.interactive) + { + tty_printf (_("Warning: Setting the User Interaction Flag to \"%s\"\n" + " can only be reverted using a factory reset!\n" + ), "permanent"); + answer = tty_get (_("Continue? (y/N) ")); + tty_kill_prompt (); + if (*answer == CONTROL_D) + err = gpg_error (GPG_ERR_CANCELED); + else if (!answer_is_yes_no_default (answer, 0/*(default to No)*/)) + err = gpg_error (GPG_ERR_CANCELED); + else + err = 0; + } + else if (!opt_yes) + { + log_info (_("Warning: Setting the User Interaction Flag to \"%s\"\n" + " can only be reverted using a factory reset!\n" + ), "permanent"); + log_info (_("Please use \"uif --yes %d %s\"\n"), + keyno, "permanent"); + err = gpg_error (GPG_ERR_CANCELED); + } + else + err = 0; + + if (err) + goto leave; + } + + snprintf (name, sizeof name, "UIF-%d", keyno); + err = scd_setattr (name, data, 2); + if (!err) /* Read all UIF attributes again. */ + err = scd_getattr ("UIF", info); leave: + xfree (answer); return err; } diff --git a/tools/gpg-card.h b/tools/gpg-card.h index fc01684b0..9627e7b30 100644 --- a/tools/gpg-card.h +++ b/tools/gpg-card.h @@ -174,11 +174,16 @@ struct card_info_s unsigned int ki:1; /* Key import available. */ unsigned int aac:1; /* Algorithm attributes are changeable. */ unsigned int kdf:1; /* KDF object to support PIN hashing available. */ - unsigned int bt:1; /* Button for confirmation available. */ + unsigned int bt:1; /* Button for confirmation available. */ + unsigned int sm:1; /* Secure messaging available. */ + unsigned int smalgo:15;/* Secure messaging cipher algorithm. */ + unsigned int private_dos:1;/* Support fpr private use DOs. */ + unsigned int mcl3:16; /* Max. length for a OpenPGP card cert.3 */ } extcap; unsigned int status_indicator; int kdf_do_enabled; /* True if card has a KDF object. */ - int uif[3]; /* True if User Interaction Flag is on. */ + int uif[3]; /* True if User Interaction Flag is on. */ + /* 1 = on, 2 = permanent on. */ }; typedef struct card_info_s *card_info_t;