1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-08 12:44:23 +01:00

* gpg.sgml: Document "addcardkey" and "keytocard".

* apdu.c (open_pcsc_reader): Do not print empty reader string.

* keygen.c (ask_algo): Allow creation of AUTH keys.

* keyid.c (usagestr_from_pk): New.

* app-openpgp.c (app_openpgp_storekey): Call flush_cache.

* keyedit.c (keyedit_menu): New command "keytocard"
(keyedit_menu): Bad hack for the not_with_sk element.
(show_key_with_all_names): Print the usage.
(find_pk_from_sknode): New.

* card-util.c (card_store_subkey): New.
(copy_mpi): New.
* cardglue.c (agent_openpgp_storekey): New.
This commit is contained in:
Werner Koch 2004-09-23 13:32:31 +00:00
parent d937ace2f8
commit 42c18de83a
15 changed files with 589 additions and 125 deletions

4
NEWS
View File

@ -10,8 +10,8 @@ Noteworthy changes in version 1.3.7
for smartcards. for smartcards.
* New command "addcardkey" in the key edit menu to add subkeys to * New command "addcardkey" in the key edit menu to add subkeys to
a smartcard. The serial number of the card is show in secret a smartcard. New command "keytocard" to transfer a key to a smartcard.
key listings. The serial number of the card is show in secret key listings.
* -K may now be used as an alias for --list-secret-keys. * -K may now be used as an alias for --list-secret-keys.

View File

@ -1,3 +1,7 @@
2004-09-23 Werner Koch <wk@g10code.com>
* gpg.sgml: Document "addcardkey" and "keytocard".
2004-09-20 Werner Koch <wk@g10code.com> 2004-09-20 Werner Koch <wk@g10code.com>
* gpg.sgml: Document -K. * gpg.sgml: Document -K.

View File

@ -414,6 +414,17 @@ Add a subkey to this key.</para></listitem></varlistentry>
<listitem><para> <listitem><para>
Generate a key on a card and add it Generate a key on a card and add it
to this key.</para></listitem></varlistentry> to this key.</para></listitem></varlistentry>
<varlistentry>
<term>keytocard</term>
<listitem><para>
Transfer the selected secret key (or the primary key if no key has
been selected) to a smartcard. The secret key in the keyring will be
replaced by a stub if the key could be stored successfully on the card
and you use the save command later. Only certain key types may be
transferred to the card. A sub menu allows you to select on what card
to store the key. Note that it is not possible to get that key back
from the card - if the card gets broken your secret key will be lost
unless you have a backup somewhere.</para></listitem></varlistentry>
<varlistentry> <varlistentry>
<term>delkey</term> <term>delkey</term>
<listitem><para> <listitem><para>

View File

@ -1,3 +1,30 @@
2004-09-23 Werner Koch <wk@g10code.com>
* apdu.c (open_pcsc_reader): Do not print empty reader string.
* keygen.c (ask_algo): Allow creation of AUTH keys.
* keyid.c (usagestr_from_pk): New.
* app-openpgp.c (app_openpgp_storekey): Call flush_cache.
* keyedit.c (keyedit_menu): New command "keytocard"
(keyedit_menu): Bad hack for the not_with_sk element.
(show_key_with_all_names): Print the usage.
(find_pk_from_sknode): New.
* card-util.c (card_store_subkey): New.
(copy_mpi): New.
* cardglue.c (agent_openpgp_storekey): New.
2004-09-22 Werner Koch <wk@g10code.com>
* card-util.c (card_generate_subkey, generate_card_keys): Factored
common code out to ...
(get_info_for_key_operation, check_pin_for_key_operation)
(restore_forced_chv1, replace_existing_key_p)
(show_card_key_info): ... new functions.
2004-09-21 David Shaw <dshaw@jabberwocky.com> 2004-09-21 David Shaw <dshaw@jabberwocky.com>
* mainproc.c (check_sig_and_print), keyedit.c (show_prefs, * mainproc.c (check_sig_and_print), keyedit.c (show_prefs,

View File

@ -1119,7 +1119,8 @@ open_pcsc_reader (const char *portstr)
{ {
if (!*p && !p[1]) if (!*p && !p[1])
break; break;
log_info ("detected reader `%s'\n", p); if (*p)
log_info ("detected reader `%s'\n", p);
if (nreader < (strlen (p)+1)) if (nreader < (strlen (p)+1))
{ {
log_error ("invalid response from pcsc_list_readers\n"); log_error ("invalid response from pcsc_list_readers\n");

View File

@ -143,6 +143,7 @@ int app_openpgp_cardinfo (app_t app,
unsigned char **fpr1, unsigned char **fpr1,
unsigned char **fpr2, unsigned char **fpr2,
unsigned char **fpr3); unsigned char **fpr3);
#endif /* GNUPG_MAJOR_VERSION != 1 */
int app_openpgp_storekey (app_t app, int keyno, int app_openpgp_storekey (app_t app, int keyno,
unsigned char *template, size_t template_len, unsigned char *template, size_t template_len,
time_t created_at, time_t created_at,
@ -153,6 +154,8 @@ int app_openpgp_storekey (app_t app, int keyno,
int app_openpgp_readkey (app_t app, int keyno, int app_openpgp_readkey (app_t app, int keyno,
unsigned char **m, size_t *mlen, unsigned char **m, size_t *mlen,
unsigned char **e, size_t *elen); unsigned char **e, size_t *elen);
#if GNUPG_MAJOR_VERSION == 1
#else
/*-- app-nks.c --*/ /*-- app-nks.c --*/
int app_select_nks (app_t app); int app_select_nks (app_t app);
@ -160,8 +163,7 @@ int app_select_nks (app_t app);
int app_select_dinsig (app_t app); int app_select_dinsig (app_t app);
#endif #endif /* GNUPG_MAJOR_VERSION != 1 */
#endif /*GNUPG_SCD_APP_COMMON_H*/ #endif /*GNUPG_SCD_APP_COMMON_H*/

View File

@ -432,7 +432,6 @@ store_fpr (int slot, int keynumber, u32 timestamp,
*p++ = nbits; *p++ = nbits;
memcpy (p, e, elen); p += elen; memcpy (p, e, elen); p += elen;
log_printhex ("fprbuf:", buffer, n+3);
gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3); gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3);
xfree (buffer); xfree (buffer);
@ -1551,6 +1550,7 @@ app_openpgp_storekey (APP app, int keyno,
if (rc) if (rc)
goto leave; goto leave;
flush_cache (app);
rc = iso7816_put_data (app->slot, rc = iso7816_put_data (app->slot,
(app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,

View File

@ -43,6 +43,39 @@
#define CONTROL_D ('D' - 'A' + 1) #define CONTROL_D ('D' - 'A' + 1)
#if GNUPG_MAJOR_VERSION == 1
#define GET_NBITS(a) mpi_get_nbits (a)
#else
#define GET_NBITS(a) gcry_mpi_get_nbits (a)
#endif
static int
copy_mpi (MPI a, unsigned char *buffer, size_t len, size_t *ncopied)
{
int rc;
#if GNUPG_MAJOR_VERSION == 1
unsigned char *tmp;
unsigned int n;
tmp = mpi_get_secure_buffer (a, &n, NULL);
if (n > len)
rc = G10ERR_GENERAL;
else
{
rc = 0;
memcpy (buffer, tmp, n);
*ncopied = n;
}
xfree (tmp);
#else /* GNUPG_MAJOR_VERSION != 1 */
rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, len, ncopied, a);
#endif /* GNUPG_MAJOR_VERSION != 1 */
if (rc)
log_error ("mpi_copy failed: %s\n", gpg_strerror (rc));
return rc;
}
/* Change the PIN of a an OpenPGP card. This is an interactive /* Change the PIN of a an OpenPGP card. This is an interactive
function. */ function. */
@ -749,26 +782,125 @@ toggle_forcesig (void)
} }
/* Helper for the key generation/edit functions. */
static int
get_info_for_key_operation (struct agent_card_info_s *info)
{
int rc;
memset (info, 0, sizeof *info);
rc = agent_scd_getattr ("SERIALNO", info);
if (rc || !info->serialno || strncmp (info->serialno, "D27600012401", 12)
|| strlen (info->serialno) != 32 )
{
log_error (_("key operation not possible: %s\n"),
rc ? gpg_strerror (rc) : _("not an OpenPGP card"));
return rc? rc: -1;
}
rc = agent_scd_getattr ("KEY-FPR", info);
if (!rc)
rc = agent_scd_getattr ("CHV-STATUS", info);
if (!rc)
rc = agent_scd_getattr ("DISP-NAME", info);
if (rc)
log_error (_("error getting current key info: %s\n"), gpg_strerror (rc));
return rc;
}
/* Helper for the key generation/edit functions. */
static int
check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1)
{
int rc = 0;
*forced_chv1 = !info->chv1_cached;
if (*forced_chv1)
{ /* Switch of the forced mode so that during key generation we
don't get bothered with PIN queries for each
self-signature. */
rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
if (rc)
{
log_error ("error clearing forced signature PIN flag: %s\n",
gpg_strerror (rc));
*forced_chv1 = 0;
}
}
if (!rc)
{
/* Check the PIN now, so that we won't get asked later for each
binding signature. */
rc = agent_scd_checkpin (info->serialno);
if (rc)
log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
}
return rc;
}
/* Helper for the key generation/edit functions. */
static void
restore_forced_chv1 (int *forced_chv1)
{
int rc;
if (*forced_chv1)
{ /* Switch back to forced state. */
rc = agent_scd_setattr ("CHV-STATUS-1", "", 1);
if (rc)
{
log_error ("error setting forced signature PIN flag: %s\n",
gpg_strerror (rc));
}
}
}
/* Helper for the key generation/edit functions. */
static void
show_card_key_info (struct agent_card_info_s *info)
{
tty_fprintf (NULL, "Signature key ....:");
print_sha1_fpr (NULL, info->fpr1valid? info->fpr1:NULL);
tty_fprintf (NULL, "Encryption key....:");
print_sha1_fpr (NULL, info->fpr2valid? info->fpr2:NULL);
tty_fprintf (NULL, "Authentication key:");
print_sha1_fpr (NULL, info->fpr3valid? info->fpr3:NULL);
tty_printf ("\n");
}
/* Helper for the key generation/edit functions. */
static int
replace_existing_key_p (struct agent_card_info_s *info, int keyno)
{
assert (keyno >= 0 && keyno <= 3);
if ((keyno == 1 && info->fpr1valid)
|| (keyno == 2 && info->fpr2valid)
|| (keyno == 3 && info->fpr3valid))
{
tty_printf ("\n");
log_info ("WARNING: such a key has already been stored on the card!\n");
tty_printf ("\n");
if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_key",
_("Replace existing key? ")))
return -1;
}
return 0;
}
static void static void
generate_card_keys (const char *serialno) generate_card_keys (const char *serialno)
{ {
struct agent_card_info_s info; struct agent_card_info_s info;
int rc;
int forced_chv1; int forced_chv1;
memset (&info, 0, sizeof info); if (get_info_for_key_operation (&info))
rc = agent_scd_getattr ("KEY-FPR", &info); return;
if (!rc)
rc = agent_scd_getattr ("SERIALNO", &info);
if (!rc)
rc = agent_scd_getattr ("CHV-STATUS", &info);
if (!rc)
rc = agent_scd_getattr ("DISP-NAME", &info);
if (rc)
{
log_error ("error getting current key info: %s\n", gpg_strerror (rc));
return;
}
if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) if ( (info.fpr1valid && !fpr_is_zero (info.fpr1))
|| (info.fpr2valid && !fpr_is_zero (info.fpr2)) || (info.fpr2valid && !fpr_is_zero (info.fpr2))
|| (info.fpr3valid && !fpr_is_zero (info.fpr3))) || (info.fpr3valid && !fpr_is_zero (info.fpr3)))
@ -793,39 +925,14 @@ generate_card_keys (const char *serialno)
tty_printf ("\n"); tty_printf ("\n");
} }
forced_chv1 = !info.chv1_cached; if (check_pin_for_key_operation (&info, &forced_chv1))
if (forced_chv1) goto leave;
{ /* Switch of the forced mode so that during key generation we
don't get bothered with PIN queries for each generate_keypair (NULL, info.serialno);
self-signature. */
rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
if (rc)
{
log_error ("error clearing forced signature PIN flag: %s\n",
gpg_strerror (rc));
return;
}
}
/* Check the PIN now, so that we won't get asked later for each
binding signature. */
rc = agent_scd_checkpin (serialno);
if (rc)
log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
else
generate_keypair (NULL, info.serialno);
leave:
agent_release_card_info (&info); agent_release_card_info (&info);
if (forced_chv1) restore_forced_chv1 (&forced_chv1);
{ /* Switch back to forced state. */
rc = agent_scd_setattr ("CHV-STATUS-1", "", 1);
if (rc)
{
log_error ("error setting forced signature PIN flag: %s\n",
gpg_strerror (rc));
return;
}
}
} }
@ -837,34 +944,12 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
struct agent_card_info_s info; struct agent_card_info_s info;
int okay = 0; int okay = 0;
int forced_chv1 = 0; int forced_chv1 = 0;
int rc;
int keyno; int keyno;
memset (&info, 0, sizeof info); if (get_info_for_key_operation (&info))
rc = agent_scd_getattr ("SERIALNO", &info); return 0;
if (rc || !info.serialno || strncmp (info.serialno, "D27600012401", 12)
|| strlen (info.serialno) != 32 ) show_card_key_info (&info);
{
log_error (_("cannot generate key: %s\n"),
rc ? gpg_strerror (rc) : _("not an OpenPGP card"));
goto leave;
}
rc = agent_scd_getattr ("KEY-FPR", &info);
if (!rc)
rc = agent_scd_getattr ("CHV-STATUS", &info);
if (rc)
{
log_error ("error getting current key info: %s\n", gpg_strerror (rc));
goto leave;
}
tty_fprintf (NULL, "Signature key ....:");
print_sha1_fpr (NULL, info.fpr1valid? info.fpr1:NULL);
tty_fprintf (NULL, "Encryption key....:");
print_sha1_fpr (NULL, info.fpr2valid? info.fpr2:NULL);
tty_fprintf (NULL, "Authentication key:");
print_sha1_fpr (NULL, info.fpr3valid? info.fpr3:NULL);
tty_printf ("\n");
tty_printf (_("Please select the type of key to generate:\n")); tty_printf (_("Please select the type of key to generate:\n"));
@ -889,54 +974,239 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
tty_printf(_("Invalid selection.\n")); tty_printf(_("Invalid selection.\n"));
} }
if ((keyno == 1 && info.fpr1valid) if (replace_existing_key_p (&info, keyno))
|| (keyno == 2 && info.fpr2valid) goto leave;
|| (keyno == 3 && info.fpr3valid))
{
tty_printf ("\n");
log_info ("WARNING: such a key has already been stored on the card!\n");
tty_printf ("\n");
if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_key",
_("Replace existing key? ")))
goto leave;
}
forced_chv1 = !info.chv1_cached; if (check_pin_for_key_operation (&info, &forced_chv1))
if (forced_chv1) goto leave;
{ /* Switch of the forced mode so that during key generation we
don't get bothered with PIN queries for each
self-signature. */
rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
if (rc)
{
log_error ("error clearing forced signature PIN flag: %s\n",
gpg_strerror (rc));
forced_chv1 = 0;
goto leave;
}
}
/* Check the PIN now, so that we won't get asked later for each okay = generate_card_subkeypair (pub_keyblock, sec_keyblock,
binding signature. */ keyno, info.serialno);
rc = agent_scd_checkpin (info.serialno);
if (rc)
log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
else
okay = generate_card_subkeypair (pub_keyblock, sec_keyblock,
keyno, info.serialno);
leave: leave:
agent_release_card_info (&info); agent_release_card_info (&info);
if (forced_chv1) restore_forced_chv1 (&forced_chv1);
{ /* Switch back to forced state. */ return okay;
rc = agent_scd_setattr ("CHV-STATUS-1", "", 1); }
if (rc)
{
log_error ("error setting forced signature PIN flag: %s\n", /* Store the subkey at NODE into the smartcard and modify NODE to
gpg_strerror (rc)); carry the serrialno stuff instead of the actual secret key
return okay; parameters. */
} int
card_store_subkey (KBNODE node, int use)
{
struct agent_card_info_s info;
int okay = 0;
int rc;
int keyno, i;
PKT_secret_key *copied_sk = NULL;
PKT_secret_key *sk;
size_t n;
MPI rsa_n, rsa_e, rsa_p, rsa_q;
unsigned int nbits;
unsigned char *template = NULL;
unsigned char *tp;
unsigned char m[128], e[4];
size_t mlen, elen;
const char *s;
int allow_keyno[3];
assert (node->pkt->pkttype == PKT_SECRET_KEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
sk = node->pkt->pkt.secret_key;
if (get_info_for_key_operation (&info))
return 0;
show_card_key_info (&info);
if (!is_RSA (sk->pubkey_algo) || nbits_from_sk (sk) != 1024 )
{
tty_printf ("You may only store a 1024 bit RSA key on the card\n");
tty_printf ("\n");
goto leave;
} }
allow_keyno[0] = (!use || (use & (PUBKEY_USAGE_SIG)));
allow_keyno[1] = (!use || (use & (PUBKEY_USAGE_ENC)));
allow_keyno[2] = (!use || (use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH)));
tty_printf (_("Please select where to store the key:\n"));
if (allow_keyno[0])
tty_printf (_(" (1) Signature key\n"));
if (allow_keyno[1])
tty_printf (_(" (2) Encryption key\n"));
if (allow_keyno[2])
tty_printf (_(" (3) Authentication key\n"));
for (;;)
{
char *answer = cpr_get ("cardedit.genkeys.storekeytype",
_("Your selection? "));
cpr_kill_prompt();
if (*answer == CONTROL_D || !*answer)
{
xfree (answer);
goto leave;
}
keyno = *answer? atoi(answer): 0;
xfree(answer);
if (keyno >= 1 && keyno <= 3 && allow_keyno[keyno-1])
break; /* Okay. */
tty_printf(_("Invalid selection.\n"));
}
if (replace_existing_key_p (&info, keyno))
goto leave;
/* Unprotect key. */
switch (is_secret_key_protected (sk) )
{
case 0: /* Not protected. */
break;
case -1:
log_error (_("unknown key protection algorithm\n"));
goto leave;
default:
if (sk->protect.s2k.mode == 1001)
{
log_error (_("secret parts of key are not available\n"));
goto leave;
}
if (sk->protect.s2k.mode == 1002)
{
log_error (_("secret key already stored on a card\n"));
goto leave;
}
/* We better copy the key before we unprotect it. */
copied_sk = sk = copy_secret_key (NULL, sk);
rc = check_secret_key (sk, 0);
if (rc)
goto leave;
}
/* Some basic checks on the key parameters. */
rsa_n = sk->skey[0];
rsa_e = sk->skey[1];
rsa_p = sk->skey[3];
rsa_q = sk->skey[4];
nbits = GET_NBITS (rsa_n);
if (nbits != 1024)
{
log_error (_("length of RSA modulus is not %d\n"), 1024);
goto leave;
}
nbits = GET_NBITS (rsa_e);
if (nbits < 2 || nbits > 32)
{
log_error (_("public exponent too large (more than 32 bits)\n"));
goto leave;
}
nbits = GET_NBITS (rsa_p);
if (nbits != 512)
{
log_error (_("length of an RSA prime is not %d\n"), 512);
goto leave;
}
nbits = GET_NBITS (rsa_q);
if (nbits != 512)
{
log_error (_("length of an RSA prime is not %d\n"), 512);
goto leave;
}
/* We need the modulus later to calculate the fingerprint. */
rc = copy_mpi (rsa_n, m, 128, &n);
if (rc)
goto leave;
assert (n == 128);
mlen = 128;
/* Build the private key template as described in section 4.3.3.6 of
the OpenPGP card specs:
0xC0 <length> public exponent
0xC1 <length> prime p
0xC2 <length> prime q
*/
template = tp = xmalloc_secure (1+2 + 1+1+4 + 1+1+(512/8) + 1+1+(512/8));
*tp++ = 0xC0;
*tp++ = 4;
rc = copy_mpi (rsa_e, tp, 4, &n);
if (rc)
goto leave;
assert (n <= 4);
memcpy (e, tp, n); /* Save a copy of the exponent for later use. */
elen = n;
if (n != 4)
{
memmove (tp+4-n, tp, 4-n);
memset (tp, 0, 4-n);
}
tp += 4;
*tp++ = 0xC1;
*tp++ = 64;
rc = copy_mpi (rsa_p, tp, 64, &n);
if (rc)
goto leave;
assert (n == 64);
tp += 64;
*tp++ = 0xC2;
*tp++ = 64;
rc = copy_mpi (rsa_q, tp, 64, &n);
if (rc)
goto leave;
assert (n == 64);
tp += 64;
assert (tp - template == 138);
rc = agent_openpgp_storekey (keyno,
template, tp - template,
sk->timestamp,
m, mlen,
e, elen);
if (rc)
goto leave;
xfree (template);
template = NULL;
/* Get back to the maybe protected original secret key. */
if (copied_sk)
{
free_secret_key (copied_sk);
copied_sk = NULL;
}
sk = node->pkt->pkt.secret_key;
/* Get rid of the secret key parameters and store the serial numer. */
n = pubkey_get_nskey (sk->pubkey_algo);
for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
{
mpi_free (sk->skey[i]);
sk->skey[i] = NULL;
}
i = pubkey_get_npkey (sk->pubkey_algo);
sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
sk->is_protected = 1;
sk->protect.s2k.mode = 1002;
s = info.serialno;
for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
sk->protect.ivlen++, s += 2)
sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
okay = 1;
leave:
if (copied_sk)
free_secret_key (copied_sk);
xfree (template);
agent_release_card_info (&info);
return okay; return okay;
} }

View File

@ -827,3 +827,22 @@ agent_scd_checkpin (const char *serialnobuf)
return app->fnc.check_pin (app, serialnobuf, pin_cb, NULL); return app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
} }
/* Wrapper to call the store key helper function of app-openpgp.c. */
int
agent_openpgp_storekey (int keyno,
unsigned char *template, size_t template_len,
time_t created_at,
const unsigned char *m, size_t mlen,
const unsigned char *e, size_t elen)
{
APP app;
app = current_app? current_app : open_card ();
if (!app)
return gpg_error (GPG_ERR_CARD);
return app_openpgp_storekey (app, keyno, template, template_len,
created_at, m, mlen, e, elen,
pin_cb, NULL);
}

View File

@ -183,6 +183,12 @@ int agent_scd_change_pin (int chvno);
/* Send a CHECKPIN command. */ /* Send a CHECKPIN command. */
int agent_scd_checkpin (const char *serialnobuf); int agent_scd_checkpin (const char *serialnobuf);
/* Call the store key utility command. */
int agent_openpgp_storekey (int keyno,
unsigned char *template, size_t template_len,
time_t created_at,
const unsigned char *m, size_t mlen,
const unsigned char *e, size_t elen);
#endif /*ENABLE_CARD_SUPPORT*/ #endif /*ENABLE_CARD_SUPPORT*/
#endif /*GNUPG_G10_CARDGLUE_H*/ #endif /*GNUPG_G10_CARDGLUE_H*/

View File

@ -258,6 +258,7 @@ const char *expirestr_from_pk( PKT_public_key *pk );
const char *expirestr_from_sk( PKT_secret_key *sk ); const char *expirestr_from_sk( PKT_secret_key *sk );
const char *expirestr_from_sig( PKT_signature *sig ); const char *expirestr_from_sig( PKT_signature *sig );
const char *revokestr_from_pk( PKT_public_key *pk ); const char *revokestr_from_pk( PKT_public_key *pk );
const char *usagestr_from_pk( PKT_public_key *pk );
const char *colon_strtime (u32 t); const char *colon_strtime (u32 t);
const char *colon_datestr_from_pk (PKT_public_key *pk); const char *colon_datestr_from_pk (PKT_public_key *pk);
const char *colon_datestr_from_sk (PKT_secret_key *sk); const char *colon_datestr_from_sk (PKT_secret_key *sk);

View File

@ -95,6 +95,34 @@ struct sign_attrib {
}; };
/* Given a node SEC_NODE with a secret key or subkey, locate the
corresponding public key from pub_keyblock. */
static PKT_public_key *
find_pk_from_sknode (KBNODE pub_keyblock, KBNODE sec_node)
{
KBNODE node = pub_keyblock;
PKT_secret_key *sk;
PKT_public_key *pk;
if (sec_node->pkt->pkttype == PKT_SECRET_KEY
&& node->pkt->pkttype == PKT_PUBLIC_KEY)
return node->pkt->pkt.public_key;
if (sec_node->pkt->pkttype != PKT_SECRET_SUBKEY)
return NULL;
sk = sec_node->pkt->pkt.secret_key;
for (; node; node = node->next)
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
pk = node->pkt->pkt.public_key;
if (pk->keyid[0] == sk->keyid[0] && pk->keyid[1] == sk->keyid[1])
return pk;
}
return NULL;
}
/* TODO: Fix duplicated code between here and the check-sigs/list-sigs /* TODO: Fix duplicated code between here and the check-sigs/list-sigs
code in keylist.c. */ code in keylist.c. */
static int static int
@ -1191,14 +1219,14 @@ keyedit_menu( const char *username, STRLIST locusr,
cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF,
cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST,
cmdADDCARDKEY, cmdADDCARDKEY, cmdKEYTOCARD,
cmdNOP }; cmdNOP };
static struct { const char *name; static struct { const char *name;
enum cmdids id; enum cmdids id;
int need_sk; int need_sk;
int not_with_sk; int not_with_sk; /* but 2 == must use SK */
const char *desc; const char *desc;
} cmds[] = { } cmds[] = {
{ N_("quit") , cmdQUIT , 0,0, N_("quit this menu") }, { N_("quit") , cmdQUIT , 0,0, N_("quit this menu") },
{ N_("q") , cmdQUIT , 0,0, NULL }, { N_("q") , cmdQUIT , 0,0, NULL },
{ N_("save") , cmdSAVE , 0,0, N_("save and quit") }, { N_("save") , cmdSAVE , 0,0, N_("save and quit") },
@ -1226,7 +1254,8 @@ keyedit_menu( const char *username, STRLIST locusr,
{ N_("addkey") , cmdADDKEY , 1,1, N_("add a secondary key") }, { N_("addkey") , cmdADDKEY , 1,1, N_("add a secondary key") },
#ifdef ENABLE_CARD_SUPPORT #ifdef ENABLE_CARD_SUPPORT
{ N_("addcardkey"), cmdADDCARDKEY , 1,1, N_("add a key to a smartcard") }, { N_("addcardkey"), cmdADDCARDKEY , 1,1, N_("add a key to a smartcard") },
#endif /* ENABLE_CARD_SUPPORT */ { N_("keytocard"), cmdKEYTOCARD , 1,2, N_("move a key to a smartcard")},
#endif /*ENABLE_CARD_SUPPORT*/
{ N_("delkey") , cmdDELKEY , 0,1, N_("delete a secondary key") }, { N_("delkey") , cmdDELKEY , 0,1, N_("delete a secondary key") },
{ N_("addrevoker"),cmdADDREVOKER,1,1, N_("add a revocation key") }, { N_("addrevoker"),cmdADDREVOKER,1,1, N_("add a revocation key") },
{ N_("delsig") , cmdDELSIG , 0,1, N_("delete signatures") }, { N_("delsig") , cmdDELSIG , 0,1, N_("delete signatures") },
@ -1256,6 +1285,7 @@ keyedit_menu( const char *username, STRLIST locusr,
KBNODE sec_keyblock = NULL; KBNODE sec_keyblock = NULL;
KEYDB_HANDLE sec_kdbhd = NULL; KEYDB_HANDLE sec_kdbhd = NULL;
KBNODE cur_keyblock; KBNODE cur_keyblock;
KBNODE node;
char *answer = NULL; char *answer = NULL;
int redisplay = 1; int redisplay = 1;
int modified = 0; int modified = 0;
@ -1379,7 +1409,8 @@ keyedit_menu( const char *username, STRLIST locusr,
tty_printf(_("Need the secret key to do this.\n")); tty_printf(_("Need the secret key to do this.\n"));
cmd = cmdNOP; cmd = cmdNOP;
} }
else if( cmds[i].not_with_sk && sec_keyblock && toggle ) { else if( (cmds[i].not_with_sk == 1 && sec_keyblock && toggle)
||(cmds[i].not_with_sk == 2 && sec_keyblock && !toggle)) {
tty_printf(_("Please use the command \"toggle\" first.\n")); tty_printf(_("Please use the command \"toggle\" first.\n"));
cmd = cmdNOP; cmd = cmdNOP;
} }
@ -1543,6 +1574,38 @@ keyedit_menu( const char *username, STRLIST locusr,
merge_keys_and_selfsig( keyblock ); merge_keys_and_selfsig( keyblock );
} }
break; break;
case cmdKEYTOCARD:
node = NULL;
switch ( count_selected_keys (sec_keyblock) )
{
case 0:
if (cpr_get_answer_is_yes("keyedit.keytocard.use_primary",
_("Really move the primary key? ")))
node = sec_keyblock;
break;
case 1:
for (node = sec_keyblock; node; node = node->next )
{
if (node->pkt->pkttype == PKT_SECRET_SUBKEY
&& node->flag & NODFLG_SELKEY)
break;
}
break;
default:
tty_printf(_("You must select exactly one key.\n"));
break;
}
if (node)
{
PKT_public_key *xxpk = find_pk_from_sknode (keyblock, node);
if (card_store_subkey (node, xxpk?xxpk->pubkey_usage:0))
{
redisplay = 1;
sec_modified = 1;
}
}
break;
#endif /* ENABLE_CARD_SUPPORT */ #endif /* ENABLE_CARD_SUPPORT */
case cmdDELKEY: { case cmdDELKEY: {
@ -2176,6 +2239,8 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
tty_printf(_("expired: %s"),expirestr_from_pk(pk)); tty_printf(_("expired: %s"),expirestr_from_pk(pk));
else else
tty_printf(_("expires: %s"),expirestr_from_pk(pk)); tty_printf(_("expires: %s"),expirestr_from_pk(pk));
tty_printf(" ");
tty_printf(_("usage: %s"),usagestr_from_pk(pk));
tty_printf("\n"); tty_printf("\n");
if( node->pkt->pkttype == PKT_PUBLIC_KEY ) if( node->pkt->pkttype == PKT_PUBLIC_KEY )

View File

@ -1177,6 +1177,14 @@ ask_algo (int addmode, unsigned int *r_usage)
tty_printf( _(" (%d) RSA (encrypt only)\n"), 5 ); tty_printf( _(" (%d) RSA (encrypt only)\n"), 5 );
if (opt.expert) if (opt.expert)
tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 6 ); tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 6 );
if (opt.expert && addmode)
tty_printf( _(" (%d) RSA (auth only)\n"), 7 );
if (opt.expert)
tty_printf( _(" (%d) RSA (sign and auth)\n"), 8 );
if (opt.expert && addmode)
tty_printf( _(" (%d) RSA (encrypt and auth)\n"), 9 );
if (opt.expert)
tty_printf( _(" (%d) RSA (sign, encrypt and auth)\n"), 10 );
for(;;) { for(;;) {
answer = cpr_get("keygen.algo",_("Your selection? ")); answer = cpr_get("keygen.algo",_("Your selection? "));
@ -1187,6 +1195,26 @@ ask_algo (int addmode, unsigned int *r_usage)
algo = 0; /* create both keys */ algo = 0; /* create both keys */
break; break;
} }
else if( algo == 10 && opt.expert ) {
algo = PUBKEY_ALGO_RSA;
*r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
break;
}
else if( algo == 9 && opt.expert && addmode) {
algo = PUBKEY_ALGO_RSA;
*r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH;
break;
}
else if( algo == 8 && opt.expert ) {
algo = PUBKEY_ALGO_RSA;
*r_usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
break;
}
else if( algo == 7 && opt.expert && addmode) {
algo = PUBKEY_ALGO_RSA;
*r_usage = PUBKEY_USAGE_AUTH;
break;
}
else if( algo == 6 && opt.expert ) { else if( algo == 6 && opt.expert ) {
algo = PUBKEY_ALGO_RSA; algo = PUBKEY_ALGO_RSA;
*r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG; *r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG;

View File

@ -535,6 +535,35 @@ revokestr_from_pk( PKT_public_key *pk )
return mk_datestr (buffer, atime); return mk_datestr (buffer, atime);
} }
const char *
usagestr_from_pk( PKT_public_key *pk )
{
static char buffer[10];
int i = 0;
unsigned int use = pk->pubkey_usage;
if ( use & PUBKEY_USAGE_SIG )
{
if (pk->is_primary)
buffer[i++] = 'C';
buffer[i++] = 'S';
}
if ( use & PUBKEY_USAGE_ENC )
buffer[i++] = 'E';
if ( (use & PUBKEY_USAGE_AUTH) )
buffer[i++] = 'A';
while (i < 4)
buffer[i++] = ' ';
buffer[i] = 0;
return buffer;
}
const char * const char *
colon_strtime (u32 t) colon_strtime (u32 t)
{ {

View File

@ -262,6 +262,7 @@ void change_pin (int no);
void card_status (FILE *fp, char *serialno, size_t serialnobuflen); void card_status (FILE *fp, char *serialno, size_t serialnobuflen);
void card_edit (STRLIST commands); void card_edit (STRLIST commands);
int card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock); int card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock);
int card_store_subkey (KBNODE node, int use);
#endif #endif
#endif /*G10_MAIN_H*/ #endif /*G10_MAIN_H*/