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:
parent
42c18de83a
commit
f36154535e
@ -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>
|
2004-05-20 David Shaw <dshaw@jabberwocky.com>
|
||||||
|
|
||||||
* dsa.c (verify): s/exp/exponent/ to fix a compiler warning. From
|
* dsa.c (verify): s/exp/exponent/ to fix a compiler warning. From
|
||||||
|
@ -353,7 +353,8 @@ rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
|
|||||||
skey[4] = sk.q;
|
skey[4] = sk.q;
|
||||||
skey[5] = sk.u;
|
skey[5] = sk.u;
|
||||||
/* make an empty list of factors */
|
/* make an empty list of factors */
|
||||||
*retfactors = m_alloc_clear( 1 * sizeof **retfactors );
|
if (retfactors)
|
||||||
|
*retfactors = m_alloc_clear( 1 * sizeof **retfactors );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
2004-09-23 Werner Koch <wk@g10code.com>
|
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.
|
* apdu.c (open_pcsc_reader): Do not print empty reader string.
|
||||||
|
|
||||||
* keygen.c (ask_algo): Allow creation of AUTH keys.
|
* keygen.c (ask_algo): Allow creation of AUTH keys.
|
||||||
@ -7,6 +18,9 @@
|
|||||||
* keyid.c (usagestr_from_pk): New.
|
* keyid.c (usagestr_from_pk): New.
|
||||||
|
|
||||||
* app-openpgp.c (app_openpgp_storekey): Call flush_cache.
|
* 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.c (keyedit_menu): New command "keytocard"
|
||||||
(keyedit_menu): Bad hack for the not_with_sk element.
|
(keyedit_menu): Bad hack for the not_with_sk element.
|
||||||
@ -15,6 +29,7 @@
|
|||||||
|
|
||||||
* card-util.c (card_store_subkey): New.
|
* card-util.c (card_store_subkey): New.
|
||||||
(copy_mpi): New.
|
(copy_mpi): New.
|
||||||
|
|
||||||
* cardglue.c (agent_openpgp_storekey): New.
|
* cardglue.c (agent_openpgp_storekey): New.
|
||||||
|
|
||||||
2004-09-22 Werner Koch <wk@g10code.com>
|
2004-09-22 Werner Koch <wk@g10code.com>
|
||||||
|
@ -63,11 +63,11 @@ static struct {
|
|||||||
{ 0x006E, 1, 0, 1, 0, 0, "Application Related Data" },
|
{ 0x006E, 1, 0, 1, 0, 0, "Application Related Data" },
|
||||||
{ 0x004F, 0, 0x6E, 1, 0, 0, "AID" },
|
{ 0x004F, 0, 0x6E, 1, 0, 0, "AID" },
|
||||||
{ 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" },
|
{ 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" },
|
||||||
{ 0x0047, 0, 0x6E, 1, 0, 0, "Card Capabilities" },
|
{ 0x0047, 0, 0x6E, 1, 1, 0, "Card Capabilities" },
|
||||||
{ 0x00C0, 0, 0x6E, 1, 0, 0, "Extended Card Capabilities" },
|
{ 0x00C0, 0, 0x6E, 1, 1, 0, "Extended Card Capabilities" },
|
||||||
{ 0x00C1, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Signature" },
|
{ 0x00C1, 0, 0x6E, 1, 1, 0, "Algorithm Attributes Signature" },
|
||||||
{ 0x00C2, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Decryption" },
|
{ 0x00C2, 0, 0x6E, 1, 1, 0, "Algorithm Attributes Decryption" },
|
||||||
{ 0x00C3, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Authentication" },
|
{ 0x00C3, 0, 0x6E, 1, 1, 0, "Algorithm Attributes Authentication" },
|
||||||
{ 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" },
|
{ 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" },
|
||||||
{ 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" },
|
{ 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" },
|
||||||
{ 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" },
|
{ 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" },
|
||||||
@ -86,6 +86,13 @@ struct cache_s {
|
|||||||
|
|
||||||
struct app_local_s {
|
struct app_local_s {
|
||||||
struct cache_s *cache;
|
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;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*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)
|
||||||
p = xtrymalloc (c->length);
|
return gpg_error (gpg_err_code_from_errno (errno));
|
||||||
if (!p)
|
memcpy (p, c->data, c->length);
|
||||||
return gpg_error (gpg_err_code_from_errno (errno));
|
*result = p;
|
||||||
memcpy (p, c->data, c->length);
|
|
||||||
*result = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
*resultlen = c->length;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
*resultlen = c->length;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
err = iso7816_get_data (app->slot, tag, &p, &len);
|
err = iso7816_get_data (app->slot, tag, &p, &len);
|
||||||
if (err)
|
if (err)
|
||||||
@ -163,24 +168,18 @@ get_cached_data (app_t app, int tag,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* No, cache it. */
|
/* 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. */
|
for (c=app->app_local->cache; c; c = c->next)
|
||||||
if (app->app_local)
|
assert (c->tag != tag);
|
||||||
|
|
||||||
|
c = xtrymalloc (sizeof *c + len);
|
||||||
|
if (c)
|
||||||
{
|
{
|
||||||
for (c=app->app_local->cache; c; c = c->next)
|
memcpy (c->data, p, len);
|
||||||
assert (c->tag != tag);
|
c->length = len;
|
||||||
|
c->tag = tag;
|
||||||
c = xtrymalloc (sizeof *c + len);
|
c->next = app->app_local->cache;
|
||||||
if (c)
|
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;
|
return 0;
|
||||||
@ -505,6 +504,7 @@ do_getattr (APP app, CTRL ctrl, const char *name)
|
|||||||
{ "SIG-COUNTER", 0x0093, 2 },
|
{ "SIG-COUNTER", 0x0093, 2 },
|
||||||
{ "SERIALNO", 0x004F, -1 },
|
{ "SERIALNO", 0x004F, -1 },
|
||||||
{ "AID", 0x004F },
|
{ "AID", 0x004F },
|
||||||
|
{ "EXTCAP", 0x0000, -2 },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
int idx, i;
|
int idx, i;
|
||||||
@ -539,6 +539,18 @@ do_getattr (APP app, CTRL ctrl, const char *name)
|
|||||||
}
|
}
|
||||||
return 0;
|
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);
|
relptr = get_one_do (app, table[idx].tag, &value, &valuelen);
|
||||||
if (relptr)
|
if (relptr)
|
||||||
@ -578,6 +590,7 @@ do_getattr (APP app, CTRL ctrl, const char *name)
|
|||||||
static int
|
static int
|
||||||
do_learn_status (APP app, CTRL ctrl)
|
do_learn_status (APP app, CTRL ctrl)
|
||||||
{
|
{
|
||||||
|
do_getattr (app, ctrl, "EXTCAP");
|
||||||
do_getattr (app, ctrl, "DISP-NAME");
|
do_getattr (app, ctrl, "DISP-NAME");
|
||||||
do_getattr (app, ctrl, "DISP-LANG");
|
do_getattr (app, ctrl, "DISP-LANG");
|
||||||
do_getattr (app, ctrl, "DISP-SEX");
|
do_getattr (app, ctrl, "DISP-SEX");
|
||||||
@ -1378,11 +1391,14 @@ app_select_openpgp (APP app)
|
|||||||
rc = iso7816_select_application (slot, aid, sizeof aid);
|
rc = iso7816_select_application (slot, aid, sizeof aid);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
|
unsigned int manufacturer;
|
||||||
|
|
||||||
app->apptype = "OPENPGP";
|
app->apptype = "OPENPGP";
|
||||||
|
|
||||||
app->did_chv1 = 0;
|
app->did_chv1 = 0;
|
||||||
app->did_chv2 = 0;
|
app->did_chv2 = 0;
|
||||||
app->did_chv3 = 0;
|
app->did_chv3 = 0;
|
||||||
|
app->app_local = NULL;
|
||||||
|
|
||||||
/* The OpenPGP card returns the serial number as part of the
|
/* The OpenPGP card returns the serial number as part of the
|
||||||
AID; because we prefer to use OpenPGP serial numbers, we
|
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[6] << 8;
|
||||||
app->card_version |= buffer[7];
|
app->card_version |= buffer[7];
|
||||||
|
manufacturer = (buffer[8]<<8 | buffer[9]);
|
||||||
|
|
||||||
xfree (app->serialno);
|
xfree (app->serialno);
|
||||||
app->serialno = buffer;
|
app->serialno = buffer;
|
||||||
app->serialnolen = buflen;
|
app->serialnolen = buflen;
|
||||||
buffer = NULL;
|
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);
|
relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
|
||||||
if (!relptr)
|
if (!relptr)
|
||||||
@ -1413,7 +1437,29 @@ app_select_openpgp (APP app)
|
|||||||
}
|
}
|
||||||
app->force_chv1 = (buflen && *buffer == 0);
|
app->force_chv1 = (buflen && *buffer == 0);
|
||||||
xfree (relptr);
|
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)
|
if (opt.verbose > 1)
|
||||||
dump_all_do (slot);
|
dump_all_do (slot);
|
||||||
|
|
||||||
@ -1431,6 +1477,8 @@ app_select_openpgp (APP app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
if (rc)
|
||||||
|
do_deinit (app);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
135
g10/card-util.c
135
g10/card-util.c
@ -43,39 +43,6 @@
|
|||||||
|
|
||||||
#define CONTROL_D ('D' - 'A' + 1)
|
#define CONTROL_D ('D' - 'A' + 1)
|
||||||
|
|
||||||
#if GNUPG_MAJOR_VERSION == 1
|
|
||||||
#define GET_NBITS(a) mpi_get_nbits (a)
|
|
||||||
#else
|
|
||||||
#define GET_NBITS(a) gcry_mpi_get_nbits (a)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
copy_mpi (MPI a, unsigned char *buffer, size_t len, size_t *ncopied)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
#if GNUPG_MAJOR_VERSION == 1
|
|
||||||
unsigned char *tmp;
|
|
||||||
unsigned int n;
|
|
||||||
|
|
||||||
tmp = mpi_get_secure_buffer (a, &n, NULL);
|
|
||||||
if (n > len)
|
|
||||||
rc = G10ERR_GENERAL;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = 0;
|
|
||||||
memcpy (buffer, tmp, n);
|
|
||||||
*ncopied = n;
|
|
||||||
}
|
|
||||||
xfree (tmp);
|
|
||||||
#else /* GNUPG_MAJOR_VERSION != 1 */
|
|
||||||
rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, len, ncopied, a);
|
|
||||||
#endif /* GNUPG_MAJOR_VERSION != 1 */
|
|
||||||
if (rc)
|
|
||||||
log_error ("mpi_copy failed: %s\n", gpg_strerror (rc));
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Change the PIN of a an OpenPGP card. This is an interactive
|
/* Change the PIN of a an OpenPGP card. This is an interactive
|
||||||
function. */
|
function. */
|
||||||
@ -897,10 +864,15 @@ generate_card_keys (const char *serialno)
|
|||||||
{
|
{
|
||||||
struct agent_card_info_s info;
|
struct agent_card_info_s info;
|
||||||
int forced_chv1;
|
int forced_chv1;
|
||||||
|
int want_backup;
|
||||||
|
|
||||||
if (get_info_for_key_operation (&info))
|
if (get_info_for_key_operation (&info))
|
||||||
return;
|
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))
|
if ( (info.fpr1valid && !fpr_is_zero (info.fpr1))
|
||||||
|| (info.fpr2valid && !fpr_is_zero (info.fpr2))
|
|| (info.fpr2valid && !fpr_is_zero (info.fpr2))
|
||||||
|| (info.fpr3valid && !fpr_is_zero (info.fpr3)))
|
|| (info.fpr3valid && !fpr_is_zero (info.fpr3)))
|
||||||
@ -928,7 +900,8 @@ generate_card_keys (const char *serialno)
|
|||||||
if (check_pin_for_key_operation (&info, &forced_chv1))
|
if (check_pin_for_key_operation (&info, &forced_chv1))
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
generate_keypair (NULL, info.serialno);
|
generate_keypair (NULL, info.serialno,
|
||||||
|
want_backup? opt.homedir:NULL);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
agent_release_card_info (&info);
|
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 *copied_sk = NULL;
|
||||||
PKT_secret_key *sk;
|
PKT_secret_key *sk;
|
||||||
size_t n;
|
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;
|
const char *s;
|
||||||
int allow_keyno[3];
|
int allow_keyno[3];
|
||||||
|
|
||||||
@ -1087,94 +1054,9 @@ card_store_subkey (KBNODE node, int use)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Some basic checks on the key parameters. */
|
rc = save_unprotected_key_to_card (sk, keyno);
|
||||||
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)
|
if (rc)
|
||||||
goto leave;
|
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. */
|
/* Get back to the maybe protected original secret key. */
|
||||||
if (copied_sk)
|
if (copied_sk)
|
||||||
@ -1205,7 +1087,6 @@ card_store_subkey (KBNODE node, int use)
|
|||||||
leave:
|
leave:
|
||||||
if (copied_sk)
|
if (copied_sk)
|
||||||
free_secret_key (copied_sk);
|
free_secret_key (copied_sk);
|
||||||
xfree (template);
|
|
||||||
agent_release_card_info (&info);
|
agent_release_card_info (&info);
|
||||||
return okay;
|
return okay;
|
||||||
}
|
}
|
||||||
|
@ -3181,12 +3181,12 @@ main( int argc, char **argv )
|
|||||||
if( opt.batch ) {
|
if( opt.batch ) {
|
||||||
if( argc > 1 )
|
if( argc > 1 )
|
||||||
wrong_args("--gen-key [parameterfile]");
|
wrong_args("--gen-key [parameterfile]");
|
||||||
generate_keypair( argc? *argv : NULL, NULL );
|
generate_keypair( argc? *argv : NULL, NULL, NULL );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if( argc )
|
if( argc )
|
||||||
wrong_args("--gen-key");
|
wrong_args("--gen-key");
|
||||||
generate_keypair(NULL, NULL);
|
generate_keypair(NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
673
g10/keygen.c
673
g10/keygen.c
@ -63,7 +63,8 @@ enum para_name {
|
|||||||
pPASSPHRASE,
|
pPASSPHRASE,
|
||||||
pPASSPHRASE_DEK,
|
pPASSPHRASE_DEK,
|
||||||
pPASSPHRASE_S2K,
|
pPASSPHRASE_S2K,
|
||||||
pSERIALNO
|
pSERIALNO,
|
||||||
|
pBACKUPENCDIR
|
||||||
};
|
};
|
||||||
|
|
||||||
struct para_data_s {
|
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,
|
static int gen_card_key (int algo, int keyno, int is_primary,
|
||||||
KBNODE pub_root, KBNODE sec_root,
|
KBNODE pub_root, KBNODE sec_root,
|
||||||
u32 expireval, struct para_data_s *para);
|
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
|
static void
|
||||||
write_uid( KBNODE root, const char *s )
|
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 *
|
static DEK *
|
||||||
do_ask_passphrase( STRING2KEY **ret_s2k )
|
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
|
* Generate a keypair (fname is only used in batch mode) If
|
||||||
* CARD_SERIALNO is not NULL the fucntion will create the keys on an
|
* 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
|
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;
|
unsigned int nbits;
|
||||||
char *uid = NULL;
|
char *uid = NULL;
|
||||||
@ -2239,158 +2286,245 @@ generate_keypair( const char *fname, const char *card_serialno )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.batch)
|
if (opt.batch)
|
||||||
{
|
{
|
||||||
read_parameter_file( fname );
|
read_parameter_file( fname );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card_serialno)
|
if (card_serialno)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_CARD_SUPPORT
|
#ifdef ENABLE_CARD_SUPPORT
|
||||||
r = xcalloc (1, sizeof *r + strlen (card_serialno) );
|
r = xcalloc (1, sizeof *r + strlen (card_serialno) );
|
||||||
r->key = pSERIALNO;
|
r->key = pSERIALNO;
|
||||||
strcpy( r->u.value, card_serialno);
|
strcpy( r->u.value, card_serialno);
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
|
|
||||||
algo = PUBKEY_ALGO_RSA;
|
algo = PUBKEY_ALGO_RSA;
|
||||||
|
|
||||||
r = xcalloc (1, sizeof *r + 20 );
|
r = xcalloc (1, sizeof *r + 20 );
|
||||||
r->key = pKEYTYPE;
|
r->key = pKEYTYPE;
|
||||||
sprintf( r->u.value, "%d", algo );
|
sprintf( r->u.value, "%d", algo );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
r = xcalloc (1, sizeof *r + 20 );
|
r = xcalloc (1, sizeof *r + 20 );
|
||||||
r->key = pKEYUSAGE;
|
r->key = pKEYUSAGE;
|
||||||
strcpy (r->u.value, "sign");
|
strcpy (r->u.value, "sign");
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
|
|
||||||
r = xcalloc (1, sizeof *r + 20 );
|
r = xcalloc (1, sizeof *r + 20 );
|
||||||
r->key = pSUBKEYTYPE;
|
r->key = pSUBKEYTYPE;
|
||||||
sprintf( r->u.value, "%d", algo );
|
sprintf( r->u.value, "%d", algo );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
r = xcalloc (1, sizeof *r + 20 );
|
r = xcalloc (1, sizeof *r + 20 );
|
||||||
r->key = pSUBKEYUSAGE;
|
r->key = pSUBKEYUSAGE;
|
||||||
strcpy (r->u.value, "encrypt");
|
strcpy (r->u.value, "encrypt");
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
|
|
||||||
r = xcalloc (1, sizeof *r + 20 );
|
r = xcalloc (1, sizeof *r + 20 );
|
||||||
r->key = pAUTHKEYTYPE;
|
r->key = pAUTHKEYTYPE;
|
||||||
sprintf( r->u.value, "%d", algo );
|
sprintf( r->u.value, "%d", algo );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
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*/
|
#endif /*ENABLE_CARD_SUPPORT*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
algo = ask_algo( 0, &use );
|
algo = ask_algo( 0, &use );
|
||||||
if( !algo )
|
if( !algo )
|
||||||
{ /* default: DSA with ElG subkey of the specified size */
|
{ /* default: DSA with ElG subkey of the specified size */
|
||||||
both = 1;
|
both = 1;
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pKEYTYPE;
|
r->key = pKEYTYPE;
|
||||||
sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
|
sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
tty_printf(_("DSA keypair will have 1024 bits.\n"));
|
tty_printf(_("DSA keypair will have 1024 bits.\n"));
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pKEYLENGTH;
|
r->key = pKEYLENGTH;
|
||||||
strcpy( r->u.value, "1024" );
|
strcpy( r->u.value, "1024" );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pKEYUSAGE;
|
r->key = pKEYUSAGE;
|
||||||
strcpy( r->u.value, "sign" );
|
strcpy( r->u.value, "sign" );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
|
|
||||||
algo = PUBKEY_ALGO_ELGAMAL_E;
|
algo = PUBKEY_ALGO_ELGAMAL_E;
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pSUBKEYTYPE;
|
r->key = pSUBKEYTYPE;
|
||||||
sprintf( r->u.value, "%d", algo );
|
sprintf( r->u.value, "%d", algo );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pSUBKEYUSAGE;
|
r->key = pSUBKEYUSAGE;
|
||||||
strcpy( r->u.value, "encrypt" );
|
strcpy( r->u.value, "encrypt" );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pKEYTYPE;
|
r->key = pKEYTYPE;
|
||||||
sprintf( r->u.value, "%d", algo );
|
sprintf( r->u.value, "%d", algo );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
|
|
||||||
if (use)
|
if (use)
|
||||||
{
|
{
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = pKEYUSAGE;
|
r->key = pKEYUSAGE;
|
||||||
sprintf( r->u.value, "%s%s",
|
sprintf( r->u.value, "%s%s",
|
||||||
(use & PUBKEY_USAGE_SIG)? "sign ":"",
|
(use & PUBKEY_USAGE_SIG)? "sign ":"",
|
||||||
(use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
|
(use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
para = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nbits = ask_keysize( algo );
|
nbits = ask_keysize( algo );
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
r = m_alloc_clear( sizeof *r + 20 );
|
||||||
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
|
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
|
||||||
sprintf( r->u.value, "%u", nbits);
|
sprintf( r->u.value, "%u", nbits);
|
||||||
r->next = para;
|
r->next = para;
|
||||||
para = r;
|
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);
|
uid = ask_user_id(0);
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
if( !uid )
|
||||||
r->key = pKEYEXPIRE;
|
{
|
||||||
r->u.expire = expire;
|
log_error(_("Key generation canceled.\n"));
|
||||||
r->next = para;
|
release_parameter_list( para );
|
||||||
para = r;
|
return;
|
||||||
r = m_alloc_clear( sizeof *r + 20 );
|
}
|
||||||
r->key = pSUBKEYEXPIRE;
|
r = m_alloc_clear( sizeof *r + strlen(uid) );
|
||||||
r->u.expire = expire;
|
r->key = pUSERID;
|
||||||
r->next = para;
|
strcpy( r->u.value, uid );
|
||||||
para = r;
|
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 )
|
/* 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
|
||||||
log_error(_("Key generation canceled.\n"));
|
as an unprotected copy of a new secret key packet. 0 is returned
|
||||||
release_parameter_list( para );
|
on success and the caller must then free the returned values. */
|
||||||
return;
|
static int
|
||||||
}
|
generate_raw_key (int algo, unsigned int nbits, u32 created_at,
|
||||||
r = m_alloc_clear( sizeof *r + strlen(uid) );
|
PKT_secret_key **r_sk_unprotected,
|
||||||
r->key = pUSERID;
|
PKT_secret_key **r_sk_protected)
|
||||||
strcpy( r->u.value, uid );
|
{
|
||||||
r->next = para;
|
int rc;
|
||||||
para = r;
|
DEK *dek = NULL;
|
||||||
|
STRING2KEY *s2k = NULL;
|
||||||
dek = card_serialno? NULL : do_ask_passphrase( &s2k );
|
PKT_secret_key *sk = NULL;
|
||||||
if( dek )
|
int i;
|
||||||
{
|
size_t nskey, npkey;
|
||||||
r = m_alloc_clear( sizeof *r );
|
|
||||||
r->key = pPASSPHRASE_DEK;
|
npkey = pubkey_get_npkey (algo);
|
||||||
r->u.dek = dek;
|
nskey = pubkey_get_nskey (algo);
|
||||||
r->next = para;
|
assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);
|
||||||
para = r;
|
|
||||||
r = m_alloc_clear( sizeof *r );
|
if (nbits < 512)
|
||||||
r->key = pPASSPHRASE_S2K;
|
{
|
||||||
r->u.s2k = s2k;
|
nbits = 512;
|
||||||
r->next = para;
|
log_info (_("keysize invalid; using %u bits\n"), nbits );
|
||||||
para = r;
|
}
|
||||||
}
|
|
||||||
|
if ((nbits % 32))
|
||||||
proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
|
{
|
||||||
release_parameter_list( para );
|
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
|
else
|
||||||
{
|
{
|
||||||
rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
|
if ((s = get_parameter_value (para, pBACKUPENCDIR)))
|
||||||
get_parameter_u32 (para, pKEYEXPIRE), para);
|
{
|
||||||
|
/* 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 )
|
if( !rc )
|
||||||
@ -2943,6 +3089,7 @@ gen_card_key (int algo, int keyno, int is_primary,
|
|||||||
PKT_public_key *pk;
|
PKT_public_key *pk;
|
||||||
|
|
||||||
assert (algo == PUBKEY_ALGO_RSA);
|
assert (algo == PUBKEY_ALGO_RSA);
|
||||||
|
|
||||||
|
|
||||||
rc = agent_scd_genkey (&info, keyno, 1);
|
rc = agent_scd_genkey (&info, keyno, 1);
|
||||||
/* if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
|
/* if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
|
||||||
@ -3006,3 +3153,241 @@ gen_card_key (int algo, int keyno, int is_primary,
|
|||||||
return -1;
|
return -1;
|
||||||
#endif /*!ENABLE_CARD_SUPPORT*/
|
#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*/
|
||||||
|
@ -153,7 +153,8 @@ void show_basic_key_info (KBNODE keyblock);
|
|||||||
/*-- keygen.c --*/
|
/*-- keygen.c --*/
|
||||||
u32 ask_expire_interval(int object);
|
u32 ask_expire_interval(int object);
|
||||||
u32 ask_expiredate(void);
|
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);
|
int keygen_set_std_prefs (const char *string,int personal);
|
||||||
PKT_user_id *keygen_get_std_prefs (void);
|
PKT_user_id *keygen_get_std_prefs (void);
|
||||||
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
|
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
|
#ifdef ENABLE_CARD_SUPPORT
|
||||||
int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
|
int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
|
||||||
int keyno, const char *serialno);
|
int keyno, const char *serialno);
|
||||||
|
int save_unprotected_key_to_card (PKT_secret_key *sk, int keyno);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-- openfile.c --*/
|
/*-- openfile.c --*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user