From 631a0de335c991044bd6100cdedcf47410abb1d8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 5 May 2009 11:44:56 +0000 Subject: [PATCH] Backport of Creation-Date parameter for unattended key generation. --- g10/ChangeLog | 11 ++++ g10/keygen.c | 169 +++++++++++++++++++++++++++++++++--------------- include/util.h | 1 + util/ChangeLog | 4 ++ util/miscutil.c | 51 +++++++++++++++ 5 files changed, 185 insertions(+), 51 deletions(-) diff --git a/g10/ChangeLog b/g10/ChangeLog index af6bf0981..52696c43c 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,5 +1,16 @@ 2009-05-05 Werner Koch + * keygen.c (output_control_s): s/create/creation/. + (enum para_name): Add pCREATIONDATE, pKEYCREATIONDATE. Remove + pCREATETIME. + (generate_keypair): Do not set old pCREATETIME. + (parse_creation_string): New. + (proc_parameter_file): Set pCREATIONDATE. + (read_parameter_file): Add keyword "Creation-Date". + (do_generate_keypair): Remove arg TIMESTAMP. Set it using + pKEYCREATIONDATE. + (get_parameter_u32): Set a default pKEYCREATIONDATE. + * tdbio.c (lookup_hashtable): Add const to function args. (cmp_trec_fpr): Ditto. (tdbio_search_trust_byfpr): Remove cast. diff --git a/g10/keygen.c b/g10/keygen.c index aac4c7c74..d5a80dd59 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -57,8 +57,9 @@ enum para_name { pPREFERENCES, pREVOKER, pUSERID, + pCREATIONDATE, + pKEYCREATIONDATE, /* Same in seconds since epoch. */ pEXPIREDATE, - pCREATETIME, /* in n seconds */ pKEYEXPIRE, /* in n seconds */ pSUBKEYEXPIRE, /* in n seconds */ pPASSPHRASE, @@ -77,8 +78,8 @@ struct para_data_s { union { DEK *dek; STRING2KEY *s2k; - u32 create; u32 expire; + u32 creation; unsigned int usage; struct revocation_key revkey; char value[1]; @@ -119,9 +120,9 @@ static byte zip_prefs[MAX_PREFS]; static int nzip_prefs; static int mdc_available,ks_modify; -static void do_generate_keypair( struct para_data_s *para, +static void do_generate_keypair (struct para_data_s *para, struct output_control_s *outctrl, - u32 timestamp, int card ); + int card); 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, @@ -1595,25 +1596,43 @@ ask_keysize( int algo ) * similar. */ u32 -parse_expire_string(u32 timestamp,const char *string) +parse_expire_string (u32 timestamp, const char *string) { - int mult; - u32 seconds,abs_date=0; + int mult; + u32 seconds; + u32 abs_date = 0; - if( !*string ) - seconds = 0; - else if ( !strncmp (string, "seconds=", 8) ) - seconds = atoi (string+8); - else if( (abs_date = scan_isodatestr(string)) && abs_date > timestamp ) - seconds = abs_date - timestamp; - else if( (mult=check_valid_days(string)) ) - seconds = atoi(string) * 86400L * mult; - else - seconds=(u32)-1; - - return seconds; + if ( !*string ) + seconds = 0; + else if ( !strncmp (string, "seconds=", 8) ) + seconds = atoi (string+8); + else if( (abs_date = scan_isodatestr(string)) && abs_date > timestamp ) + seconds = abs_date - timestamp; + else if( (mult=check_valid_days(string)) ) + seconds = atoi(string) * 86400L * mult; + else + seconds=(u32)-1; + + return seconds; } +/* Parse an 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))) + seconds = isotime2seconds (string); + return seconds; +} + + /* object == 0 for a key, and 1 for a sig */ u32 ask_expire_interval(u32 timestamp,int object,const char *def_expire) @@ -1678,7 +1697,7 @@ ask_expire_interval(u32 timestamp,int object,const char *def_expire) } cpr_kill_prompt(); trim_spaces(answer); - interval = parse_expire_string( timestamp, answer ); + interval = parse_expire_string (timestamp, answer); if( interval == (u32)-1 ) { tty_printf(_("invalid value\n")); @@ -2121,16 +2140,56 @@ parse_revocation_key (const char *fname, static u32 get_parameter_u32( struct para_data_s *para, enum para_name key ) { - struct para_data_s *r = get_parameter( para, key ); + struct para_data_s *r; - if( !r ) - return 0; + r = get_parameter (para, key); + if (!r && key == pKEYCREATIONDATE) + { + /* Return a default for the creation date if it has not yet been + set. We need to set this into the parameter list so that a + second call for pKEYCREATIONDATE returns the same value. The + default is the current time unless an explicit creation date + has been specified. Checking the creation date here is only + for the case that it has not yet been parsed. */ + r = get_parameter (para, pCREATIONDATE); + if (r && *r->u.value) + { + u32 seconds; + + seconds = parse_creation_string (r->u.value); + if (!seconds) + log_error ("invalid creation date in line %d\n", r->lnr ); + else /* Okay: Change this parameter. */ + { + r->u.creation = seconds; + r->key = pKEYCREATIONDATE; + } + } + + r = get_parameter (para, key); + if (!r) + { + /* Create a new parameter. */ + r = xmalloc_clear (sizeof *r); + r->key = key; + r->u.creation = make_timestamp (); + r->next = para; + para = r; + } + + r = get_parameter (para, key); + assert (r); + } + + + 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 ) return r->u.usage; - if( r->key == pCREATETIME ) - return r->u.create; return (unsigned int)strtoul( r->u.value, NULL, 10 ); } @@ -2171,13 +2230,6 @@ proc_parameter_file( struct para_data_s *para, const char *fname, size_t n; char *p; int have_user_id=0,err,algo; - u32 timestamp; - - /* If we were told a creation time from outside, use it. Otherwise - look at the clock. */ - timestamp=get_parameter_u32( para, pCREATETIME ); - if(!timestamp) - timestamp=make_timestamp(); /* Check that we have all required parameters. */ r = get_parameter( para, pKEYTYPE ); @@ -2315,9 +2367,9 @@ proc_parameter_file( struct para_data_s *para, const char *fname, /* make DEK and S2K from the Passphrase */ r = get_parameter( para, pPASSPHRASE ); if( r && *r->u.value ) { - /* we have a plain text passphrase - create a DEK from it. - * It is a little bit ridiculous to keep it ih secure memory - * but becuase we do this alwasy, why not here */ + /* We have a plain text passphrase - create a DEK from it. + * It is a little bit ridiculous to keep it in secure memory + * but because we do this alwasy, why not here. */ STRING2KEY *s2k; DEK *dek; @@ -2343,14 +2395,31 @@ 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 ) { u32 seconds; - seconds = parse_expire_string( timestamp, r->u.value ); - if( seconds == (u32)-1 ) + seconds = parse_expire_string + (get_parameter_u32 (para, pKEYCREATIONDATE), r->u.value); + if (seconds == (u32)(-1)) { log_error("%s:%d: invalid expire date\n", fname, r->lnr ); return -1; @@ -2370,7 +2439,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname, return -1; } - do_generate_keypair( para, outctrl, timestamp, card ); + do_generate_keypair (para, outctrl, card); return 0; } @@ -2396,6 +2465,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 }, @@ -2600,7 +2670,7 @@ generate_keypair (const char *fname, const char *card_serialno, int algo; unsigned int use; int both = 0; - u32 timestamp,expire; + u32 expire; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; @@ -2620,13 +2690,6 @@ generate_keypair (const char *fname, const char *card_serialno, return; } - timestamp=make_timestamp(); - r = xmalloc_clear( sizeof *r ); - r->key = pCREATETIME; - r->u.create = timestamp; - r->next = para; - para = r; - if (card_serialno) { #ifdef ENABLE_CARD_SUPPORT @@ -2741,7 +2804,8 @@ generate_keypair (const char *fname, const char *card_serialno, para = r; } - expire = ask_expire_interval(timestamp,0,NULL); + expire = ask_expire_interval (get_parameter_u32 (para, pKEYCREATIONDATE), + 0, NULL); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYEXPIRE; r->u.expire = expire; @@ -2878,8 +2942,8 @@ start_tree(KBNODE *tree) } static void -do_generate_keypair( struct para_data_s *para,struct output_control_s *outctrl, - u32 timestamp,int card ) +do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl, + int card) { KBNODE pub_root = NULL; KBNODE sec_root = NULL; @@ -2888,6 +2952,7 @@ do_generate_keypair( struct para_data_s *para,struct output_control_s *outctrl, struct revocation_key *revkey; int rc; int did_sub = 0; + u32 timestamp; if( outctrl->dryrun ) { @@ -2965,7 +3030,7 @@ do_generate_keypair( struct para_data_s *para,struct output_control_s *outctrl, } - /* we create the packets as a tree of kbnodes. Because the + /* 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. @@ -2974,6 +3039,8 @@ do_generate_keypair( struct para_data_s *para,struct output_control_s *outctrl, start_tree(&pub_root); start_tree(&sec_root); + timestamp = get_parameter_u32 (para, pKEYCREATIONDATE); + if (!card) { rc = do_create( get_parameter_algo( para, pKEYTYPE ), diff --git a/include/util.h b/include/util.h index e8fe9a590..ffae3d211 100644 --- a/include/util.h +++ b/include/util.h @@ -149,6 +149,7 @@ int is_file_compressed(const char *s, int *r_status); /*-- miscutil.c --*/ u32 make_timestamp(void); u32 scan_isodatestr( const char *string ); +u32 isotime2seconds (const char *string); const char *strtimevalue( u32 stamp ); const char *strtimestamp( u32 stamp ); /* GMT */ const char *isotimestamp( u32 stamp ); /* GMT with hh:mm:ss */ diff --git a/util/ChangeLog b/util/ChangeLog index f44e45977..f99f0a461 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,7 @@ +2009-05-05 Werner Koch + + * miscutil.c (isotime2seconds): New. + 2009-04-05 David Shaw * srv.h: Move to include/srv.h. diff --git a/util/miscutil.c b/util/miscutil.c index 30129634c..14fdc79c0 100644 --- a/util/miscutil.c +++ b/util/miscutil.c @@ -152,6 +152,57 @@ isotimestamp (u32 stamp) return buffer; } + +/* Scan am ISO timestamp and return an Epoch based timestamp. The only + supported format is "yyyymmddThhmmss" delimited by white space, nul, a + colon or a comma. Returns 0 for an invalid string. */ +u32 +isotime2seconds (const char *string) +{ + const char *s; + int year, month, day, hour, minu, sec; + struct tm tmbuf; + int i; + time_t result; + + if (!*string) + return 0; + for (s=string, i=0; i < 8; i++, s++) + if (!digitp (s)) + return 0; + if (*s != 'T') + return 0; + for (s++, i=9; i < 15; i++, s++) + if (!digitp (s)) + return 0; + if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ',')) + return 0; /* 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 0; + + 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; + result = timegm (&tmbuf); + return (result == (time_t)(-1))? 0 : (u32)result; +} + + /**************** * Note: this function returns local time */