diff options
author | Werner Koch <wk@gnupg.org> | 2004-09-23 21:34:45 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2004-09-23 21:34:45 +0200 |
commit | f36154535e344ee4771f9d1c7676961fa330ed96 (patch) | |
tree | 92f297e3c222b40d9afd7d10b154d61b19b6840b | |
parent | * gpg.sgml: Document "addcardkey" and "keytocard". (diff) | |
download | gnupg2-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/ChangeLog | 5 | ||||
-rw-r--r-- | cipher/rsa.c | 3 | ||||
-rw-r--r-- | g10/ChangeLog | 15 | ||||
-rw-r--r-- | g10/app-openpgp.c | 126 | ||||
-rw-r--r-- | g10/card-util.c | 135 | ||||
-rw-r--r-- | g10/g10.c | 4 | ||||
-rw-r--r-- | g10/keygen.c | 675 | ||||
-rw-r--r-- | g10/main.h | 4 |
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; } @@ -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 --*/ |