Fixed card key generation of gpg2.

Reveal less information about timings while generating a key.
This commit is contained in:
Werner Koch 2007-07-05 16:58:19 +00:00
parent fa84b8cd82
commit 4631bc8ddf
51 changed files with 6316 additions and 5852 deletions

View File

@ -1,3 +1,7 @@
2007-07-05 Werner Koch <wk@g10code.com>
* configure.ac: Require libassuan 1.0.2.
2007-07-05 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Invoke AM_LANGINFO_CODESET.

3
NEWS
View File

@ -11,6 +11,9 @@ Noteworthy changes in version 2.0.5
* The command --gen-key may now be used instead of the
gpgsm-gencert.sh script.
* Changed key generation to reveal less information about the
machine. Bug fixes for gpg2's card key generation.
Noteworthy changes in version 2.0.4 (2007-05-09)
------------------------------------------------

View File

@ -1,3 +1,8 @@
2007-07-05 Werner Koch <wk@g10code.com>
* call-scd.c (struct inq_needpin_s): New.
(inq_needpin): Pass unknown inquiries up.
2007-07-04 Werner Koch <wk@g10code.com>
* gpg-agent.c (TIMERTICK_INTERVAL): New.

View File

@ -1,5 +1,5 @@
/* call-scd.c - fork of the scdaemon to do SC operations
* Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -79,6 +79,8 @@ struct inq_needpin_s
assuan_context_t ctx;
int (*getpin_cb)(void *, const char *, char*, size_t);
void *getpin_cb_arg;
assuan_context_t passthru; /* If not NULL, pass unknown inquiries
up to the caller. */
};
@ -731,6 +733,36 @@ inq_needpin (void *opaque, const char *line)
{
rc = parm->getpin_cb (parm->getpin_cb_arg, "", NULL, 0);
}
else if (parm->passthru)
{
unsigned char *value;
size_t valuelen;
int rest;
int needrest = !strncmp (line, "KEYDATA", 8);
/* Pass the inquiry up to our caller. We limit the maximum
amount to an arbitrary value. As we know that the KEYDATA
enquiry is pretty sensitive we disable logging then */
if ((rest = (needrest
&& !assuan_get_flag (parm->passthru, ASSUAN_CONFIDENTIAL))))
assuan_begin_confidential (parm->passthru);
rc = assuan_inquire (parm->passthru, line, &value, &valuelen, 8096);
if (rest)
assuan_end_confidential (parm->passthru);
if (!rc)
{
if ((rest = (needrest
&& !assuan_get_flag (parm->ctx, ASSUAN_CONFIDENTIAL))))
assuan_begin_confidential (parm->ctx);
rc = assuan_send_data (parm->ctx, value, valuelen);
if (rest)
assuan_end_confidential (parm->ctx);
xfree (value);
}
else
log_error ("error forwarding inquiry `%s': %s\n",
line, gpg_strerror (rc));
}
else
{
log_error ("unsupported inquiry `%s'\n", line);
@ -780,6 +812,7 @@ agent_card_pksign (ctrl_t ctrl,
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.passthru = 0;
snprintf (line, DIM(line)-1,
ctrl->use_auth_call? "PKAUTH %s":"PKSIGN %s", keyid);
line[DIM(line)-1] = 0;
@ -850,6 +883,7 @@ agent_card_pkdecrypt (ctrl_t ctrl,
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.passthru = 0;
snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
line[DIM(line)-1] = 0;
rc = assuan_transact (ctrl->scd_local->ctx, line,
@ -1065,8 +1099,8 @@ pass_data_thru (void *opaque, const void *buffer, size_t length)
/* Send the line CMDLINE with command for the SCDdaemon to it and send
all status messages back. This command is used as a general quoting
mechanism to pass everything verbatim to SCDAEMOPN. The PIN
inquirey is handled inside gpg-agent. */
mechanism to pass everything verbatim to SCDAEMON. The PIN
inquiry is handled inside gpg-agent. */
int
agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *, char*, size_t),
@ -1082,6 +1116,7 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.passthru = assuan_context;
rc = assuan_transact (ctrl->scd_local->ctx, cmdline,
pass_data_thru, assuan_context,
inq_needpin, &inqparm,

View File

@ -1,3 +1,8 @@
2007-07-05 Werner Koch <wk@g10code.com>
* t-gettime.c: New.
* gettime.c (isotime2epoch, epoch2isotime): New.
2007-07-04 Werner Koch <wk@g10code.com>
* estream.c (es_init_do): Do not throw an error if pth as already

View File

@ -81,13 +81,15 @@ libgpgrl_a_SOURCES = \
#
# Module tests
#
module_tests = t-convert
module_tests = t-convert t-gettime
t_common_ldadd = ../jnlib/libjnlib.a $(libcommon) ../gl/libgnu.a \
t_common_ldadd = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
t_convert_DEPENDENCIES = convert.c libcommon.a
t_convert_LDADD = $(t_common_ldadd)
t_gettime_DEPENDENCIES = gettime.c libcommon.a
t_gettime_LDADD = $(t_common_ldadd)
$(PROGRAMS): ../jnlib/libjnlib.a $(libcommon) ../gl/libgnu.a

View File

@ -1,5 +1,5 @@
/* gettime.c - Wrapper for time functions
* Copyright (C) 1998, 2002 Free Software Foundation, Inc.
* Copyright (C) 1998, 2002, 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -20,6 +20,7 @@
#include <config.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif
@ -64,7 +65,7 @@ gnupg_get_isotime (gnupg_isotime_t timebuf)
#else
tp = gmtime (&atime);
#endif
sprintf (timebuf,"%04d%02d%02dT%02d%02d%02d",
snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec);
}
@ -164,6 +165,78 @@ scan_isodatestr( const char *string )
return stamp;
}
/* Scan am ISO timestamp and return a epoch based timestamp. The only
supported format is "yyyymmddThhmmss" delimited by white space, nul, a
colon or a comma. Returns (time_t)(-1) for an invalid string. */
time_t
isotime2epoch (const char *string)
{
const char *s;
int year, month, day, hour, minu, sec;
struct tm tmbuf;
int i;
if (!*string)
return (time_t)(-1);
for (s=string, i=0; i < 8; i++, s++)
if (!digitp (s))
return (time_t)(-1);
if (*s != 'T')
return (time_t)(-1);
for (s++, i=9; i < 15; i++, s++)
if (!digitp (s))
return (time_t)(-1);
if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
return (time_t)(-1); /* Wrong delimiter. */
year = atoi_4 (string);
month = atoi_2 (string + 4);
day = atoi_2 (string + 6);
hour = atoi_2 (string + 9);
minu = atoi_2 (string + 11);
sec = atoi_2 (string + 13);
/* Basic checks. */
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|| hour > 23 || minu > 59 || sec > 61 )
return (time_t)(-1);
memset (&tmbuf, 0, sizeof tmbuf);
tmbuf.tm_sec = sec;
tmbuf.tm_min = minu;
tmbuf.tm_hour = hour;
tmbuf.tm_mday = day;
tmbuf.tm_mon = month-1;
tmbuf.tm_year = year - 1900;
tmbuf.tm_isdst = -1;
return timegm (&tmbuf);
}
/* Convert an Epoch time to an iso time stamp. */
void
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
{
if (atime < 0)
*timebuf = 0;
else
{
struct tm *tp;
#ifdef HAVE_GMTIME_R
struct tm tmbuf;
tp = gmtime_r (&atime, &tmbuf);
#else
tp = gmtime (&atime);
#endif
snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec);
}
}
u32
add_days_to_timestamp( u32 stamp, u16 days )

98
common/t-gettime.c Normal file
View File

@ -0,0 +1,98 @@
/* t-gettime.c - Module test for gettime.c
* Copyright (C) 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "util.h"
#define pass() do { ; } while(0)
#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
__FILE__,__LINE__, (a)); \
errcount++; \
} while(0)
static int verbose;
static int errcount;
#define INVALID ((time_t)(-1))
static void
test_isotime2epoch (void)
{
struct { const char *string; time_t expected; } array [] = {
{ "19700101T000001", 1 },
{ "19700101T235959", 86399 },
{ "19980815T143712", 903191832 },
{ "19700101T000000", 0 },
{ "19691231T235959", INVALID },
{ "19000101T000000", INVALID },
{ "", INVALID },
{ "19000101T00000", INVALID },
{ "20010101t123456", INVALID },
{ "20010101T123456", 978352496 },
{ "20070629T160000", 1183132800 },
{ "20070629T160000:", 1183132800 },
{ "20070629T160000,", 1183132800 },
{ "20070629T160000 ", 1183132800 },
{ "20070629T160000\n", 1183132800 },
{ "20070629T160000.", INVALID },
{ NULL, 0 }
};
int idx;
u32 val;
gnupg_isotime_t tbuf;
for (idx=0; array[idx].string; idx++)
{
val = isotime2epoch (array[idx].string);
if (val != array[idx].expected )
{
fail (idx);
if (verbose)
fprintf (stderr, "string `%s' exp: %ld got: %ld\n",
array[idx].string, (long)array[idx].expected,
(long)val);
}
if (array[idx].expected != INVALID)
{
epoch2isotime (tbuf, val);
if (strlen (tbuf) != 15)
fail (idx);
if (strncmp (array[idx].string, tbuf, 15))
fail (idx);
}
}
}
int
main (int argc, char **argv)
{
if (argc > 1 && !strcmp (argv[1], "--verbose"))
verbose = 1;
test_isotime2epoch ();
return !!errcount;
}

View File

@ -103,6 +103,8 @@ void gnupg_set_time (time_t newtime, int freeze);
int gnupg_faked_time_p (void);
u32 make_timestamp (void);
u32 scan_isodatestr (const char *string);
time_t isotime2epoch (const char *string);
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
u32 add_days_to_timestamp (u32 stamp, u16 days);
const char *strtimevalue (u32 stamp);
const char *strtimestamp (u32 stamp); /* GMT */

View File

@ -43,7 +43,7 @@ NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.2.2
NEED_LIBASSUAN_API=1
NEED_LIBASSUAN_VERSION=0.9.3
NEED_LIBASSUAN_VERSION=1.0.2
NEED_KSBA_API=1
NEED_KSBA_VERSION=1.0.2

View File

@ -819,6 +819,13 @@ The format of this file is as follows:
may either be entered in ISO date format (2000-08-15) or as
number of days, weeks, month or years. Without a letter days
are assumed.
Creation-Date: <iso-date>
Set the creation date of the key as stored in the key
information and which is also part of the fingerprint
calculation. Either a date like "1986-04-26" or a full
timestamp like "19860426T042640" may be used. The time is
considered to be UTC. If it is not given the current time
is used.
Preferences: <string>
Set the cipher, hash, and compression preference values for
this key. This expects the same type of string as "setpref"

View File

@ -176,10 +176,10 @@ or other purposes and don't have a corresponding certificate.
@menu
* gpg 1.4 vs. 1.9:: Relationship between the two branches.
* GnuPG-1 and GnuPG-2:: Relationship between the two branches.
@end menu
@node gpg 1.4 vs. 1.9
@node GnuPG-1 and GnuPG-2
@subsection Relationship between the two branches.
Here is a little picture showing how the components work together:

View File

@ -1,3 +1,27 @@
2007-07-05 Werner Koch <wk@g10code.com>
* card-util.c (card_generate_subkey, card_store_subkey): Enable
the code also for GnuPG-2.
* keygen.c (make_backsig): Add arg TIMESTAMP.
(write_keybinding): Add arg TIMESTAMP, pass it to make_backsig.
(write_direct_sig, write_selfsigs): Add arg TIMESTAMP.
(gen_elg, gen_dsa, gen_rsa): Add arg TIMESTAMP.
(do_create): Ditto.
(do_generate_keypair): Use the same timestamp for key creation
time and all key signatures. Return an error if write_direct_sig
for the secret key fails.
(generate_subkeypair): Ditto.
(gen_card_key): New arg TIMESTAMP.
(generate_card_subkeypair): Pass current time to gen_card_key.
(gen_card_key_with_backup): New arg TIMESTAMP.
(read_parameter_file): Add option Creation-Date.
(parse_creation_string): New.
(do_generate_keypair): Use the Creation-Date if available.
(save_unprotected_key_to_card): Use P for P and not D.
* call-agent.c (agent_scd_genkey): Add arg CREATETIME.
* keyedit.c (menu_backsign): Use the same timestamp for all backsigs.
2007-06-26 Werner Koch <wk@g10code.com>
* openfile.c (try_make_homedir): Support W32; use standard_homedir.

View File

@ -1,5 +1,5 @@
/* call-agent.c - divert operations to the agent
* Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -498,21 +498,32 @@ scd_genkey_cb (void *opaque, const char *line)
}
/* Send a GENKEY command to the SCdaemon. SERIALNO is not used in
this implementation. */
this implementation. If CREATEDATE has been given, it will be
passed to SCDAEMON so that the key can be created with this
timestamp; note the user needs to use the returned timestamp as old
versions of scddaemon don't support this option. */
int
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
const char *serialno)
const char *serialno, u32 createtime)
{
int rc;
char line[ASSUAN_LINELENGTH];
gnupg_isotime_t tbuf;
rc = start_agent ();
if (rc)
return rc;
if (createtime)
epoch2isotime (tbuf, createtime);
else
*tbuf = 0;
memset (info, 0, sizeof *info);
snprintf (line, DIM(line)-1, "SCD GENKEY %s%d",
force? "--force ":"", keyno);
snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
*tbuf? "--timestamp=":"", tbuf,
force? "--force":"",
keyno);
line[DIM(line)-1] = 0;
memset (info, 0, sizeof *info);

View File

@ -82,7 +82,7 @@ int agent_scd_writekey (int keyno, const char *serialno,
/* Send a GENKEY command to the SCdaemon. */
int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
const char *serialno);
const char *serialno, u32 createtime);
/* Send a PKSIGN command to the SCdaemon. */
int agent_scd_pksign (const char *keyid, int hashalgo,

View File

@ -999,7 +999,7 @@ restore_forced_chv1 (int *forced_chv1)
}
}
#if GNUPG_MAJOR_VERSION == 1
/* Helper for the key generation/edit functions. */
static void
show_card_key_info (struct agent_card_info_s *info)
@ -1012,9 +1012,8 @@ show_card_key_info (struct agent_card_info_s *info)
print_sha1_fpr (NULL, info->fpr3valid? info->fpr3:NULL);
tty_printf ("\n");
}
#endif
#if GNUPG_MAJOR_VERSION == 1
/* Helper for the key generation/edit functions. */
static int
replace_existing_key_p (struct agent_card_info_s *info, int keyno)
@ -1034,7 +1033,6 @@ replace_existing_key_p (struct agent_card_info_s *info, int keyno)
}
return 0;
}
#endif
static void
@ -1104,7 +1102,6 @@ generate_card_keys (const char *serialno)
int
card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
{
#if GNUPG_MAJOR_VERSION == 1
struct agent_card_info_s info;
int okay = 0;
int forced_chv1 = 0;
@ -1151,9 +1148,6 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
agent_release_card_info (&info);
restore_forced_chv1 (&forced_chv1);
return okay;
#else
return 0;
#endif
}
@ -1164,7 +1158,6 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
int
card_store_subkey (KBNODE node, int use)
{
#if GNUPG_MAJOR_VERSION == 1
struct agent_card_info_s info;
int okay = 0;
int rc;
@ -1266,7 +1259,7 @@ card_store_subkey (KBNODE node, int use)
n = pubkey_get_nskey (sk->pubkey_algo);
for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
{
mpi_free (sk->skey[i]);
gcry_mpi_release (sk->skey[i]);
sk->skey[i] = NULL;
}
i = pubkey_get_npkey (sk->pubkey_algo);
@ -1285,9 +1278,6 @@ card_store_subkey (KBNODE node, int use)
free_secret_key (copied_sk);
agent_release_card_info (&info);
return okay;
#else
return 0;
#endif
}

View File

@ -3652,6 +3652,7 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
PKT_public_key *main_pk;
PKT_secret_key *main_sk,*sub_sk=NULL;
KBNODE node;
u32 timestamp;
assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
@ -3661,6 +3662,10 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
main_sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
keyid_from_pk(main_pk,NULL);
/* We use the same timestamp for all backsigs so that we don't
reveal information about the used machine. */
timestamp = make_timestamp ();
for(node=pub_keyblock;node;node=node->next)
{
PKT_public_key *sub_pk=NULL;
@ -3748,7 +3753,8 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
set_next_passphrase(passphrase);
xfree(passphrase);
rc=make_backsig(sig_pk->pkt->pkt.signature,main_pk,sub_pk,sub_sk);
rc = make_backsig (sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_sk,
timestamp);
if(rc==0)
{
PKT_signature *newsig;

View File

@ -1,6 +1,6 @@
/* keygen.c - generate a key pair
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006 Free Software Foundation, Inc.
* 2006, 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -60,6 +60,8 @@ enum para_name {
pPREFERENCES,
pREVOKER,
pUSERID,
pCREATIONDATE,
pKEYCREATIONDATE, /* Same in seconds since epoch. */
pEXPIREDATE,
pKEYEXPIRE, /* in n seconds */
pSUBKEYEXPIRE, /* in n seconds */
@ -80,6 +82,7 @@ struct para_data_s {
DEK *dek;
STRING2KEY *s2k;
u32 expire;
u32 creation;
unsigned int usage;
struct revocation_key revkey;
char value[1];
@ -126,9 +129,11 @@ 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,
PKT_secret_key **ret_sk,
u32 *timestamp,
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 timestamp,
u32 expireval, struct para_data_s *para,
const char *backup_dir);
@ -769,21 +774,27 @@ keygen_add_revkey(PKT_signature *sig, void *opaque)
return 0;
}
/* Create a back-signature. If TIMESTAMP is not NULL, use it for the
signature creation time. */
int
make_backsig (PKT_signature *sig,PKT_public_key *pk,
PKT_public_key *sub_pk,PKT_secret_key *sub_sk)
PKT_public_key *sub_pk,PKT_secret_key *sub_sk,
u32 timestamp)
{
PKT_signature *backsig;
int rc;
cache_public_key(sub_pk);
rc=make_keysig_packet(&backsig,pk,NULL,sub_pk,sub_sk,0x19,0,0,0,0,NULL,NULL);
rc = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_sk, 0x19,
0, 0, timestamp, 0, NULL, NULL);
if(rc)
log_error("make_keysig_packet failed for backsig: %s\n",g10_errstr(rc));
else
{
/* get it into a binary packed form. */
/* Get it into a binary packed form. */
IOBUF backsig_out=iobuf_temp();
PACKET backsig_pkt;
@ -848,7 +859,7 @@ make_backsig(PKT_signature *sig,PKT_public_key *pk,
buf+=mark;
}
/* now make the binary blob into a subpacket */
/* Now make the binary blob into a subpacket. */
build_sig_subpkt(sig,SIGSUBPKT_SIGNATURE,buf,pktlen);
iobuf_close(backsig_out);
@ -861,7 +872,7 @@ make_backsig(PKT_signature *sig,PKT_public_key *pk,
static int
write_direct_sig (KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
struct revocation_key *revkey )
struct revocation_key *revkey, u32 timestamp)
{
PACKET *pkt;
PKT_signature *sig;
@ -872,20 +883,22 @@ write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
if( opt.verbose )
log_info(_("writing direct signature\n"));
/* get the pk packet from the pub_tree */
/* Get the pk packet from the pub_tree. */
node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
if( !node )
BUG();
pk = node->pkt->pkt.public_key;
/* we have to cache the key, so that the verification of the signature
* creation is able to retrieve the public key */
/* We have to cache the key, so that the verification of the
signature creation is able to retrieve the public key. */
cache_public_key (pk);
/* and make the signature */
rc = make_keysig_packet(&sig,pk,NULL,NULL,sk,0x1F,0,0,0,0,
/* Make the signature. */
rc = make_keysig_packet (&sig,pk,NULL,NULL,sk,0x1F,
0, 0, timestamp, 0,
keygen_add_revkey, revkey);
if( rc ) {
if( rc )
{
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
@ -897,9 +910,10 @@ write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
return rc;
}
static int
write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
unsigned int use )
unsigned int use, u32 timestamp )
{
PACKET *pkt;
PKT_signature *sig;
@ -911,25 +925,29 @@ write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
if( opt.verbose )
log_info(_("writing self signature\n"));
/* get the uid packet from the list */
/* Get the uid packet from the list. */
node = find_kbnode( pub_root, PKT_USER_ID );
if( !node )
BUG(); /* no user id packet in tree */
BUG(); /* No user id packet in tree. */
uid = node->pkt->pkt.user_id;
/* get the pk packet from the pub_tree */
/* Get the pk packet from the pub_tree. */
node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
if( !node )
BUG();
pk = node->pkt->pkt.public_key;
pk->pubkey_usage = use;
/* we have to cache the key, so that the verification of the signature
* creation is able to retrieve the public key */
/* We have to cache the key, so that the verification of the
signature creation is able to retrieve the public key. */
cache_public_key (pk);
/* and make the signature */
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
/* Make the signature. */
rc = make_keysig_packet (&sig, pk, uid, NULL, sk, 0x13,
0, 0, timestamp, 0,
keygen_add_std_prefs, pk);
if( rc ) {
if( rc )
{
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
@ -946,10 +964,13 @@ write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
return rc;
}
/* Write the key binding signature. If TIMESTAMP is not NULL use the
signature creation times. */
static int
write_keybinding (KBNODE root, KBNODE pub_root,
PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
unsigned int use )
unsigned int use, u32 timestamp)
{
PACKET *pkt;
PKT_signature *sig;
@ -961,38 +982,42 @@ write_keybinding( KBNODE root, KBNODE pub_root,
if ( opt.verbose )
log_info(_("writing key binding signature\n"));
/* get the pk packet from the pub_tree */
/* Get the pk packet from the pub_tree. */
node = find_kbnode ( pub_root, PKT_PUBLIC_KEY );
if ( !node )
BUG();
pri_pk = node->pkt->pkt.public_key;
/* we have to cache the key, so that the verification of the signature
* creation is able to retrieve the public key */
/* We have to cache the key, so that the verification of the
* signature creation is able to retrieve the public key. */
cache_public_key (pri_pk);
/* find the last subkey */
/* Find the last subkey. */
sub_pk = NULL;
for(node=pub_root; node; node = node->next ) {
for (node=pub_root; node; node = node->next )
{
if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
sub_pk = node->pkt->pkt.public_key;
}
if (!sub_pk)
BUG();
/* and make the signature */
/* Make the signature. */
oduap.usage = use;
oduap.pk = sub_pk;
rc=make_keysig_packet(&sig, pri_pk, NULL, sub_pk, pri_sk, 0x18, 0, 0, 0, 0,
rc = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_sk, 0x18,
0, 0, timestamp, 0,
keygen_add_key_flags_and_expire, &oduap );
if( rc ) {
if (rc)
{
log_error ("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
/* make a backsig */
/* Make a backsig. */
if (use&PUBKEY_USAGE_SIG)
{
rc=make_backsig(sig,pri_pk,sub_pk,sub_sk);
rc = make_backsig (sig, pri_pk, sub_pk, sub_sk, timestamp);
if (rc)
return rc;
}
@ -1103,11 +1128,13 @@ genhelp_factors (gcry_sexp_t misc_key_info, KBNODE sec_root)
}
/* Generate an Elgamal encryption key pair. TIMESTAMP is the creatuion
time to be put into the key structure. */
static int
gen_elg (int algo, unsigned int nbits,
KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval,
int is_subkey)
STRING2KEY *s2k, PKT_secret_key **ret_sk,
u32 timestamp, u32 expireval, int is_subkey)
{
int rc;
PACKET *pkt;
@ -1118,12 +1145,14 @@ gen_elg(int algo, unsigned int nbits,
assert( is_ELGAMAL(algo) );
if( nbits < 512 ) {
if (nbits < 512)
{
nbits = 1024;
log_info (_("keysize invalid; using %u bits\n"), nbits );
}
if( (nbits % 32) ) {
if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
log_info (_("keysize rounded up to %u bits\n"), nbits );
}
@ -1147,19 +1176,13 @@ gen_elg(int algo, unsigned int nbits,
sk = xmalloc_clear( sizeof *sk );
pk = xmalloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->timestamp = pk->timestamp = timestamp;
sk->version = pk->version = 4;
if( expireval ) {
if (expireval)
{
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
}
sk->pubkey_algo = pk->pubkey_algo = algo;
/* pk->pkey[0] = mpi_copy( skey[0] ); */
/* pk->pkey[1] = mpi_copy( skey[1] ); */
/* pk->pkey[2] = mpi_copy( skey[2] ); */
/* sk->skey[0] = skey[0]; */
/* sk->skey[1] = skey[1]; */
/* sk->skey[2] = skey[2]; */
/* sk->skey[3] = skey[3]; */
rc = key_from_sexp (pk->pkey, s_key, "public-key", "pgy");
if (rc)
@ -1186,7 +1209,7 @@ gen_elg(int algo, unsigned int nbits,
sk->protect.algo = 0;
sk->csum = checksum_mpi (sk->skey[3]);
if( ret_sk ) /* return an unprotected version of the sk */
if (ret_sk) /* Return an unprotected version of the sk. */
*ret_sk = copy_secret_key ( NULL, sk );
rc = genhelp_protect (dek, s2k, sk);
@ -1203,8 +1226,9 @@ gen_elg(int algo, unsigned int nbits,
pkt->pkt.public_key = pk;
add_kbnode (pub_root, new_kbnode( pkt ));
/* Don't know whether it makes sense to have the factors, so for now
* we store them in the secret keyring (but they are not secret). */
/* Don't know whether it makes sense to have access to the factors,
so for now we store them in the secret keyring (but they are not
secret). */
pkt = xmalloc_clear (sizeof *pkt);
pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
pkt->pkt.secret_key = sk;
@ -1221,7 +1245,8 @@ gen_elg(int algo, unsigned int nbits,
*/
static int
gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
STRING2KEY *s2k, PKT_secret_key **ret_sk,
u32 timestamp, u32 expireval, int is_subkey)
{
int rc;
PACKET *pkt;
@ -1290,7 +1315,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk = xmalloc_clear( sizeof *sk );
pk = xmalloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->timestamp = pk->timestamp = timestamp;
sk->version = pk->version = 4;
if (expireval)
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
@ -1360,7 +1385,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
*/
static int
gen_rsa (int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
STRING2KEY *s2k, PKT_secret_key **ret_sk,
u32 timestamp, u32 expireval, int is_subkey)
{
int rc;
PACKET *pkt;
@ -1370,12 +1396,14 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
assert (is_RSA(algo));
if( nbits < 1024 ) {
if (nbits < 1024)
{
nbits = 1024;
log_info (_("keysize invalid; using %u bits\n"), nbits );
}
if( (nbits % 32) ) {
if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
log_info (_("keysize rounded up to %u bits\n"), nbits );
}
@ -1396,9 +1424,10 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk = xmalloc_clear( sizeof *sk );
pk = xmalloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->timestamp = pk->timestamp = timestamp;
sk->version = pk->version = 4;
if( expireval ) {
if (expireval)
{
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
}
sk->pubkey_algo = pk->pubkey_algo = algo;
@ -1762,6 +1791,26 @@ parse_expire_string( const char *string )
return seconds;
}
/* Parsean Creation-Date string which is either "1986-04-26" or
"19860426T042640". Returns 0 on error. */
static u32
parse_creation_string (const char *string)
{
u32 seconds;
if (!*string)
seconds = 0;
else if ( !strncmp (string, "seconds=", 8) )
seconds = atoi (string+8);
else if ( !(seconds = scan_isodatestr (string)))
{
time_t tmp = isotime2epoch (string);
seconds = (tmp == (time_t)(-1))? 0 : tmp;
}
return seconds;
}
/* object == 0 for a key, and 1 for a sig */
u32
ask_expire_interval(int object,const char *def_expire)
@ -2084,10 +2133,12 @@ do_ask_passphrase ( STRING2KEY **ret_s2k, int *r_canceled )
}
/* Basic key generation. Here we divert to the actual generation
routines based on the requested algorithm. */
static int
do_create (int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate,
int is_subkey )
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk,
u32 timestamp, u32 expiredate, int is_subkey )
{
int rc=0;
@ -2099,14 +2150,14 @@ do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
"generator a better chance to gain enough entropy.\n") );
if( algo == PUBKEY_ALGO_ELGAMAL_E )
rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
is_subkey);
rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk,
timestamp, expiredate, is_subkey);
else if( algo == PUBKEY_ALGO_DSA )
rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
is_subkey);
rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk,
timestamp, expiredate, is_subkey);
else if( algo == PUBKEY_ALGO_RSA )
rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
is_subkey);
rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk,
timestamp, expiredate, is_subkey);
else
BUG();
@ -2283,6 +2334,8 @@ get_parameter_u32( struct para_data_s *para, enum para_name key )
if( !r )
return 0;
if( r->key == pKEYCREATIONDATE )
return r->u.creation;
if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
return r->u.expire;
if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
@ -2472,7 +2525,23 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
para = r;
}
/* make KEYEXPIRE from Expire-Date */
/* Make KEYCREATIONDATE from Creation-Date. */
r = get_parameter (para, pCREATIONDATE);
if (r && *r->u.value)
{
u32 seconds;
seconds = parse_creation_string (r->u.value);
if (!seconds)
{
log_error ("%s:%d: invalid creation date\n", fname, r->lnr );
return -1;
}
r->u.creation = seconds;
r->key = pKEYCREATIONDATE; /* Change that entry. */
}
/* Make KEYEXPIRE from Expire-Date. */
r = get_parameter( para, pEXPIREDATE );
if( r && *r->u.value )
{
@ -2525,6 +2594,7 @@ read_parameter_file( const char *fname )
{ "Name-Email", pNAMEEMAIL },
{ "Name-Comment", pNAMECOMMENT },
{ "Expire-Date", pEXPIREDATE },
{ "Creation-Date", pCREATIONDATE },
{ "Passphrase", pPASSPHRASE },
{ "Preferences", pPREFERENCES },
{ "Revoker", pREVOKER },
@ -3027,6 +3097,7 @@ start_tree(KBNODE *tree)
delete_kbnode(*tree);
}
static void
do_generate_keypair (struct para_data_s *para,
struct output_control_s *outctrl, int card)
@ -3038,6 +3109,7 @@ do_generate_keypair( struct para_data_s *para,
struct revocation_key *revkey;
int rc;
int did_sub = 0;
u32 timestamp;
if( outctrl->dryrun )
{
@ -3045,8 +3117,10 @@ do_generate_keypair( struct para_data_s *para,
return;
}
if( outctrl->use_files ) {
if( outctrl->pub.newfname ) {
if ( outctrl->use_files )
{
if ( outctrl->pub.newfname )
{
iobuf_close(outctrl->pub.stream);
outctrl->pub.stream = NULL;
if (outctrl->pub.fname)
@ -3055,23 +3129,27 @@ do_generate_keypair( struct para_data_s *para,
outctrl->pub.fname = outctrl->pub.newfname;
outctrl->pub.newfname = NULL;
if (is_secured_filename (outctrl->pub.fname) ) {
if (is_secured_filename (outctrl->pub.fname) )
{
outctrl->pub.stream = NULL;
errno = EPERM;
}
else
outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
if( !outctrl->pub.stream ) {
if (!outctrl->pub.stream)
{
log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
strerror(errno) );
return;
}
if( opt.armor ) {
if (opt.armor)
{
outctrl->pub.afx->what = 1;
push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
}
}
if( outctrl->sec.newfname ) {
if (outctrl->sec.newfname)
{
mode_t oldmask;
iobuf_close(outctrl->sec.stream);
@ -3083,26 +3161,30 @@ do_generate_keypair( struct para_data_s *para,
outctrl->sec.newfname = NULL;
oldmask = umask (077);
if (is_secured_filename (outctrl->sec.fname) ) {
if (is_secured_filename (outctrl->sec.fname) )
{
outctrl->sec.stream = NULL;
errno = EPERM;
}
else
outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
umask (oldmask);
if( !outctrl->sec.stream ) {
if (!outctrl->sec.stream)
{
log_error(_("can't create `%s': %s\n"), outctrl->sec.newfname,
strerror(errno) );
return;
}
if( opt.armor ) {
if (opt.armor)
{
outctrl->sec.afx->what = 5;
push_armor_filter (outctrl->sec.afx, outctrl->sec.stream);
}
}
assert( outctrl->pub.stream );
assert( outctrl->sec.stream );
if( opt.verbose ) {
if (opt.verbose)
{
log_info (_("writing public key to `%s'\n"), outctrl->pub.fname );
if (card)
log_info (_("writing secret key stub to `%s'\n"),
@ -3113,15 +3195,18 @@ do_generate_keypair( struct para_data_s *para,
}
/* we create the packets as a tree of kbnodes. Because the
* structure we create is known in advance we simply generate a
* linked list. The first packet is a dummy packet which we flag
* as deleted. The very first packet must always be a KEY packet.
*/
/* We create the packets as a tree of kbnodes. Because the
structure we create is known in advance we simply generate a
linked list. The first packet is a dummy packet which we flag as
deleted. The very first packet must always be a KEY packet. */
start_tree (&pub_root);
start_tree (&sec_root);
timestamp = get_parameter_u32 (para, pKEYCREATIONDATE);
if (!timestamp)
timestamp = make_timestamp ();
if (!card)
{
rc = do_create (get_parameter_algo( para, pKEYTYPE ),
@ -3130,11 +3215,15 @@ do_generate_keypair( struct para_data_s *para,
get_parameter_dek( para, pPASSPHRASE_DEK ),
get_parameter_s2k( para, pPASSPHRASE_S2K ),
&pri_sk,
timestamp,
get_parameter_u32( para, pKEYEXPIRE ), 0 );
}
else
{
/* Note, that depending on the backend, the card key generation
may update TIMESTAMP. */
rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL,
&timestamp,
get_parameter_u32 (para, pKEYEXPIRE), para);
if (!rc)
{
@ -3145,20 +3234,18 @@ do_generate_keypair( struct para_data_s *para,
if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
{
rc=write_direct_sig(pub_root,pub_root,pri_sk,revkey);
rc = write_direct_sig (pub_root, pub_root, pri_sk, revkey, timestamp);
if (!rc)
write_direct_sig(sec_root,pub_root,pri_sk,revkey);
rc = write_direct_sig (sec_root, pub_root, pri_sk, revkey, timestamp);
}
if( !rc && (s=get_parameter_value(para, pUSERID)) )
{
write_uid (pub_root, s );
if( !rc )
write_uid (sec_root, s );
if( !rc )
rc = write_selfsigs (sec_root, pub_root, pri_sk,
get_parameter_uint (para, pKEYUSAGE));
get_parameter_uint (para, pKEYUSAGE), timestamp);
}
/* Write the auth key to the card before the encryption key. This
@ -3170,13 +3257,18 @@ do_generate_keypair( struct para_data_s *para,
if (!rc && card && get_parameter (para, pAUTHKEYTYPE))
{
/* Note, that depending on the backend, the card key generation
may update TIMESTAMP. */
rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root, NULL,
&timestamp,
get_parameter_u32 (para, pKEYEXPIRE), para);
if (!rc)
rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk,
PUBKEY_USAGE_AUTH, timestamp);
if (!rc)
rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk,
PUBKEY_USAGE_AUTH, timestamp);
}
if( !rc && get_parameter( para, pSUBKEYTYPE ) )
@ -3189,6 +3281,7 @@ do_generate_keypair( struct para_data_s *para,
get_parameter_dek( para, pPASSPHRASE_DEK ),
get_parameter_s2k( para, pPASSPHRASE_S2K ),
&sub_sk,
timestamp,
get_parameter_u32( para, pSUBKEYEXPIRE ), 1 );
}
else
@ -3196,58 +3289,69 @@ do_generate_keypair( struct para_data_s *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
Generate the key in 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,
timestamp,
get_parameter_u32 (para,
pKEYEXPIRE),
para, s);
}
else
{
/* Note, that depending on the backend, the card key
generation may update TIMESTAMP. */
rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
NULL,
&timestamp,
get_parameter_u32 (para, pKEYEXPIRE), para);
}
}
if( !rc )
rc = write_keybinding(pub_root, pub_root, pri_sk, sub_sk,
get_parameter_uint (para, pSUBKEYUSAGE));
get_parameter_uint (para, pSUBKEYUSAGE),
timestamp);
if( !rc )
rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk,
get_parameter_uint (para, pSUBKEYUSAGE));
get_parameter_uint (para, pSUBKEYUSAGE),
timestamp);
did_sub = 1;
}
if( !rc && outctrl->use_files ) { /* direct write to specified files */
if (!rc && outctrl->use_files) /* Direct write to specified files. */
{
rc = write_keyblock( outctrl->pub.stream, pub_root );
if (rc)
log_error ("can't write public key: %s\n", g10_errstr(rc) );
if( !rc ) {
if (!rc)
{
rc = write_keyblock( outctrl->sec.stream, sec_root );
if(rc)
log_error ("can't write secret key: %s\n", g10_errstr(rc) );
}
}
else if( !rc ) { /* write to the standard keyrings */
else if (!rc) /* Write to the standard keyrings. */
{
KEYDB_HANDLE pub_hd = keydb_new (0);
KEYDB_HANDLE sec_hd = keydb_new (1);
/* FIXME: we may have to create the keyring first */
rc = keydb_locate_writable (pub_hd, NULL);
if (rc)
log_error (_("no writable public keyring found: %s\n"),
g10_errstr (rc));
if (!rc) {
if (!rc)
{
rc = keydb_locate_writable (sec_hd, NULL);
if (rc)
log_error (_("no writable secret keyring found: %s\n"),
g10_errstr (rc));
}
if (!rc && opt.verbose) {
if (!rc && opt.verbose)
{
log_info (_("writing public key to `%s'\n"),
keydb_get_resource_name (pub_hd));
if (card)
@ -3258,14 +3362,16 @@ do_generate_keypair( struct para_data_s *para,
keydb_get_resource_name (sec_hd));
}
if (!rc) {
if (!rc)
{
rc = keydb_insert_keyblock (pub_hd, pub_root);
if (rc)
log_error (_("error writing public keyring `%s': %s\n"),
keydb_get_resource_name (pub_hd), g10_errstr(rc));
}
if (!rc) {
if (!rc)
{
rc = keydb_insert_keyblock (sec_hd, sec_root);
if (rc)
log_error (_("error writing secret keyring `%s': %s\n"),
@ -3275,22 +3381,26 @@ do_generate_keypair( struct para_data_s *para,
keydb_release (pub_hd);
keydb_release (sec_hd);
if (!rc) {
int no_enc_rsa =
get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
if (!rc)
{
int no_enc_rsa;
PKT_public_key *pk;
no_enc_rsa = (get_parameter_algo (para, pKEYTYPE) == PUBKEY_ALGO_RSA
&& get_parameter_uint (para, pKEYUSAGE)
&& !(get_parameter_uint( para,pKEYUSAGE) & PUBKEY_USAGE_ENC);
PKT_public_key *pk = find_kbnode (pub_root,
PKT_PUBLIC_KEY)->pkt->pkt.public_key;
&& !((get_parameter_uint (para, pKEYUSAGE)
& PUBKEY_USAGE_ENC)) );
pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key;
keyid_from_pk(pk,pk->main_keyid);
register_trusted_keyid(pk->main_keyid);
update_ownertrust (pk,
((get_ownertrust (pk) & ~TRUST_MASK)
update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
| TRUST_ULTIMATE ));
if (!opt.batch) {
if (!opt.batch)
{
tty_printf (_("public and secret key created and signed.\n") );
tty_printf ("\n");
list_keyblock(pub_root,0,1,NULL);
@ -3310,14 +3420,16 @@ do_generate_keypair( struct para_data_s *para,
}
}
if( rc ) {
if (rc)
{
if (opt.batch)
log_error ("key generation failed: %s\n", g10_errstr(rc) );
else
tty_printf (_("Key generation failed: %s\n"), g10_errstr(rc) );
print_status_key_not_created ( get_parameter_value (para, pHANDLE) );
}
else {
else
{
PKT_public_key *pk = find_kbnode (pub_root,
PKT_PUBLIC_KEY)->pkt->pkt.public_key;
print_status_key_created (did_sub? 'B':'P', pk,
@ -3326,17 +3438,15 @@ do_generate_keypair( struct para_data_s *para,
release_kbnode( pub_root );
release_kbnode( sec_root );
if( pri_sk && !card) /* the unprotected secret key unless we have a */
free_secret_key(pri_sk); /* shallow copy in card mode. */
if (pri_sk && !card) /* The unprotected secret key unless we */
free_secret_key (pri_sk); /* have a shallow copy in card mode. */
if (sub_sk)
free_secret_key(sub_sk);
}
/****************
* add a new subkey to an existing key.
* Returns true if a new key has been generated and put into the keyblocks.
*/
/* Add a new subkey to an existing key. Returns true if a new key has
been generated and put into the keyblocks. */
int
generate_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock)
{
@ -3354,36 +3464,42 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
int ask_pass = 0;
int canceled;
/* break out the primary secret key */
/* Break out the primary secret key. */
node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
if( !node ) {
if( !node )
{
log_error ("Oops; secret key not found anymore!\n");
goto leave;
}
/* make a copy of the sk to keep the protected one in the keyblock */
/* Make a copy of the sk to keep the protected one in the keyblock. */
pri_sk = copy_secret_key (NULL, node->pkt->pkt.secret_key);
cur_time = make_timestamp();
if( pri_sk->timestamp > cur_time ) {
if (pri_sk->timestamp > cur_time)
{
ulong d = pri_sk->timestamp - cur_time;
log_info ( d==1 ? _("key has been created %lu second "
"in future (time warp or clock problem)\n")
: _("key has been created %lu seconds "
"in future (time warp or clock problem)\n"), d );
if( !opt.ignore_time_conflict ) {
if (!opt.ignore_time_conflict)
{
rc = G10ERR_TIME_CONFLICT;
goto leave;
}
}
if (pri_sk->version < 4) {
if (pri_sk->version < 4)
{
log_info (_("NOTE: creating subkeys for v3 keys "
"is not OpenPGP compliant\n"));
goto leave;
}
if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) {
if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001)
{
tty_printf (_("Secret parts of primary key are not available.\n"));
rc = G10ERR_NO_SECKEY;
goto leave;
@ -3391,7 +3507,8 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
/* Unprotect to get the passphrase. */
switch( is_secret_key_protected( pri_sk ) ) {
switch (is_secret_key_protected (pri_sk) )
{
case -1:
rc = G10ERR_PUBKEY_ALGO;
break;
@ -3423,7 +3540,8 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
canceled = 0;
if (ask_pass)
dek = do_ask_passphrase (&s2k, &canceled);
else if (passphrase) {
else if (passphrase)
{
s2k = xmalloc_secure ( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = S2K_DIGEST_ALGO;
@ -3437,12 +3555,15 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
if (!rc)
rc = do_create (algo, nbits, pub_keyblock, sec_keyblock,
dek, s2k, &sub_sk, expire, 1 );
dek, s2k, &sub_sk, cur_time, expire, 1 );
if (!rc)
rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk,
use, cur_time);
if (!rc)
rc = write_keybinding(sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
if( !rc ) {
rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk,
use, cur_time);
if (!rc)
{
okay = 1;
write_status_text (STATUS_KEY_CREATED, "S");
}
@ -3453,7 +3574,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
xfree (passphrase);
xfree (dek);
xfree (s2k);
/* release the copy of the (now unprotected) secret keys */
/* Release the copy of the (now unprotected) secret keys. */
if (pri_sk)
free_secret_key (pri_sk);
if (sub_sk)
@ -3551,12 +3672,17 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
if (passphrase)
set_next_passphrase (passphrase);
/* Note, that depending on the backend, the card key generation may
update CUR_TIME. */
rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock,
&sub_sk, expire, para);
&sub_sk, &cur_time, expire, para);
if (!rc)
rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk,
use, cur_time);
if (!rc)
rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk,
use, cur_time);
if (!rc)
{
okay = 1;
@ -3577,7 +3703,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
#endif /* !ENABLE_CARD_SUPPORT */
/****************
/*
* Write a keyblock to an output stream
*/
static int
@ -3601,10 +3727,11 @@ write_keyblock( IOBUF out, KBNODE node )
}
/* Note that timestamp is an in/out arg. */
static int
gen_card_key (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk,
u32 expireval, struct para_data_s *para)
u32 *timestamp, u32 expireval, struct para_data_s *para)
{
#ifdef ENABLE_CARD_SUPPORT
int rc;
@ -3617,7 +3744,7 @@ gen_card_key (int algo, int keyno, int is_primary,
assert (algo == PUBKEY_ALGO_RSA);
/* Fixme: We don't have the serialnumber available, thus passing NULL. */
rc = agent_scd_genkey (&info, keyno, 1, NULL);
rc = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
/* if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
/* { */
/* tty_printf ("\n"); */
@ -3641,6 +3768,9 @@ gen_card_key (int algo, int keyno, int is_primary,
return gpg_error (GPG_ERR_GENERAL);
}
if (*timestamp != info.created_at)
log_info ("Note that the key does not use the suggested creation date\n");
*timestamp = info.created_at;
pk = xcalloc (1, sizeof *pk );
sk = xcalloc (1, sizeof *sk );
@ -3688,6 +3818,7 @@ gen_card_key (int algo, int keyno, int is_primary,
static int
gen_card_key_with_backup (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root,
u32 timestamp,
u32 expireval, struct para_data_s *para,
const char *backup_dir)
{
@ -3700,7 +3831,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
size_t n;
int i;
rc = generate_raw_key (algo, 1024, make_timestamp (),
rc = generate_raw_key (algo, 1024, timestamp,
&sk_unprotected, &sk_protected);
if (rc)
return rc;
@ -3857,8 +3988,8 @@ save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
/* Copy the parameters into straight buffers. */
gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_n, &rsa_n_len, sk->skey[0]);
gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_e, &rsa_e_len, sk->skey[1]);
gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[2]);
gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[3]);
gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[3]);
gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]);
if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
{
rc = G10ERR_INV_ARG;

View File

@ -198,7 +198,8 @@ int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
int keygen_add_notations(PKT_signature *sig,void *opaque);
int keygen_add_revkey(PKT_signature *sig, void *opaque);
int make_backsig(PKT_signature *sig,PKT_public_key *pk,
PKT_public_key *sub_pk,PKT_secret_key *sub_sk);
PKT_public_key *sub_pk,PKT_secret_key *sub_sk,
u32 timestamp);
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
#ifdef ENABLE_CARD_SUPPORT
int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,

368
po/be.po

File diff suppressed because it is too large Load Diff

368
po/ca.po

File diff suppressed because it is too large Load Diff

368
po/cs.po

File diff suppressed because it is too large Load Diff

368
po/da.po

File diff suppressed because it is too large Load Diff

368
po/de.po

File diff suppressed because it is too large Load Diff

368
po/el.po

File diff suppressed because it is too large Load Diff

368
po/eo.po

File diff suppressed because it is too large Load Diff

368
po/es.po

File diff suppressed because it is too large Load Diff

368
po/et.po

File diff suppressed because it is too large Load Diff

368
po/fi.po

File diff suppressed because it is too large Load Diff

368
po/fr.po

File diff suppressed because it is too large Load Diff

368
po/gl.po

File diff suppressed because it is too large Load Diff

368
po/hu.po

File diff suppressed because it is too large Load Diff

368
po/id.po

File diff suppressed because it is too large Load Diff

368
po/it.po

File diff suppressed because it is too large Load Diff

368
po/ja.po

File diff suppressed because it is too large Load Diff

368
po/nb.po

File diff suppressed because it is too large Load Diff

368
po/pl.po

File diff suppressed because it is too large Load Diff

368
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

368
po/ro.po

File diff suppressed because it is too large Load Diff

368
po/ru.po

File diff suppressed because it is too large Load Diff

368
po/sk.po

File diff suppressed because it is too large Load Diff

368
po/sv.po

File diff suppressed because it is too large Load Diff

368
po/tr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,14 @@
2007-07-05 Werner Koch <wk@g10code.com>
* command.c (has_option_name, skip_options): New.
(cmd_genkey): Add option --timestamp.
(cmd_writekey): Enter confidential mode while inquiring the key data.
* app.c (app_genkey): Add arg CREATETIME.
* app-common.h (app_ctx_s): Likewise
* app-openpgp.c (do_genkey): Ditto. Use it.
2007-07-04 Werner Koch <wk@g10code.com>
* command.c (cmd_getinfo): New subcommand "version".

View File

@ -97,6 +97,7 @@ struct app_ctx_s {
const unsigned char *pk, size_t pklen);
gpg_error_t (*genkey) (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t (*change_pin) (app_t app, ctrl_t ctrl,
@ -167,6 +168,7 @@ gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t app_get_challenge (app_t app, size_t nbytes,

View File

@ -1981,6 +1981,7 @@ do_writekey (app_t app, ctrl_t ctrl,
/* Handle the GENKEY command. */
static gpg_error_t
do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
@ -2014,7 +2015,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
if (rc)
return rc;
/* Prepare for key generation by verifying the ADmin PIN. */
/* Prepare for key generation by verifying the Admin PIN. */
rc = verify_chv3 (app, pincb, pincb_arg);
if (rc)
goto leave;
@ -2067,7 +2068,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
/* log_printhex ("RSA e:", e, elen); */
send_key_data (ctrl, "e", e, elen);
created_at = gnupg_get_time ();
created_at = createtime? createtime : gnupg_get_time ();
sprintf (numbuf, "%lu", (unsigned long)created_at);
send_status_info (ctrl, "KEY-CREATED-AT",
numbuf, (size_t)strlen(numbuf), NULL, 0);

View File

@ -766,6 +766,7 @@ app_writekey (app_t app, ctrl_t ctrl,
/* Perform a SETATTR operation. */
gpg_error_t
app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
@ -780,7 +781,8 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
err = lock_reader (app->slot);
if (err)
return err;
err = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg);
err = app->fnc.genkey (app, ctrl, keynostr, flags,
createtime, pincb, pincb_arg);
unlock_reader (app->slot);
if (opt.verbose)
log_info ("operation genkey result: %s\n", gpg_strerror (err));

View File

@ -1,5 +1,6 @@
/* command.c - SCdaemon command handler
* Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
* 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -178,6 +179,41 @@ has_option (const char *line, const char *name)
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
/* Same as has_option but does only test for the name of the option
and ignores an argument, i.e. with NAME being "--hash" it would
return a pointer for "--hash" as well as for "--hash=foo". If
thhere is no such option NULL is returned. The pointer returned
points right behind the option name, this may be an equal sign, Nul
or a space. */
static const char *
has_option_name (const char *line, const char *name)
{
const char *s;
int n = strlen (name);
s = strstr (line, name);
return (s && (s == line || spacep (s-1))
&& (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
}
/* Skip over options. It is assumed that leading spaces have been
removed (this is the case for lines passed to a handler from
assuan). Blanks after the options are also removed. */
static char *
skip_options (char *line)
{
while ( *line == '-' && line[1] == '-' )
{
while (*line && !spacep (line))
line++;
while (spacep (line))
line++;
}
return line;
}
/* Convert the STRING into a newly allocated buffer while translating
the hex numbers. Stops at the first invalid character. Blanks and
@ -1099,7 +1135,9 @@ cmd_writekey (assuan_context_t ctx, char *line)
return out_of_core ();
/* Now get the actual keydata. */
assuan_begin_confidential (ctx);
rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
assuan_end_confidential (ctx);
if (rc)
{
xfree (keyid);
@ -1118,7 +1156,7 @@ cmd_writekey (assuan_context_t ctx, char *line)
/* GENKEY [--force] <no>
/* GENKEY [--force] [--timestamp=<isodate>] <no>
Generate a key on-card identified by NO, which is application
specific. Return values are application specific. For OpenPGP
@ -1128,11 +1166,14 @@ cmd_writekey (assuan_context_t ctx, char *line)
S KEY-CREATED-AT <seconds_since_epoch>
S KEY-DATA [p|n] <hexdata>
--force is required to overwrite an already existing key. The
KEY-CREATED-AT is required for further processing because it is
part of the hashed key material for the fingerprint.
If --timestamp is given an OpenPGP key will be created using this
value. The value needs to be in ISO Format; e.g.
"--timestamp=20030316T120000" and after 1970-01-01 00:00:00.
The public part of the key can also later be retrieved using the
READKEY command.
@ -1143,19 +1184,28 @@ cmd_genkey (assuan_context_t ctx, char *line)
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
char *keyno;
int force = has_option (line, "--force");
int force;
const char *s;
time_t timestamp;
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
/* Skip over options. */
while ( *line == '-' && line[1] == '-' )
force = has_option (line, "--force");
if ((s=has_option_name (line, "--timestamp")))
{
while (*line && !spacep (line))
line++;
while (spacep (line))
line++;
if (*s != '=')
return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
timestamp = isotime2epoch (s+1);
if (timestamp < 1)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
}
else
timestamp = 0;
line = skip_options (line);
if (!*line)
return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
keyno = line;
@ -1172,7 +1222,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
keyno = xtrystrdup (keyno);
if (!keyno)
return out_of_core ();
rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0,
timestamp, pin_cb, ctx);
xfree (keyno);
TEST_CARD_REMOVAL (ctrl, rc);