summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2004-09-23 21:34:45 +0200
committerWerner Koch <wk@gnupg.org>2004-09-23 21:34:45 +0200
commitf36154535e344ee4771f9d1c7676961fa330ed96 (patch)
tree92f297e3c222b40d9afd7d10b154d61b19b6840b
parent* gpg.sgml: Document "addcardkey" and "keytocard". (diff)
downloadgnupg2-f36154535e344ee4771f9d1c7676961fa330ed96.tar.xz
gnupg2-f36154535e344ee4771f9d1c7676961fa330ed96.zip
Note: I have not fully tested the new key creation due to a pc/sc
error. However the backupfile has been created successfully. * rsa.c (rsa_generate): Return the dummy list of factors only if the caller asked for it. * card_util.c (generate_card_keys): ask whether backup should be created. (card_store_subkey): Factored some code out to .. * keygen.c (save_unprotected_key_to_card): .. new function. (gen_card_key_with_backup): New. (generate_raw_key): New. (generate_keypair): New arg BACKUP_ENCRYPTION_DIR. Changed all callers. (do_generate_keypair): Divert to gen_card_key_with_backup when desired.
-rw-r--r--cipher/ChangeLog5
-rw-r--r--cipher/rsa.c3
-rw-r--r--g10/ChangeLog15
-rw-r--r--g10/app-openpgp.c126
-rw-r--r--g10/card-util.c135
-rw-r--r--g10/g10.c4
-rw-r--r--g10/keygen.c675
-rw-r--r--g10/main.h4
8 files changed, 652 insertions, 315 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 25cc2657c..47f09ca00 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,8 @@
+2004-09-23 Werner Koch <wk@g10code.com>
+
+ * rsa.c (rsa_generate): Return the dummy list of factors only if
+ the caller asked for it.
+
2004-05-20 David Shaw <dshaw@jabberwocky.com>
* dsa.c (verify): s/exp/exponent/ to fix a compiler warning. From
diff --git a/cipher/rsa.c b/cipher/rsa.c
index 7eb757a97..e41ff2481 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -353,7 +353,8 @@ rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
skey[4] = sk.q;
skey[5] = sk.u;
/* make an empty list of factors */
- *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+ if (retfactors)
+ *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
return 0;
}
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 667115d2a..96e724edf 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,5 +1,16 @@
2004-09-23 Werner Koch <wk@g10code.com>
+ * card_util.c (generate_card_keys): ask whether backup should be
+ created.
+ (card_store_subkey): Factored some code out to ..
+ * keygen.c (save_unprotected_key_to_card): .. new function.
+ (gen_card_key_with_backup): New.
+ (generate_raw_key): New.
+ (generate_keypair): New arg BACKUP_ENCRYPTION_DIR. Changed all
+ callers.
+ (do_generate_keypair): Divert to gen_card_key_with_backup when
+ desired.
+
* apdu.c (open_pcsc_reader): Do not print empty reader string.
* keygen.c (ask_algo): Allow creation of AUTH keys.
@@ -7,6 +18,9 @@
* keyid.c (usagestr_from_pk): New.
* app-openpgp.c (app_openpgp_storekey): Call flush_cache.
+ (get_cached_data): Move local data initialization to ..
+ (app_select_openpgp): .. here. Read some flags for later use.
+ (do_getattr): New read-only attribute EXTCAP.
* keyedit.c (keyedit_menu): New command "keytocard"
(keyedit_menu): Bad hack for the not_with_sk element.
@@ -15,6 +29,7 @@
* card-util.c (card_store_subkey): New.
(copy_mpi): New.
+
* cardglue.c (agent_openpgp_storekey): New.
2004-09-22 Werner Koch <wk@g10code.com>
diff --git a/g10/app-openpgp.c b/g10/app-openpgp.c
index 096e66e78..e4c147714 100644
--- a/g10/app-openpgp.c
+++ b/g10/app-openpgp.c
@@ -63,11 +63,11 @@ static struct {
{ 0x006E, 1, 0, 1, 0, 0, "Application Related Data" },
{ 0x004F, 0, 0x6E, 1, 0, 0, "AID" },
{ 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" },
- { 0x0047, 0, 0x6E, 1, 0, 0, "Card Capabilities" },
- { 0x00C0, 0, 0x6E, 1, 0, 0, "Extended Card Capabilities" },
- { 0x00C1, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Signature" },
- { 0x00C2, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Decryption" },
- { 0x00C3, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Authentication" },
+ { 0x0047, 0, 0x6E, 1, 1, 0, "Card Capabilities" },
+ { 0x00C0, 0, 0x6E, 1, 1, 0, "Extended Card Capabilities" },
+ { 0x00C1, 0, 0x6E, 1, 1, 0, "Algorithm Attributes Signature" },
+ { 0x00C2, 0, 0x6E, 1, 1, 0, "Algorithm Attributes Decryption" },
+ { 0x00C3, 0, 0x6E, 1, 1, 0, "Algorithm Attributes Authentication" },
{ 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" },
{ 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" },
{ 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" },
@@ -86,6 +86,13 @@ struct cache_s {
struct app_local_s {
struct cache_s *cache;
+ struct
+ {
+ unsigned int get_challenge:1;
+ unsigned int key_import:1;
+ unsigned int change_force_chv:1;
+ unsigned int private_dos:1;
+ } extcap;
};
@@ -127,25 +134,23 @@ get_cached_data (app_t app, int tag,
*result = NULL;
*resultlen = 0;
- if (app->app_local)
- {
- for (c=app->app_local->cache; c; c = c->next)
- if (c->tag == tag)
+ for (c=app->app_local->cache; c; c = c->next)
+ if (c->tag == tag)
+ {
+ if(c->length)
{
- if(c->length)
- {
- p = xtrymalloc (c->length);
- if (!p)
- return gpg_error (gpg_err_code_from_errno (errno));
- memcpy (p, c->data, c->length);
- *result = p;
- }
-
- *resultlen = c->length;
-
- return 0;
+ p = xtrymalloc (c->length);
+ if (!p)
+ return gpg_error (gpg_err_code_from_errno (errno));
+ memcpy (p, c->data, c->length);
+ *result = p;
}
- }
+
+ *resultlen = c->length;
+
+ return 0;
+ }
+
err = iso7816_get_data (app->slot, tag, &p, &len);
if (err)
@@ -163,24 +168,18 @@ get_cached_data (app_t app, int tag,
}
/* No, cache it. */
- if (!app->app_local)
- app->app_local = xtrycalloc (1, sizeof *app->app_local);
- /* Note that we can safely ignore out of core errors. */
- if (app->app_local)
+ for (c=app->app_local->cache; c; c = c->next)
+ assert (c->tag != tag);
+
+ c = xtrymalloc (sizeof *c + len);
+ if (c)
{
- for (c=app->app_local->cache; c; c = c->next)
- assert (c->tag != tag);
-
- c = xtrymalloc (sizeof *c + len);
- if (c)
- {
- memcpy (c->data, p, len);
- c->length = len;
- c->tag = tag;
- c->next = app->app_local->cache;
- app->app_local->cache = c;
- }
+ memcpy (c->data, p, len);
+ c->length = len;
+ c->tag = tag;
+ c->next = app->app_local->cache;
+ app->app_local->cache = c;
}
return 0;
@@ -505,6 +504,7 @@ do_getattr (APP app, CTRL ctrl, const char *name)
{ "SIG-COUNTER", 0x0093, 2 },
{ "SERIALNO", 0x004F, -1 },
{ "AID", 0x004F },
+ { "EXTCAP", 0x0000, -2 },
{ NULL, 0 }
};
int idx, i;
@@ -539,6 +539,18 @@ do_getattr (APP app, CTRL ctrl, const char *name)
}
return 0;
}
+ if (table[idx].special == -2)
+ {
+ char tmp[50];
+
+ sprintf (tmp, "gc=%d ki=%d fc=%d pd=%d",
+ app->app_local->extcap.get_challenge,
+ app->app_local->extcap.key_import,
+ app->app_local->extcap.change_force_chv,
+ app->app_local->extcap.private_dos);
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ return 0;
+ }
relptr = get_one_do (app, table[idx].tag, &value, &valuelen);
if (relptr)
@@ -578,6 +590,7 @@ do_getattr (APP app, CTRL ctrl, const char *name)
static int
do_learn_status (APP app, CTRL ctrl)
{
+ do_getattr (app, ctrl, "EXTCAP");
do_getattr (app, ctrl, "DISP-NAME");
do_getattr (app, ctrl, "DISP-LANG");
do_getattr (app, ctrl, "DISP-SEX");
@@ -1378,11 +1391,14 @@ app_select_openpgp (APP app)
rc = iso7816_select_application (slot, aid, sizeof aid);
if (!rc)
{
+ unsigned int manufacturer;
+
app->apptype = "OPENPGP";
app->did_chv1 = 0;
app->did_chv2 = 0;
app->did_chv3 = 0;
+ app->app_local = NULL;
/* The OpenPGP card returns the serial number as part of the
AID; because we prefer to use OpenPGP serial numbers, we
@@ -1400,10 +1416,18 @@ app_select_openpgp (APP app)
app->card_version = buffer[6] << 8;
app->card_version |= buffer[7];
+ manufacturer = (buffer[8]<<8 | buffer[9]);
+
xfree (app->serialno);
app->serialno = buffer;
app->serialnolen = buflen;
buffer = NULL;
+ app->app_local = xtrycalloc (1, sizeof *app->app_local);
+ if (!app->app_local)
+ {
+ rc = gpg_error (gpg_err_code_from_errno (errno));
+ goto leave;
+ }
relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
if (!relptr)
@@ -1413,7 +1437,29 @@ app_select_openpgp (APP app)
}
app->force_chv1 = (buflen && *buffer == 0);
xfree (relptr);
-
+
+ relptr = get_one_do (app, 0x00C0, &buffer, &buflen);
+ if (!relptr)
+ {
+ log_error ("can't access Extended Capability Flags - "
+ "invalid OpenPGP card?\n");
+ goto leave;
+ }
+ if (buflen)
+ {
+ app->app_local->extcap.get_challenge = !!(*buffer & 0x40);
+ app->app_local->extcap.key_import = !!(*buffer & 0x20);
+ app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
+ app->app_local->extcap.private_dos = !!(*buffer & 0x08);
+ }
+ xfree (relptr);
+
+ /* Some of the first cards accidently don't set the
+ CHANGE_FORCE_CHV bit but allow it anyway. */
+ if (app->card_version <= 0x0100 && manufacturer == 1)
+ app->app_local->extcap.change_force_chv = 1;
+
+
if (opt.verbose > 1)
dump_all_do (slot);
@@ -1431,6 +1477,8 @@ app_select_openpgp (APP app)
}
leave:
+ if (rc)
+ do_deinit (app);
return rc;
}
diff --git a/g10/card-util.c b/g10/card-util.c
index c5cd344b6..5b3a33e5b 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -43,39 +43,6 @@
#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
function. */
@@ -897,10 +864,15 @@ generate_card_keys (const char *serialno)
{
struct agent_card_info_s info;
int forced_chv1;
+ int want_backup;
if (get_info_for_key_operation (&info))
return;
+ want_backup = !(cpr_get_answer_is_yes
+ ( "cardedit.genkeys.backup_enc",
+ _("Inhibit creation of encryption key backup? ")));
+
if ( (info.fpr1valid && !fpr_is_zero (info.fpr1))
|| (info.fpr2valid && !fpr_is_zero (info.fpr2))
|| (info.fpr3valid && !fpr_is_zero (info.fpr3)))
@@ -928,7 +900,8 @@ generate_card_keys (const char *serialno)
if (check_pin_for_key_operation (&info, &forced_chv1))
goto leave;
- generate_keypair (NULL, info.serialno);
+ generate_keypair (NULL, info.serialno,
+ want_backup? opt.homedir:NULL);
leave:
agent_release_card_info (&info);
@@ -1003,12 +976,6 @@ card_store_subkey (KBNODE node, int use)
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];
@@ -1087,94 +1054,9 @@ card_store_subkey (KBNODE node, int use)
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);
-
+ rc = save_unprotected_key_to_card (sk, keyno);
if (rc)
goto leave;
- xfree (template);
- template = NULL;
/* Get back to the maybe protected original secret key. */
if (copied_sk)
@@ -1205,7 +1087,6 @@ card_store_subkey (KBNODE node, int use)
leave:
if (copied_sk)
free_secret_key (copied_sk);
- xfree (template);
agent_release_card_info (&info);
return okay;
}
diff --git a/g10/g10.c b/g10/g10.c
index 66692f79e..d6b65a017 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -3181,12 +3181,12 @@ main( int argc, char **argv )
if( opt.batch ) {
if( argc > 1 )
wrong_args("--gen-key [parameterfile]");
- generate_keypair( argc? *argv : NULL, NULL );
+ generate_keypair( argc? *argv : NULL, NULL, NULL );
}
else {
if( argc )
wrong_args("--gen-key");
- generate_keypair(NULL, NULL);
+ generate_keypair(NULL, NULL, NULL);
}
break;
diff --git a/g10/keygen.c b/g10/keygen.c
index 23bbed1ee..96afad4e8 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -63,7 +63,8 @@ enum para_name {
pPASSPHRASE,
pPASSPHRASE_DEK,
pPASSPHRASE_S2K,
- pSERIALNO
+ pSERIALNO,
+ pBACKUPENCDIR
};
struct para_data_s {
@@ -120,6 +121,47 @@ static int write_keyblock( IOBUF out, KBNODE node );
static int gen_card_key (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root,
u32 expireval, struct para_data_s *para);
+static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
+ KBNODE pub_root, KBNODE sec_root,
+ u32 expireval, struct para_data_s *para,
+ const char *backup_dir);
+
+
+#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;
+}
+
+
+
static void
write_uid( KBNODE root, const char *s )
@@ -1622,6 +1664,7 @@ ask_user_id( int mode )
}
+/* FIXME: We need a way to cancel this prompt. */
static DEK *
do_ask_passphrase( STRING2KEY **ret_s2k )
{
@@ -2213,10 +2256,14 @@ read_parameter_file( const char *fname )
/*
* Generate a keypair (fname is only used in batch mode) If
* CARD_SERIALNO is not NULL the fucntion will create the keys on an
- * OpenPGP Card.
+ * OpenPGP Card. If BACKUP_ENCRYPTION_DIR has been set and
+ * CARD_SERIALNO is NOT NULL, the encryption key for the card gets
+ * generate in software, imported to the card and a backup file
+ * written to directory given by this argument .
*/
void
-generate_keypair( const char *fname, const char *card_serialno )
+generate_keypair (const char *fname, const char *card_serialno,
+ const char *backup_encryption_dir)
{
unsigned int nbits;
char *uid = NULL;
@@ -2239,158 +2286,245 @@ generate_keypair( const char *fname, const char *card_serialno )
return;
}
- if (opt.batch)
- {
- read_parameter_file( fname );
- return;
- }
-
- if (card_serialno)
- {
+ if (opt.batch)
+ {
+ read_parameter_file( fname );
+ return;
+ }
+
+ if (card_serialno)
+ {
#ifdef ENABLE_CARD_SUPPORT
- r = xcalloc (1, sizeof *r + strlen (card_serialno) );
- r->key = pSERIALNO;
- strcpy( r->u.value, card_serialno);
- r->next = para;
- para = r;
+ r = xcalloc (1, sizeof *r + strlen (card_serialno) );
+ r->key = pSERIALNO;
+ strcpy( r->u.value, card_serialno);
+ r->next = para;
+ para = r;
- algo = PUBKEY_ALGO_RSA;
+ algo = PUBKEY_ALGO_RSA;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYUSAGE;
- strcpy (r->u.value, "sign");
- r->next = para;
- para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ strcpy (r->u.value, "sign");
+ r->next = para;
+ para = r;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pSUBKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pSUBKEYUSAGE;
- strcpy (r->u.value, "encrypt");
- r->next = para;
- para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pSUBKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pSUBKEYUSAGE;
+ strcpy (r->u.value, "encrypt");
+ r->next = para;
+ para = r;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pAUTHKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pAUTHKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+
+ if (backup_encryption_dir)
+ {
+ r = xcalloc (1, sizeof *r + strlen (backup_encryption_dir) );
+ r->key = pBACKUPENCDIR;
+ strcpy (r->u.value, backup_encryption_dir);
+ r->next = para;
+ para = r;
+ }
#endif /*ENABLE_CARD_SUPPORT*/
- }
- else
- {
- algo = ask_algo( 0, &use );
- if( !algo )
- { /* default: DSA with ElG subkey of the specified size */
- both = 1;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
- r->next = para;
- para = r;
- tty_printf(_("DSA keypair will have 1024 bits.\n"));
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYLENGTH;
- strcpy( r->u.value, "1024" );
- r->next = para;
- para = r;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYUSAGE;
- strcpy( r->u.value, "sign" );
- r->next = para;
- para = r;
+ }
+ else
+ {
+ algo = ask_algo( 0, &use );
+ if( !algo )
+ { /* default: DSA with ElG subkey of the specified size */
+ both = 1;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
+ r->next = para;
+ para = r;
+ tty_printf(_("DSA keypair will have 1024 bits.\n"));
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYLENGTH;
+ strcpy( r->u.value, "1024" );
+ r->next = para;
+ para = r;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ strcpy( r->u.value, "sign" );
+ r->next = para;
+ para = r;
- algo = PUBKEY_ALGO_ELGAMAL_E;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pSUBKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pSUBKEYUSAGE;
- strcpy( r->u.value, "encrypt" );
- r->next = para;
- para = r;
- }
- else
- {
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
+ algo = PUBKEY_ALGO_ELGAMAL_E;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pSUBKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pSUBKEYUSAGE;
+ strcpy( r->u.value, "encrypt" );
+ r->next = para;
+ para = r;
+ }
+ else
+ {
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
- if (use)
- {
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYUSAGE;
- sprintf( r->u.value, "%s%s",
- (use & PUBKEY_USAGE_SIG)? "sign ":"",
- (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
- r->next = para;
- para = r;
- }
+ if (use)
+ {
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ sprintf( r->u.value, "%s%s",
+ (use & PUBKEY_USAGE_SIG)? "sign ":"",
+ (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+ r->next = para;
+ para = r;
+ }
- }
+ }
- nbits = ask_keysize( algo );
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
- sprintf( r->u.value, "%u", nbits);
- r->next = para;
- para = r;
- }
-
- expire = ask_expire_interval(0);
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYEXPIRE;
- r->u.expire = expire;
- r->next = para;
- para = r;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pSUBKEYEXPIRE;
- r->u.expire = expire;
- r->next = para;
- para = r;
-
- uid = ask_user_id(0);
- if( !uid )
- {
- log_error(_("Key generation canceled.\n"));
- release_parameter_list( para );
- return;
- }
- r = m_alloc_clear( sizeof *r + strlen(uid) );
- r->key = pUSERID;
- strcpy( r->u.value, uid );
- r->next = para;
- para = r;
+ nbits = ask_keysize( algo );
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+ sprintf( r->u.value, "%u", nbits);
+ r->next = para;
+ para = r;
+ }
+
+ expire = ask_expire_interval(0);
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYEXPIRE;
+ r->u.expire = expire;
+ r->next = para;
+ para = r;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pSUBKEYEXPIRE;
+ r->u.expire = expire;
+ r->next = para;
+ para = r;
+
+ uid = ask_user_id(0);
+ if( !uid )
+ {
+ log_error(_("Key generation canceled.\n"));
+ release_parameter_list( para );
+ return;
+ }
+ r = m_alloc_clear( sizeof *r + strlen(uid) );
+ r->key = pUSERID;
+ strcpy( r->u.value, uid );
+ r->next = para;
+ para = r;
- dek = card_serialno? NULL : do_ask_passphrase( &s2k );
- if( dek )
- {
- r = m_alloc_clear( sizeof *r );
- r->key = pPASSPHRASE_DEK;
- r->u.dek = dek;
- r->next = para;
- para = r;
- r = m_alloc_clear( sizeof *r );
- r->key = pPASSPHRASE_S2K;
- r->u.s2k = s2k;
- r->next = para;
- para = r;
- }
+ dek = card_serialno? NULL : do_ask_passphrase( &s2k );
+ if( dek )
+ {
+ r = m_alloc_clear( sizeof *r );
+ r->key = pPASSPHRASE_DEK;
+ r->u.dek = dek;
+ r->next = para;
+ para = r;
+ r = m_alloc_clear( sizeof *r );
+ r->key = pPASSPHRASE_S2K;
+ r->u.s2k = s2k;
+ r->next = para;
+ para = r;
+ }
- proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
- release_parameter_list( para );
+ proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
+ release_parameter_list( para );
+}
+
+
+/* Generate a raw key and return it as a secret key packet. The
+ function will ask for the passphrase and return a protected as well
+ as an unprotected copy of a new secret key packet. 0 is returned
+ on success and the caller must then free the returned values. */
+static int
+generate_raw_key (int algo, unsigned int nbits, u32 created_at,
+ PKT_secret_key **r_sk_unprotected,
+ PKT_secret_key **r_sk_protected)
+{
+ int rc;
+ DEK *dek = NULL;
+ STRING2KEY *s2k = NULL;
+ PKT_secret_key *sk = NULL;
+ int i;
+ size_t nskey, npkey;
+
+ npkey = pubkey_get_npkey (algo);
+ nskey = pubkey_get_nskey (algo);
+ assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);
+
+ if (nbits < 512)
+ {
+ nbits = 512;
+ log_info (_("keysize invalid; using %u bits\n"), nbits );
+ }
+
+ if ((nbits % 32))
+ {
+ nbits = ((nbits + 31) / 32) * 32;
+ log_info(_("keysize rounded up to %u bits\n"), nbits );
+ }
+
+ dek = do_ask_passphrase (&s2k);
+
+ sk = m_alloc_clear (sizeof *sk);
+ sk->timestamp = created_at;
+ sk->version = 4;
+ sk->pubkey_algo = algo;
+
+ rc = pubkey_generate (algo, nbits, sk->skey, NULL);
+ if (rc)
+ {
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
+ goto leave;
+ }
+
+ for (i=npkey; i < nskey; i++)
+ sk->csum += checksum_mpi (sk->skey[i]);
+
+ if (r_sk_unprotected)
+ *r_sk_unprotected = copy_secret_key (NULL, sk);
+
+ if (dek)
+ {
+ sk->protect.algo = dek->algo;
+ sk->protect.s2k = *s2k;
+ rc = protect_secret_key (sk, dek);
+ if (rc)
+ {
+ log_error ("protect_secret_key failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ }
+ if (r_sk_protected)
+ {
+ *r_sk_protected = sk;
+ sk = NULL;
+ }
+
+ leave:
+ if (sk)
+ free_secret_key (sk);
+ m_free (dek);
+ m_free (s2k);
+ return rc;
}
@@ -2552,8 +2686,20 @@ do_generate_keypair( struct para_data_s *para,
}
else
{
- rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
- get_parameter_u32 (para, pKEYEXPIRE), para);
+ if ((s = get_parameter_value (para, pBACKUPENCDIR)))
+ {
+ /* A backup of the encryption key has been requested.
+ Generate the key i software and import it then to
+ the card. Write a backup file. */
+ rc = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0,
+ pub_root, sec_root,
+ get_parameter_u32 (para,
+ pKEYEXPIRE),
+ para, s);
+ }
+ else
+ rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
+ get_parameter_u32 (para, pKEYEXPIRE), para);
}
if( !rc )
@@ -2943,6 +3089,7 @@ gen_card_key (int algo, int keyno, int is_primary,
PKT_public_key *pk;
assert (algo == PUBKEY_ALGO_RSA);
+
rc = agent_scd_genkey (&info, keyno, 1);
/* if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
@@ -3006,3 +3153,241 @@ gen_card_key (int algo, int keyno, int is_primary,
return -1;
#endif /*!ENABLE_CARD_SUPPORT*/
}
+
+
+
+static int
+gen_card_key_with_backup (int algo, int keyno, int is_primary,
+ KBNODE pub_root, KBNODE sec_root,
+ u32 expireval, struct para_data_s *para,
+ const char *backup_dir)
+{
+#ifdef ENABLE_CARD_SUPPORT
+ int rc;
+ const char *s;
+ PACKET *pkt;
+ PKT_secret_key *sk, *sk_unprotected, *sk_protected;
+ PKT_public_key *pk;
+ size_t n;
+ int i;
+
+ rc = generate_raw_key (algo, 1024, make_timestamp (),
+ &sk_unprotected, &sk_protected);
+ if (rc)
+ return rc;
+
+ /* First, store the key to the card. */
+ rc = save_unprotected_key_to_card (sk_unprotected, keyno);
+ if (rc)
+ {
+ log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
+ free_secret_key (sk_unprotected);
+ free_secret_key (sk_protected);
+ return rc;
+ }
+
+ /* Get rid of the secret key parameters and store the serial numer. */
+ sk = sk_unprotected;
+ 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 = get_parameter_value (para, pSERIALNO);
+ assert (s);
+ 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);
+
+ /* Now write the *protected* secret key to the file. */
+ {
+ char name_buffer[50];
+ char *fname;
+ IOBUF fp;
+ mode_t oldmask;
+
+ keyid_from_sk (sk, NULL);
+ sprintf (name_buffer,"sk_%08lX%08lX.gpg",
+ (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
+
+ fname = make_filename (backup_dir, name_buffer, NULL);
+ oldmask = umask (077);
+ fp = iobuf_create (fname);
+ umask (oldmask);
+ if (!fp)
+ {
+ log_error (_("can't create backup file `%s': %s\n"),
+ fname, strerror(errno) );
+ m_free (fname);
+ free_secret_key (sk_unprotected);
+ free_secret_key (sk_protected);
+ return G10ERR_OPEN_FILE;
+ }
+
+ pkt = xcalloc (1, sizeof *pkt);
+ pkt->pkttype = PKT_SECRET_KEY;
+ pkt->pkt.secret_key = sk_protected;
+ sk_protected = NULL;
+
+ rc = build_packet (fp, pkt);
+ if (rc)
+ {
+ log_error("build packet failed: %s\n", g10_errstr(rc) );
+ iobuf_cancel (fp);
+ }
+ else
+ {
+ iobuf_close (fp);
+ iobuf_ioctl (NULL, 2, 0, (char*)fname);
+ log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+ }
+ free_packet (pkt);
+ m_free (pkt);
+ m_free (fname);
+ if (rc)
+ {
+ free_secret_key (sk_unprotected);
+ return rc;
+ }
+ }
+
+ /* Create the public key from the secret key. */
+ pk = xcalloc (1, sizeof *pk );
+ pk->timestamp = sk->timestamp;
+ pk->version = sk->version;
+ if (expireval)
+ pk->expiredate = sk->expiredate = sk->timestamp + expireval;
+ pk->pubkey_algo = sk->pubkey_algo;
+ n = pubkey_get_npkey (sk->pubkey_algo);
+ for (i=0; i < n; i++)
+ pk->pkey[i] = mpi_copy (sk->skey[i]);
+
+ /* Build packets and add them to the node lists. */
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+ pkt->pkt.public_key = pk;
+ add_kbnode(pub_root, new_kbnode( pkt ));
+
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+ pkt->pkt.secret_key = sk;
+ add_kbnode(sec_root, new_kbnode( pkt ));
+
+ return 0;
+#else
+ return -1;
+#endif /*!ENABLE_CARD_SUPPORT*/
+}
+
+
+#ifdef ENABLE_CARD_SUPPORT
+int
+save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
+{
+ int rc;
+ 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;
+
+ assert (is_RSA (sk->pubkey_algo));
+ assert (!sk->is_protected);
+
+ rc = -1;
+ /* 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);
+
+ leave:
+ xfree (template);
+ return rc;
+}
+#endif /*ENABLE_CARD_SUPPORT*/
diff --git a/g10/main.h b/g10/main.h
index 0205f7e00..1326bd442 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -153,7 +153,8 @@ void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/
u32 ask_expire_interval(int object);
u32 ask_expiredate(void);
-void generate_keypair( const char *fname, const char *card_serialno );
+void generate_keypair( const char *fname, const char *card_serialno,
+ const char *backup_encryption_dir );
int keygen_set_std_prefs (const char *string,int personal);
PKT_user_id *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
@@ -165,6 +166,7 @@ int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
#ifdef ENABLE_CARD_SUPPORT
int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
int keyno, const char *serialno);
+int save_unprotected_key_to_card (PKT_secret_key *sk, int keyno);
#endif
/*-- openfile.c --*/