1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

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.
This commit is contained in:
Werner Koch 2004-09-23 19:34:45 +00:00
parent 42c18de83a
commit f36154535e
8 changed files with 651 additions and 314 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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>

View File

@ -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;
}

View File

@ -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);
rc = save_unprotected_key_to_card (sk, keyno);
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)
@ -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;
}

View File

@ -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;

View File

@ -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 (opt.batch)
{
read_parameter_file( fname );
return;
}
if (card_serialno)
{
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;
}
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;
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;
}
proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
release_parameter_list( para );
}
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;
}
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*/

View File

@ -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 --*/