Backport of Creation-Date parameter for unattended key generation.
authorWerner Koch <wk@gnupg.org>
Tue, 5 May 2009 11:44:56 +0000 (11:44 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 5 May 2009 11:44:56 +0000 (11:44 +0000)
g10/ChangeLog
g10/keygen.c
include/util.h
util/ChangeLog
util/miscutil.c

index af6bf09..52696c4 100644 (file)
@@ -1,5 +1,16 @@
 2009-05-05  Werner Koch  <wk@g10code.com>
 
+       * 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.
index aac4c7c..d5a80dd 100644 (file)
@@ -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_keypairstruct 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;
-
-    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;
+  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;
+}
 
-    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_keypairstruct 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 ),
index e8fe9a5..ffae3d2 100644 (file)
@@ -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 */
index f44e459..f99f0a4 100644 (file)
@@ -1,3 +1,7 @@
+2009-05-05  Werner Koch  <wk@g10code.com>
+
+       * miscutil.c (isotime2seconds): New.
+
 2009-04-05  David Shaw  <dshaw@jabberwocky.com>
 
        * srv.h: Move to include/srv.h.
index 3012963..14fdc79 100644 (file)
@@ -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
  */