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,9 +65,9 @@ gnupg_get_isotime (gnupg_isotime_t timebuf)
#else
tp = gmtime (&atime);
#endif
sprintf (timebuf,"%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);
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;

File diff suppressed because it is too large Load Diff

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

@ -96,9 +96,10 @@ struct app_ctx_s {
void *pincb_arg,
const unsigned char *pk, size_t pklen);
gpg_error_t (*genkey) (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
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,
const char *chvnostr, int reset_mode,
gpg_error_t (*pincb)(void*, const char *, char **),
@ -166,9 +167,10 @@ gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
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,
unsigned char *buffer);
gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,

View File

@ -1981,8 +1981,9 @@ 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,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
int rc;
char numbuf[30];
@ -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);