Use macros for iobuf ioctls.
[gnupg.git] / g10 / keygen.c
index de57f23..9d5d39d 100644 (file)
@@ -1,12 +1,12 @@
 /* keygen.c - generate a key pair
 /* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006, 2007, 2009 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
  *
  * 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 2 of the License, or
+ * 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,
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
@@ -29,6 +28,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+
+#include "gpg.h"
 #include "util.h"
 #include "main.h"
 #include "packet.h"
 #include "util.h"
 #include "main.h"
 #include "packet.h"
 #include "trustdb.h"
 #include "status.h"
 #include "i18n.h"
 #include "trustdb.h"
 #include "status.h"
 #include "i18n.h"
-#include "cardglue.h"
+#include "keyserver-internal.h"
+#include "call-agent.h"
+
+/* The default algorithms.  If you change them remember to change them
+   also in gpg.c:gpgconf_list.  You should also check that the value
+   is inside the bounds enforced by ask_keysize and gen_xxx.  */
+#define DEFAULT_STD_ALGO    GCRY_PK_RSA
+#define DEFAULT_STD_KEYSIZE 2048
+
 
 #define MAX_PREFS 30 
 
 
 #define MAX_PREFS 30 
 
@@ -57,6 +66,8 @@ enum para_name {
   pPREFERENCES,
   pREVOKER,
   pUSERID,
   pPREFERENCES,
   pREVOKER,
   pUSERID,
+  pCREATIONDATE,
+  pKEYCREATIONDATE, /* Same in seconds since epoch.  */
   pEXPIREDATE,
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
   pEXPIREDATE,
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
@@ -65,7 +76,8 @@ enum para_name {
   pPASSPHRASE_S2K,
   pSERIALNO,
   pBACKUPENCDIR,
   pPASSPHRASE_S2K,
   pSERIALNO,
   pBACKUPENCDIR,
-  pHANDLE
+  pHANDLE,
+  pKEYSERVER
 };
 
 struct para_data_s {
 };
 
 struct para_data_s {
@@ -76,6 +88,7 @@ struct para_data_s {
         DEK *dek;
         STRING2KEY *s2k;
         u32 expire;
         DEK *dek;
         STRING2KEY *s2k;
         u32 expire;
+        u32 creation;
         unsigned int usage;
         struct revocation_key revkey;
         char value[1];
         unsigned int usage;
         struct revocation_key revkey;
         char value[1];
@@ -85,18 +98,19 @@ struct para_data_s {
 struct output_control_s {
     int lnr;
     int dryrun;
 struct output_control_s {
     int lnr;
     int dryrun;
+    int ask_passphrase;
     int use_files;
     struct {
        char  *fname;
        char  *newfname;
        IOBUF stream;
     int use_files;
     struct {
        char  *fname;
        char  *newfname;
        IOBUF stream;
-       armor_filter_context_t afx;
+       armor_filter_context_t *afx;
     } pub;
     struct {
        char  *fname;
        char  *newfname;
        IOBUF stream;
     } pub;
     struct {
        char  *fname;
        char  *newfname;
        IOBUF stream;
-       armor_filter_context_t afx;
+       armor_filter_context_t *afx;
     } sec;
 };
 
     } sec;
 };
 
@@ -121,49 +135,16 @@ static void do_generate_keypair( struct para_data_s *para,
 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,
 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 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);
 
 
                                      u32 expireval, struct para_data_s *para,
                                      const char *backup_dir);
 
 
-#if GNUPG_MAJOR_VERSION == 1
-#define GET_NBITS(a)  mpi_get_nbits (a)
-#else
-#define GET_NBITS(a)  gcry_mpi_get_nbits (a)
-#endif
-
-#ifdef ENABLE_CARD_SUPPORT
-static int
-copy_mpi (MPI a, unsigned char *buffer, size_t len, size_t *ncopied)
-{
-  int rc;
-#if GNUPG_MAJOR_VERSION == 1
-  unsigned char *tmp;
-  unsigned int n;
-
-  tmp = mpi_get_secure_buffer (a, &n, NULL);
-  if (n > len)
-    rc = G10ERR_GENERAL;
-  else
-    {
-      rc = 0;
-      memcpy (buffer, tmp, n);
-      *ncopied = n;
-    }
-  xfree (tmp);
-#else /* GNUPG_MAJOR_VERSION != 1 */
-  rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, len, ncopied, a);
-#endif /* GNUPG_MAJOR_VERSION != 1 */
-  if (rc)
-    log_error ("mpi_copy failed: %s\n", gpg_strerror (rc));
-  return rc;
-}
-#endif /* ENABLE_CARD_SUPPORT */
-
-
-
 static void
 print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
 {
 static void
 print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
 {
@@ -209,11 +190,11 @@ print_status_key_not_created (const char *handle)
 static void
 write_uid( KBNODE root, const char *s )
 {
 static void
 write_uid( KBNODE root, const char *s )
 {
-    PACKET *pkt = m_alloc_clear(sizeof *pkt );
+    PACKET *pkt = xmalloc_clear(sizeof *pkt );
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
-    pkt->pkt.user_id = m_alloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
+    pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
     pkt->pkt.user_id->len = n;
     pkt->pkt.user_id->ref = 1;
     strcpy(pkt->pkt.user_id->name, s);
     pkt->pkt.user_id->len = n;
     pkt->pkt.user_id->ref = 1;
     strcpy(pkt->pkt.user_id->name, s);
@@ -225,9 +206,6 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
 {
     byte buf[1];
 
 {
     byte buf[1];
 
-    if (!use) 
-        return;
-
     buf[0] = 0;
 
     /* The spec says that all primary keys MUST be able to certify. */
     buf[0] = 0;
 
     /* The spec says that all primary keys MUST be able to certify. */
@@ -240,6 +218,10 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
         buf[0] |= 0x04 | 0x08;
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
         buf[0] |= 0x04 | 0x08;
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
+
+    if (!buf[0]) 
+        return;
+
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
@@ -255,7 +237,7 @@ keygen_add_key_expire( PKT_signature *sig, void *opaque )
         if(pk->expiredate > pk->timestamp)
          u= pk->expiredate - pk->timestamp;
        else
         if(pk->expiredate > pk->timestamp)
          u= pk->expiredate - pk->timestamp;
        else
-         u= 0;
+         u= 1;
 
        buf[0] = (u >> 24) & 0xff;
        buf[1] = (u >> 16) & 0xff;
 
        buf[0] = (u >> 24) & 0xff;
        buf[1] = (u >> 16) & 0xff;
@@ -325,7 +307,7 @@ keygen_set_std_prefs (const char *string,int personal)
     byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
     int nsym=0, nhash=0, nzip=0, val, rc=0;
     int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */
     byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
     int nsym=0, nhash=0, nzip=0, val, rc=0;
     int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */
-    char dummy_string[45]; /* enough for 15 items */
+    char dummy_string[20*4+1]; /* Enough for 20 items. */
 
     if (!string || !ascii_strcasecmp (string, "default"))
       {
 
     if (!string || !ascii_strcasecmp (string, "default"))
       {
@@ -335,15 +317,28 @@ keygen_set_std_prefs (const char *string,int personal)
          {
            dummy_string[0]='\0';
 
          {
            dummy_string[0]='\0';
 
+            /* The rationale why we use the order AES256,192,128 is
+               for compatibility reasons with PGP.  If gpg would
+               define AES128 first, we would get the somewhat
+               confusing situation:
+
+                 gpg -r pgpkey -r gpgkey  ---gives--> AES256
+                 gpg -r gpgkey -r pgpkey  ---gives--> AES
+                 
+               Note that by using --personal-cipher-preferences it is
+               possible to prefer AES128.
+            */
+
            /* Make sure we do not add more than 15 items here, as we
            /* Make sure we do not add more than 15 items here, as we
-              could overflow the size of dummy_string. */
-           if(!check_cipher_algo(CIPHER_ALGO_AES256))
+              could overflow the size of dummy_string.  We currently
+              have at most 12. */
+           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES256) )
              strcat(dummy_string,"S9 ");
              strcat(dummy_string,"S9 ");
-           if(!check_cipher_algo(CIPHER_ALGO_AES192))
+           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES192) )
              strcat(dummy_string,"S8 ");
              strcat(dummy_string,"S8 ");
-           if(!check_cipher_algo(CIPHER_ALGO_AES))
+           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) )
              strcat(dummy_string,"S7 ");
              strcat(dummy_string,"S7 ");
-           if(!check_cipher_algo(CIPHER_ALGO_CAST5))
+           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_CAST5) )
              strcat(dummy_string,"S3 ");
            strcat(dummy_string,"S2 "); /* 3DES */
            /* If we have it, IDEA goes *after* 3DES so it won't be
              strcat(dummy_string,"S3 ");
            strcat(dummy_string,"S2 "); /* 3DES */
            /* If we have it, IDEA goes *after* 3DES so it won't be
@@ -353,11 +348,41 @@ keygen_set_std_prefs (const char *string,int personal)
               break PGP2, but that is difficult with the current
               code, and not really worth checking as a non-RSA <=2048
               bit key wouldn't be usable by PGP2 anyway. -dms */
               break PGP2, but that is difficult with the current
               code, and not really worth checking as a non-RSA <=2048
               bit key wouldn't be usable by PGP2 anyway. -dms */
-           if(!check_cipher_algo(CIPHER_ALGO_IDEA))
+           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) )
              strcat(dummy_string,"S1 ");
 
              strcat(dummy_string,"S1 ");
 
-           /* SHA-1, RIPEMD160, ZLIB, ZIP */
-           strcat(dummy_string,"H2 H3 Z2 Z1");
+
+            /* The default hash algo order is:
+                 SHA-256, SHA-1, SHA-384, SHA-512, SHA-224.
+               Ordering SHA-1 before SHA-384 might be viewed as a bit
+               strange; it is done because we expect that soon enough
+               SHA-3 will be available and at that point there should
+               be no more need for SHA-384 etc.  Anyway this order is
+               just a default and can easily be changed by a config
+               option.  */
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256))
+             strcat (dummy_string, "H8 ");
+
+           strcat (dummy_string, "H2 "); /* SHA-1 */
+
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384))
+             strcat (dummy_string, "H9 ");
+
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512))
+             strcat (dummy_string, "H10 ");
+
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224))
+             strcat (dummy_string, "H11 ");
+
+
+           /* ZLIB */
+           strcat(dummy_string,"Z2 ");
+
+           if(!check_compress_algo(COMPRESS_ALGO_BZIP2))
+             strcat(dummy_string,"Z3 ");
+
+           /* ZIP */
+           strcat(dummy_string,"Z1");
 
            string=dummy_string;
          }
 
            string=dummy_string;
          }
@@ -369,16 +394,16 @@ keygen_set_std_prefs (const char *string,int personal)
       {
        char *tok,*prefstring;
 
       {
        char *tok,*prefstring;
 
-       prefstring=m_strdup(string); /* need a writable string! */
+       prefstring=xstrdup(string); /* need a writable string! */
 
        while((tok=strsep(&prefstring," ,")))
          {
 
        while((tok=strsep(&prefstring," ,")))
          {
-           if((val=string_to_cipher_algo(tok)))
+           if((val=string_to_cipher_algo (tok)))
              {
                if(set_one_pref(val,1,tok,sym,&nsym))
                  rc=-1;
              }
              {
                if(set_one_pref(val,1,tok,sym,&nsym))
                  rc=-1;
              }
-           else if((val=string_to_digest_algo(tok)))
+           else if((val=string_to_digest_algo (tok)))
              {
                if(set_one_pref(val,2,tok,hash,&nhash))
                  rc=-1;
              {
                if(set_one_pref(val,2,tok,hash,&nhash))
                  rc=-1;
@@ -409,7 +434,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
          }
 
              }
          }
 
-       m_free(prefstring);
+       xfree(prefstring);
       }
 
     if(!rc)
       }
 
     if(!rc)
@@ -418,7 +443,7 @@ keygen_set_std_prefs (const char *string,int personal)
          {
            if(personal==PREFTYPE_SYM)
              {
          {
            if(personal==PREFTYPE_SYM)
              {
-               m_free(opt.personal_cipher_prefs);
+               xfree(opt.personal_cipher_prefs);
 
                if(nsym==0)
                  opt.personal_cipher_prefs=NULL;
 
                if(nsym==0)
                  opt.personal_cipher_prefs=NULL;
@@ -427,7 +452,7 @@ keygen_set_std_prefs (const char *string,int personal)
                    int i;
 
                    opt.personal_cipher_prefs=
                    int i;
 
                    opt.personal_cipher_prefs=
-                     m_alloc(sizeof(prefitem_t *)*(nsym+1));
+                     xmalloc(sizeof(prefitem_t *)*(nsym+1));
 
                    for (i=0; i<nsym; i++)
                      {
 
                    for (i=0; i<nsym; i++)
                      {
@@ -441,7 +466,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
            else if(personal==PREFTYPE_HASH)
              {
              }
            else if(personal==PREFTYPE_HASH)
              {
-               m_free(opt.personal_digest_prefs);
+               xfree(opt.personal_digest_prefs);
 
                if(nhash==0)
                  opt.personal_digest_prefs=NULL;
 
                if(nhash==0)
                  opt.personal_digest_prefs=NULL;
@@ -450,7 +475,7 @@ keygen_set_std_prefs (const char *string,int personal)
                    int i;
 
                    opt.personal_digest_prefs=
                    int i;
 
                    opt.personal_digest_prefs=
-                     m_alloc(sizeof(prefitem_t *)*(nhash+1));
+                     xmalloc(sizeof(prefitem_t *)*(nhash+1));
 
                    for (i=0; i<nhash; i++)
                      {
 
                    for (i=0; i<nhash; i++)
                      {
@@ -464,7 +489,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
            else if(personal==PREFTYPE_ZIP)
              {
              }
            else if(personal==PREFTYPE_ZIP)
              {
-               m_free(opt.personal_compress_prefs);
+               xfree(opt.personal_compress_prefs);
 
                if(nzip==0)
                  opt.personal_compress_prefs=NULL;
 
                if(nzip==0)
                  opt.personal_compress_prefs=NULL;
@@ -473,7 +498,7 @@ keygen_set_std_prefs (const char *string,int personal)
                    int i;
 
                    opt.personal_compress_prefs=
                    int i;
 
                    opt.personal_compress_prefs=
-                     m_alloc(sizeof(prefitem_t *)*(nzip+1));
+                     xmalloc(sizeof(prefitem_t *)*(nzip+1));
 
                    for (i=0; i<nzip; i++)
                      {
 
                    for (i=0; i<nzip; i++)
                      {
@@ -502,15 +527,18 @@ keygen_set_std_prefs (const char *string,int personal)
 
 /* Return a fake user ID containing the preferences.  Caller must
    free. */
 
 /* Return a fake user ID containing the preferences.  Caller must
    free. */
-PKT_user_id *keygen_get_std_prefs(void)
+PKT_user_id *
+keygen_get_std_prefs(void)
 {
   int i,j=0;
 {
   int i,j=0;
-  PKT_user_id *uid=m_alloc_clear(sizeof(PKT_user_id));
+  PKT_user_id *uid=xmalloc_clear(sizeof(PKT_user_id));
 
   if(!prefs_initialized)
     keygen_set_std_prefs(NULL,0);
 
 
   if(!prefs_initialized)
     keygen_set_std_prefs(NULL,0);
 
-  uid->prefs=m_alloc((sizeof(prefitem_t *)*
+  uid->ref=1;
+
+  uid->prefs=xmalloc((sizeof(prefitem_t *)*
                      (nsym_prefs+nhash_prefs+nzip_prefs+1)));
 
   for(i=0;i<nsym_prefs;i++,j++)
                      (nsym_prefs+nhash_prefs+nzip_prefs+1)));
 
   for(i=0;i<nsym_prefs;i++,j++)
@@ -534,8 +562,8 @@ PKT_user_id *keygen_get_std_prefs(void)
   uid->prefs[j].type=PREFTYPE_NONE;
   uid->prefs[j].value=0;
 
   uid->prefs[j].type=PREFTYPE_NONE;
   uid->prefs[j].value=0;
 
-  uid->mdc_feature=mdc_available;
-  uid->ks_modify=ks_modify;
+  uid->flags.mdc=mdc_available;
+  uid->flags.ks_modify=ks_modify;
 
   return uid;
 }
 
   return uid;
 }
@@ -556,10 +584,10 @@ add_feature_mdc (PKT_signature *sig,int enabled)
 
     if (!s || !n) { /* create a new one */
         n = 1;
 
     if (!s || !n) { /* create a new one */
         n = 1;
-        buf = m_alloc_clear (n);
+        buf = xmalloc_clear (n);
     }
     else {
     }
     else {
-        buf = m_alloc (n);
+        buf = xmalloc (n);
         memcpy (buf, s, n);
     }
 
         memcpy (buf, s, n);
     }
 
@@ -578,7 +606,7 @@ add_feature_mdc (PKT_signature *sig,int enabled)
     else
       build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
 
     else
       build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
 
-    m_free (buf);
+    xfree (buf);
 }
 
 static void
 }
 
 static void
@@ -600,10 +628,10 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
 
   if (!s || !n) { /* create a new one */
     n = 1;
 
   if (!s || !n) { /* create a new one */
     n = 1;
-    buf = m_alloc_clear (n);
+    buf = xmalloc_clear (n);
   }
   else {
   }
   else {
-    buf = m_alloc (n);
+    buf = xmalloc (n);
     memcpy (buf, s, n);
   }
 
     memcpy (buf, s, n);
   }
 
@@ -622,44 +650,48 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
   else
     build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n);
 
   else
     build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n);
 
-  m_free (buf);
+  xfree (buf);
 }
 
 }
 
+
 int
 int
-keygen_upd_std_prefs( PKT_signature *sig, void *opaque )
+keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
 {
 {
-    if (!prefs_initialized)
-        keygen_set_std_prefs (NULL, 0);
-
-    if (nsym_prefs) 
-        build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
-    else
-      {
-        delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
-        delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
-      }
-
-    if (nhash_prefs)
-        build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
-    else
-      {
-       delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH);
-       delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH);
-      }
-
-    if (nzip_prefs)
-        build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
-    else
-      {
-        delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
-        delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
-      }
+  (void)opaque;
+  
+  if (!prefs_initialized)
+    keygen_set_std_prefs (NULL, 0);
+  
+  if (nsym_prefs) 
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
+    }
+  
+  if (nhash_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH);
+    }
 
 
-    /* Make sure that the MDC feature flag is set if needed */
-    add_feature_mdc (sig,mdc_available);
-    add_keyserver_modify (sig,ks_modify);
+  if (nzip_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
+    }
+  
+  /* Make sure that the MDC feature flag is set if needed.  */
+  add_feature_mdc (sig,mdc_available);
+  add_keyserver_modify (sig,ks_modify);
+  keygen_add_keyserver_url(sig,NULL);
 
 
-    return 0;
+  return 0;
 }
 
 
 }
 
 
@@ -676,6 +708,7 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque )
     do_add_key_flags (sig, pk->pubkey_usage);
     keygen_add_key_expire( sig, opaque );
     keygen_upd_std_prefs (sig, opaque);
     do_add_key_flags (sig, pk->pubkey_usage);
     keygen_add_key_expire( sig, opaque );
     keygen_upd_std_prefs (sig, opaque);
+    keygen_add_keyserver_url(sig,NULL);
 
     return 0;
 }
 
     return 0;
 }
@@ -685,6 +718,9 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
 {
   const char *url=opaque;
 
 {
   const char *url=opaque;
 
+  if(!url)
+    url=opt.def_keyserver_url;
+
   if(url)
     build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url));
   else
   if(url)
     build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url));
   else
@@ -694,6 +730,55 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
 }
 
 int
 }
 
 int
+keygen_add_notations(PKT_signature *sig,void *opaque)
+{
+  struct notation *notation;
+
+  /* We always start clean */
+  delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION);
+  delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION);
+  sig->flags.notation=0;
+
+  for(notation=opaque;notation;notation=notation->next)
+    if(!notation->flags.ignore)
+      {
+       unsigned char *buf;
+       unsigned int n1,n2;
+
+       n1=strlen(notation->name);
+       if(notation->altvalue)
+         n2=strlen(notation->altvalue);
+       else if(notation->bdat)
+         n2=notation->blen;
+       else
+         n2=strlen(notation->value);
+
+       buf = xmalloc( 8 + n1 + n2 );
+
+       /* human readable or not */
+       buf[0] = notation->bdat?0:0x80;
+       buf[1] = buf[2] = buf[3] = 0;
+       buf[4] = n1 >> 8;
+       buf[5] = n1;
+       buf[6] = n2 >> 8;
+       buf[7] = n2;
+       memcpy(buf+8, notation->name, n1 );
+       if(notation->altvalue)
+         memcpy(buf+8+n1, notation->altvalue, n2 );
+       else if(notation->bdat)
+         memcpy(buf+8+n1, notation->bdat, n2 );
+       else
+         memcpy(buf+8+n1, notation->value, n2 );
+       build_sig_subpkt( sig, SIGSUBPKT_NOTATION |
+                         (notation->flags.critical?SIGSUBPKT_FLAG_CRITICAL:0),
+                         buf, 8+n1+n2 );
+       xfree(buf);
+      }
+
+  return 0;
+}
+
+int
 keygen_add_revkey(PKT_signature *sig, void *opaque)
 {
   struct revocation_key *revkey=opaque;
 keygen_add_revkey(PKT_signature *sig, void *opaque)
 {
   struct revocation_key *revkey=opaque;
@@ -715,29 +800,27 @@ keygen_add_revkey(PKT_signature *sig, void *opaque)
   return 0;
 }
 
   return 0;
 }
 
-static int
-make_backsig(PKT_signature *sig, PKT_public_key *pk,
-            PKT_public_key *sub_pk, PKT_secret_key *sub_sk)
+
+
+/* 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,
+              u32 timestamp)
 {
   PKT_signature *backsig;
   int rc;
 
 {
   PKT_signature *backsig;
   int rc;
 
-#ifndef DO_BACKSIGS
-  /* This is not enabled yet, as I want to get a bit closer to RFC day
-     before enabling this.  I've been burned before :) */
-
-  return 0;
-#endif
-
-  cache_public_key (sub_pk);
+  cache_public_key(sub_pk);
 
 
-  rc=make_keysig_packet(&backsig,pk,NULL,sub_pk,sub_sk, 0x19, 0, 0, 0, 0,
-                       NULL,NULL);
-  if( rc )
-    log_error("make_keysig_packet failed for backsig: %s\n", g10_errstr(rc) );
+  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
     {
   else
     {
-      /* get it into a binary packed form. */
+      /* Get it into a binary packed form. */
       IOBUF backsig_out=iobuf_temp();
       PACKET backsig_pkt;
  
       IOBUF backsig_out=iobuf_temp();
       PACKET backsig_pkt;
  
@@ -802,7 +885,7 @@ make_backsig(PKT_signature *sig, PKT_public_key *pk,
              buf+=mark;
            }
  
              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);
          build_sig_subpkt(sig,SIGSUBPKT_SIGNATURE,buf,pktlen);
 
          iobuf_close(backsig_out);
@@ -814,415 +897,643 @@ make_backsig(PKT_signature *sig, PKT_public_key *pk,
 
 
 static int
 
 
 static int
-write_direct_sigKBNODE root, KBNODE pub_root, PKT_secret_key *sk,
-                 struct revocation_key *revkey )
+write_direct_sig (KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
+                 struct revocation_key *revkey, u32 timestamp)
 {
 {
-    PACKET *pkt;
-    PKT_signature *sig;
-    int rc=0;
-    KBNODE node;
-    PKT_public_key *pk;
+  PACKET *pkt;
+  PKT_signature *sig;
+  int rc=0;
+  KBNODE node;
+  PKT_public_key *pk;
 
 
-    if( opt.verbose )
-       log_info(_("writing direct signature\n"));
+  if( opt.verbose )
+    log_info(_("writing direct signature\n"));
 
 
-    /* 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;
+  /* 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 */
-    cache_public_key (pk);
+  /* 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,
-                           keygen_add_revkey,revkey);
-    if( rc ) {
-       log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
-       return rc;
+  /* Make the signature.  */
+  rc = make_keysig_packet (&sig,pk,NULL,NULL,sk,0x1F,
+                           0, 0, timestamp, 0,
+                           keygen_add_revkey, revkey);
+  if( rc )
+    {
+      log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
+      return rc;
     }
     }
-
-    pkt = m_alloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = sig;
-    add_kbnode( root, new_kbnode( pkt ) );
-    return rc;
+  
+  pkt = xmalloc_clear( sizeof *pkt );
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = sig;
+  add_kbnode( root, new_kbnode( pkt ) );
+  return rc;
 }
 
 }
 
+
 static int
 static int
-write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
-               unsigned int use )
+write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
+               unsigned int use, u32 timestamp )
 {
 {
-    PACKET *pkt;
-    PKT_signature *sig;
-    PKT_user_id *uid;
-    int rc=0;
-    KBNODE node;
-    PKT_public_key *pk;
+  PACKET *pkt;
+  PKT_signature *sig;
+  PKT_user_id *uid;
+  int rc=0;
+  KBNODE node;
+  PKT_public_key *pk;
 
 
-    if( opt.verbose )
-       log_info(_("writing self signature\n"));
-
-    /* get the uid packet from the list */
-    node = find_kbnode( root, PKT_USER_ID );
-    if( !node )
-       BUG(); /* no user id packet in tree */
-    uid = node->pkt->pkt.user_id;
-    /* 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 */
-    cache_public_key (pk);
-
-    /* and make the signature */
-    rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
-                            keygen_add_std_prefs, pk );
-    if( rc ) {
-       log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
-       return rc;
-    }
-
-    pkt = m_alloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = sig;
-    add_kbnode( root, new_kbnode( pkt ) );
-    return rc;
+  if( opt.verbose )
+    log_info(_("writing self signature\n"));
+
+  /* Get the uid packet from the list. */
+  node = find_kbnode( pub_root, PKT_USER_ID );
+  if( !node )
+    BUG(); /* No user id packet in tree.  */
+  uid = node->pkt->pkt.user_id;
+
+  /* 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.  */
+  cache_public_key (pk);
+
+  /* Make the signature.  */
+  rc = make_keysig_packet (&sig, pk, uid, NULL, sk, 0x13,
+                           0, 0, timestamp, 0,
+                           keygen_add_std_prefs, pk);
+  if( rc ) 
+    {
+      log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
+      return rc;
+    }
+
+  pkt = xmalloc_clear( sizeof *pkt );
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = sig;
+  add_kbnode( sec_root, new_kbnode( pkt ) );
+
+  pkt = xmalloc_clear( sizeof *pkt );
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = copy_signature(NULL,sig);
+  add_kbnode( pub_root, new_kbnode( pkt ) );
+  return rc;
 }
 
 }
 
-/* sub_sk is currently unused (reserved for backsigs) */
+
+/* Write the key binding signature.  If TIMESTAMP is not NULL use the
+   signature creation times.  */
 static int
 static int
-write_keybindingKBNODE root, KBNODE pub_root,
+write_keybinding (KBNODE root, KBNODE pub_root,
                  PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
                  PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
-                  unsigned int use )
+                  unsigned int use, u32 timestamp)
 {
 {
-    PACKET *pkt;
-    PKT_signature *sig;
-    int rc=0;
-    KBNODE node;
-    PKT_public_key *pri_pk, *sub_pk;
-    struct opaque_data_usage_and_pk oduap;
-
-    if( opt.verbose )
-       log_info(_("writing key binding signature\n"));
-
-    /* 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 */
-    cache_public_key (pri_pk);
+  PACKET *pkt;
+  PKT_signature *sig;
+  int rc=0;
+  KBNODE node;
+  PKT_public_key *pri_pk, *sub_pk;
+  struct opaque_data_usage_and_pk oduap;
+
+  if ( opt.verbose )
+    log_info(_("writing key binding signature\n"));
+
+  /* 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.  */
+  cache_public_key (pri_pk);
  
  
-    /* find the last subkey */
-    sub_pk = NULL;
-    for(node=pub_root; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           sub_pk = node->pkt->pkt.public_key;
+  /* Find the last subkey. */
+  sub_pk = NULL;
+  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();
+  if (!sub_pk)
+    BUG();
 
 
-    /* and 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,
-                         keygen_add_key_flags_and_expire, &oduap );
-    if( rc ) {
-       log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
-       return rc;
+  /* 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, timestamp, 0,
+                           keygen_add_key_flags_and_expire, &oduap );
+  if (rc) 
+    {
+      log_error ("make_keysig_packet failed: %s\n", g10_errstr(rc) );
+      return rc;
     }
 
     }
 
-    /* make a backsig */
-    if(use&PUBKEY_USAGE_SIG)
-      {
-       rc=make_backsig(sig,pri_pk,sub_pk,sub_sk);
-       if(rc)
-         return rc;
-      }
-
-    pkt = m_alloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = sig;
-    add_kbnode( root, new_kbnode( pkt ) );
-    return rc;
+  /* Make a backsig.  */
+  if (use&PUBKEY_USAGE_SIG)
+    {
+      rc = make_backsig (sig, pri_pk, sub_pk, sub_sk, timestamp);
+      if (rc)
+        return rc;
+    }
+  
+  pkt = xmalloc_clear ( sizeof *pkt );
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = sig;
+  add_kbnode (root, new_kbnode (pkt) );
+  return rc;
 }
 
 
 }
 
 
+
 static int
 static int
-gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
-       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
+key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
+               const char *topname, const char *elems)
 {
 {
-    int rc;
-    int i;
-    PACKET *pkt;
-    PKT_secret_key *sk;
-    PKT_public_key *pk;
-    MPI skey[4];
-    MPI *factors;
-
-    assert( is_ELGAMAL(algo) );
-
-    if( nbits < 512 ) {
-       nbits = 1024;
-       log_info(_("keysize invalid; using %u bits\n"), nbits );
-    }
-
-    if( (nbits % 32) ) {
-       nbits = ((nbits + 31) / 32) * 32;
-       log_info(_("keysize rounded up to %u bits\n"), nbits );
-    }
-
-    rc = pubkey_generate( algo, nbits, skey, &factors );
-    if( rc ) {
-       log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
-       return rc;
-    }
-
-    sk = m_alloc_clear( sizeof *sk );
-    pk = m_alloc_clear( sizeof *pk );
-    sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = 4;
-    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];
-    sk->is_protected = 0;
-    sk->protect.algo = 0;
-
-    sk->csum = checksum_mpi( sk->skey[3] );
-    if( ret_sk ) /* return an unprotected version of the sk */
-       *ret_sk = copy_secret_key( NULL, sk );
-
-    if( dek ) {
-       sk->protect.algo = dek->algo;
-       sk->protect.s2k = *s2k;
-       rc = protect_secret_key( sk, dek );
-       if( rc ) {
-           log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
-           free_public_key(pk);
-           free_secret_key(sk);
-           return rc;
-       }
+  gcry_sexp_t list, l2;
+  const char *s;
+  int i, idx;
+  int rc = 0;
+
+  list = gcry_sexp_find_token (sexp, topname, 0);
+  if (!list)
+    return gpg_error (GPG_ERR_INV_OBJ);
+  l2 = gcry_sexp_cadr (list);
+  gcry_sexp_release (list);
+  list = l2;
+  if (!list)
+    return gpg_error (GPG_ERR_NO_OBJ);
+
+  for (idx=0,s=elems; *s; s++, idx++)
+    {
+      l2 = gcry_sexp_find_token (list, s, 1);
+      if (!l2)
+        {
+          rc = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */
+          goto leave;
+        }
+      array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+      gcry_sexp_release (l2);
+      if (!array[idx]) 
+        {
+          rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */
+          goto leave;
+        }
     }
     }
+  gcry_sexp_release (list);
 
 
-    pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
-    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) */
-    pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk;
-    add_kbnode(sec_root, new_kbnode( pkt ));
-    for(i=0; factors[i]; i++ )
-       add_kbnode( sec_root,
-                   make_mpi_comment_node("#:ELG_factor:", factors[i] ));
-
-    return 0;
+ leave:
+  if (rc)
+    {
+      for (i=0; i<idx; i++)
+        {
+          xfree (array[i]);
+          array[i] = NULL;
+        }
+      gcry_sexp_release (list);
+    }
+  return rc;
 }
 
 
 }
 
 
-/****************
- * Generate a DSA key
- */
 static int
 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)
+genhelp_protect (DEK *dek, STRING2KEY *s2k, PKT_secret_key *sk)
 {
 {
-    int rc;
-    int i;
-    PACKET *pkt;
-    PKT_secret_key *sk;
-    PKT_public_key *pk;
-    MPI skey[5];
-    MPI *factors;
-
-    if( nbits > 1024 || nbits < 512 ) {
-       nbits = 1024;
-       log_info(_("keysize invalid; using %u bits\n"), nbits );
-    }
-
-    if( (nbits % 64) ) {
-       nbits = ((nbits + 63) / 64) * 64;
-       log_info(_("keysize rounded up to %u bits\n"), nbits );
-    }
-
-    rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors );
-    if( rc ) {
-       log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
-       return rc;
-    }
-
-    sk = m_alloc_clear( sizeof *sk );
-    pk = m_alloc_clear( sizeof *pk );
-    sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = 4;
-    if( expireval ) {
-       sk->expiredate = pk->expiredate = sk->timestamp + expireval;
-    }
-    sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA;
-                      pk->pkey[0] = mpi_copy( skey[0] );
-                      pk->pkey[1] = mpi_copy( skey[1] );
-                      pk->pkey[2] = mpi_copy( skey[2] );
-                      pk->pkey[3] = mpi_copy( skey[3] );
-    sk->skey[0] = skey[0];
-    sk->skey[1] = skey[1];
-    sk->skey[2] = skey[2];
-    sk->skey[3] = skey[3];
-    sk->skey[4] = skey[4];
-    sk->is_protected = 0;
-    sk->protect.algo = 0;
-
-    sk->csum = checksum_mpi ( sk->skey[4] );
-    if( ret_sk ) /* return an unprotected version of the sk */
-       *ret_sk = copy_secret_key( NULL, sk );
-
-    if( dek ) {
-       sk->protect.algo = dek->algo;
-       sk->protect.s2k = *s2k;
-       rc = protect_secret_key( sk, dek );
-       if( rc ) {
-           log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
-           free_public_key(pk);
-           free_secret_key(sk);
-           return rc;
-       }
+  int rc = 0;
+
+  if (dek)
+    {
+      sk->protect.algo = dek->algo;
+      sk->protect.s2k = *s2k;
+      rc = protect_secret_key (sk, dek);
+      if (rc)
+        log_error ("protect_secret_key failed: %s\n", gpg_strerror (rc) );
     }
 
     }
 
-    pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
-    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)
-     * p = 2 * q * f1 * f2 * ... * fn
-     * We store only f1 to f_n-1;  fn can be calculated because p and q
-     * are known.
-     */
-    pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk;
-    add_kbnode(sec_root, new_kbnode( pkt ));
-    for(i=1; factors[i]; i++ ) /* the first one is q */
-       add_kbnode( sec_root,
-                   make_mpi_comment_node("#:DSA_factor:", factors[i] ));
+  return rc;
+}
 
 
-    return 0;
+static void
+genhelp_factors (gcry_sexp_t misc_key_info, KBNODE sec_root)
+{
+  (void)misc_key_info;
+  (void)sec_root;
+#if 0 /* Not used anymore */
+  size_t n;
+  char *buf;
+  
+  if (misc_key_info)
+    {
+      /* DSA: 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)
+         p = 2 * q * f1 * f2 * ... * fn
+         We store only f1 to f_n-1;  fn can be calculated because p and q
+         are known. */
+      n = gcry_sexp_sprint (misc_key_info, 0, NULL, 0);
+      buf = xmalloc (n+4);
+      strcpy (buf, "#::");
+      n = gcry_sexp_sprint (misc_key_info, 0, buf+3, n);
+      if (n)
+        {
+          n += 3;
+          add_kbnode (sec_root, make_comment_node_from_buffer (buf, n));
+        }
+      xfree (buf);
+      gcry_sexp_release (misc_key_info);
+    }
+#endif
 }
 
 
 }
 
 
-/* 
- * Generate an RSA key.
- */
+/* Generate an Elgamal encryption key pair. TIMESTAMP is the creatuion
+   time to be put into the key structure.  */
 static int
 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)
+gen_elg (int algo, unsigned int nbits,
+         KBNODE pub_root, KBNODE sec_root, DEK *dek,
+         STRING2KEY *s2k, PKT_secret_key **ret_sk, 
+         u32 timestamp, u32 expireval, int is_subkey)
 {
 {
-    int rc;
-    PACKET *pkt;
-    PKT_secret_key *sk;
-    PKT_public_key *pk;
-    MPI skey[6];
-    MPI *factors;
-
-    assert( is_RSA(algo) );
-
-    if( nbits < 1024 ) {
-       nbits = 1024;
-       log_info(_("keysize invalid; using %u bits\n"), nbits );
-    }
-
-    if( (nbits % 32) ) {
-       nbits = ((nbits + 31) / 32) * 32;
-       log_info(_("keysize rounded up to %u bits\n"), nbits );
-    }
-
-    rc = pubkey_generate( algo, nbits, skey, &factors );
-    if( rc ) {
-       log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
-       return rc;
-    }
-
-    sk = m_alloc_clear( sizeof *sk );
-    pk = m_alloc_clear( sizeof *pk );
-    sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = 4;
-    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] );
-    sk->skey[0] = skey[0];
-    sk->skey[1] = skey[1];
-    sk->skey[2] = skey[2];
-    sk->skey[3] = skey[3];
-    sk->skey[4] = skey[4];
-    sk->skey[5] = skey[5];
-    sk->is_protected = 0;
-    sk->protect.algo = 0;
-
-    sk->csum  = checksum_mpi (sk->skey[2] );
-    sk->csum += checksum_mpi (sk->skey[3] );
-    sk->csum += checksum_mpi (sk->skey[4] );
-    sk->csum += checksum_mpi (sk->skey[5] );
-    if( ret_sk ) /* return an unprotected version of the sk */
-       *ret_sk = copy_secret_key( NULL, sk );
-
-    if( dek ) {
-       sk->protect.algo = dek->algo;
-       sk->protect.s2k = *s2k;
-       rc = protect_secret_key( sk, dek );
-       if( rc ) {
-           log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
-           free_public_key(pk);
-           free_secret_key(sk);
-           return rc;
-       }
+  int rc;
+  PACKET *pkt;
+  PKT_secret_key *sk;
+  PKT_public_key *pk;
+  gcry_sexp_t s_parms, s_key;
+  gcry_sexp_t misc_key_info;
+  
+  assert( is_ELGAMAL(algo) );
+
+  if (nbits < 512)
+    {
+      nbits = 1024;
+      log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
     }
 
-    pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
-    pkt->pkt.public_key = pk;
-    add_kbnode(pub_root, new_kbnode( pkt ));
+  if ((nbits % 32))
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      log_info (_("keysize rounded up to %u bits\n"), nbits );
+    }
 
 
-    pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk;
-    add_kbnode(sec_root, new_kbnode( pkt ));
 
 
-    return 0;
+  rc = gcry_sexp_build ( &s_parms, NULL,
+                         "(genkey(%s(nbits %d)))",
+                         algo == GCRY_PK_ELG_E ? "openpgp-elg" :
+                         algo == GCRY_PK_ELG    ? "elg" : "x-oops" ,
+                         (int)nbits);
+  if (rc)
+    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
+  
+  rc = gcry_pk_genkey (&s_key, s_parms);
+  gcry_sexp_release (s_parms);
+  if (rc)
+    {
+      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
+      return rc;
+    }
+  
+  sk = xmalloc_clear( sizeof *sk );
+  pk = xmalloc_clear( sizeof *pk );
+  sk->timestamp = pk->timestamp = timestamp;
+  sk->version = pk->version = 4;
+  if (expireval) 
+    {
+      sk->expiredate = pk->expiredate = sk->timestamp + expireval;
+    }
+  sk->pubkey_algo = pk->pubkey_algo = algo;
+
+  rc = key_from_sexp (pk->pkey, s_key, "public-key", "pgy");
+  if (rc) 
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      gcry_sexp_release (s_key);
+      free_secret_key (sk);
+      free_public_key (pk);
+      return rc;
+    }
+  rc = key_from_sexp (sk->skey, s_key, "private-key", "pgyx");
+  if (rc)
+    {
+      log_error("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      gcry_sexp_release (s_key);
+      free_secret_key (sk);
+      free_public_key (pk);
+      return rc;
+    }
+  misc_key_info = gcry_sexp_find_token (s_key, "misc-key-info", 0);
+  gcry_sexp_release (s_key);
+  
+  sk->is_protected = 0;
+  sk->protect.algo = 0;
+
+  sk->csum = checksum_mpi (sk->skey[3]);
+  if (ret_sk) /* Return an unprotected version of the sk.  */
+    *ret_sk = copy_secret_key ( NULL, sk );
+
+  rc = genhelp_protect (dek, s2k, sk);
+  if (rc)
+    {
+      free_public_key (pk);
+      free_secret_key (sk);
+      gcry_sexp_release (misc_key_info);
+      return rc;
+    }
+  
+  pkt = xmalloc_clear (sizeof *pkt);
+  pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
+  pkt->pkt.public_key = pk;
+  add_kbnode (pub_root, new_kbnode( pkt ));
+
+  /* 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;
+  add_kbnode (sec_root, new_kbnode( pkt ));
+  
+  genhelp_factors (misc_key_info, sec_root);
+  
+  return 0;
 }
 
 
 /****************
 }
 
 
 /****************
- * check valid days:
- * return 0 on error or the multiplier
+ * Generate a DSA key
  */
 static int
  */
 static int
-check_valid_days( const char *s )
+gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+         STRING2KEY *s2k, PKT_secret_key **ret_sk, 
+         u32 timestamp, u32 expireval, int is_subkey)
 {
 {
-    if( !digitp(s) )
-       return 0;
-    for( s++; *s; s++)
-       if( !digitp(s) )
+  int rc;
+  PACKET *pkt;
+  PKT_secret_key *sk;
+  PKT_public_key *pk;
+  gcry_sexp_t s_parms, s_key;
+  gcry_sexp_t misc_key_info;
+  unsigned int qbits;
+
+  if ( nbits < 512) 
+    {
+      nbits = 1024;
+      log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
+  else if ( nbits > 3072 )
+    {
+      nbits = 3072;
+      log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
+
+  if( (nbits % 64) )
+    {
+      nbits = ((nbits + 63) / 64) * 64;
+      log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
+
+  /* To comply with FIPS rules we round up to the next value unless in
+     expert mode.  */
+  if (!opt.expert && nbits > 1024 && (nbits % 1024))
+    {
+      nbits = ((nbits + 1023) / 1024) * 1024;
+      log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
+
+  /*
+    Figure out a q size based on the key size.  FIPS 180-3 says:
+    L = 1024, N = 160
+    L = 2048, N = 224
+    L = 2048, N = 256
+    L = 3072, N = 256
+    2048/256 is an odd pair since there is also a 2048/224 and
+    3072/256.  Matching sizes is not a very exact science.
+      
+    We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024
+    but less than 2048, and 160 for 1024 (DSA1).
+  */
+  if (nbits > 2047)
+    qbits = 256;
+  else if ( nbits > 1024)
+    qbits = 224;
+  else
+    qbits = 160;
+  if (qbits != 160 )
+    log_info (_("WARNING: some OpenPGP programs can't"
+                " handle a DSA key with this digest size\n"));
+
+  rc = gcry_sexp_build (&s_parms, NULL,
+                        "(genkey(dsa(nbits %d)(qbits %d)))",
+                        (int)nbits, (int)qbits);
+  if (rc)
+    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
+  
+  rc = gcry_pk_genkey (&s_key, s_parms);
+  gcry_sexp_release (s_parms);
+  if (rc)
+    {
+      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
+      return rc;
+    }
+
+  sk = xmalloc_clear( sizeof *sk );
+  pk = xmalloc_clear( sizeof *pk );
+  sk->timestamp = pk->timestamp = timestamp;
+  sk->version = pk->version = 4;
+  if (expireval) 
+    sk->expiredate = pk->expiredate = sk->timestamp + expireval;
+  sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA;
+
+  rc = key_from_sexp (pk->pkey, s_key, "public-key", "pqgy");
+  if (rc) 
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc));
+      gcry_sexp_release (s_key);
+      free_public_key(pk);
+      free_secret_key(sk);
+      return rc;
+    }
+  rc = key_from_sexp (sk->skey, s_key, "private-key", "pqgyx");
+  if (rc) 
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      gcry_sexp_release (s_key);
+      free_public_key(pk);
+      free_secret_key(sk);
+      return rc;
+    }
+  misc_key_info = gcry_sexp_find_token (s_key, "misc-key-info", 0);
+  gcry_sexp_release (s_key);
+  
+  sk->is_protected = 0;
+  sk->protect.algo = 0;
+
+  sk->csum = checksum_mpi ( sk->skey[4] );
+  if( ret_sk ) /* return an unprotected version of the sk */
+    *ret_sk = copy_secret_key( NULL, sk );
+
+  rc = genhelp_protect (dek, s2k, sk);
+  if (rc)
+    {
+      free_public_key (pk);
+      free_secret_key (sk);
+      gcry_sexp_release (misc_key_info);
+      return rc;
+    }
+
+  pkt = xmalloc_clear(sizeof *pkt);
+  pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
+  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)
+   * p = 2 * q * f1 * f2 * ... * fn
+   * We store only f1 to f_n-1;  fn can be calculated because p and q
+   * are known.
+   */
+  pkt = xmalloc_clear(sizeof *pkt);
+  pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
+  pkt->pkt.secret_key = sk;
+  add_kbnode(sec_root, new_kbnode( pkt ));
+
+  genhelp_factors (misc_key_info, sec_root);
+
+  return 0;
+}
+
+
+/* 
+ * Generate an RSA key.
+ */
+static int
+gen_rsa (int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+         STRING2KEY *s2k, PKT_secret_key **ret_sk,
+         u32 timestamp, u32 expireval, int is_subkey)
+{
+  int rc;
+  PACKET *pkt;
+  PKT_secret_key *sk;
+  PKT_public_key *pk;
+  gcry_sexp_t s_parms, s_key;
+
+  assert (is_RSA(algo));
+
+  if (!nbits)
+    nbits = DEFAULT_STD_KEYSIZE;
+
+  if (nbits < 1024) 
+    {
+      nbits = 1024;
+      log_info (_("keysize invalid; using %u bits\n"), nbits );
+    }
+  
+  if ((nbits % 32))
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      log_info (_("keysize rounded up to %u bits\n"), nbits );
+    }
+
+  rc = gcry_sexp_build (&s_parms, NULL,
+                        "(genkey(rsa(nbits %d)))",
+                        (int)nbits);
+  if (rc)
+    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
+  
+  rc = gcry_pk_genkey (&s_key, s_parms);
+  gcry_sexp_release (s_parms);
+  if (rc)
+    {
+      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
+      return rc;
+    }
+
+  sk = xmalloc_clear( sizeof *sk );
+  pk = xmalloc_clear( sizeof *pk );
+  sk->timestamp = pk->timestamp = timestamp;
+  sk->version = pk->version = 4;
+  if (expireval)
+    {
+      sk->expiredate = pk->expiredate = sk->timestamp + expireval;
+    }
+  sk->pubkey_algo = pk->pubkey_algo = algo;
+
+  rc = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
+  if (rc) 
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc));
+      gcry_sexp_release (s_key);
+      free_public_key(pk);
+      free_secret_key(sk);
+      return rc;
+    }
+  rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
+  if (rc) 
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      gcry_sexp_release (s_key);
+      free_public_key(pk);
+      free_secret_key(sk);
+      return rc;
+    }
+  gcry_sexp_release (s_key);
+
+  sk->is_protected = 0;
+  sk->protect.algo = 0;
+
+  sk->csum  = checksum_mpi (sk->skey[2] );
+  sk->csum += checksum_mpi (sk->skey[3] );
+  sk->csum += checksum_mpi (sk->skey[4] );
+  sk->csum += checksum_mpi (sk->skey[5] );
+  if( ret_sk ) /* return an unprotected version of the sk */
+    *ret_sk = copy_secret_key( NULL, sk );
+
+  rc = genhelp_protect (dek, s2k, sk);
+  if (rc)
+    {
+      free_public_key (pk);
+      free_secret_key (sk);
+      return rc;
+    }
+
+  pkt = xmalloc_clear(sizeof *pkt);
+  pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
+  pkt->pkt.public_key = pk;
+  add_kbnode(pub_root, new_kbnode( pkt ));
+
+  pkt = xmalloc_clear(sizeof *pkt);
+  pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
+  pkt->pkt.secret_key = sk;
+  add_kbnode(sec_root, new_kbnode( pkt ));
+
+  return 0;
+}
+
+
+/****************
+ * check valid days:
+ * return 0 on error or the multiplier
+ */
+static int
+check_valid_days( const char *s )
+{
+    if( !digitp(s) )
+       return 0;
+    for( s++; *s; s++)
+       if( !digitp(s) )
            break;
     if( !*s )
        return 1;
            break;
     if( !*s )
        return 1;
@@ -1246,6 +1557,9 @@ print_key_flags(int flags)
   if(flags&PUBKEY_USAGE_SIG)
     tty_printf("%s ",_("Sign"));
 
   if(flags&PUBKEY_USAGE_SIG)
     tty_printf("%s ",_("Sign"));
 
+  if(flags&PUBKEY_USAGE_CERT)
+    tty_printf("%s ",_("Certify"));
+
   if(flags&PUBKEY_USAGE_ENC)
     tty_printf("%s ",_("Encrypt"));
 
   if(flags&PUBKEY_USAGE_ENC)
     tty_printf("%s ",_("Encrypt"));
 
@@ -1256,15 +1570,33 @@ print_key_flags(int flags)
 
 /* Returns the key flags */
 static unsigned int
 
 /* Returns the key flags */
 static unsigned int
-ask_key_flags(int algo)
+ask_key_flags(int algo,int subkey)
 {
 {
+  /* TRANSLATORS: Please use only plain ASCII characters for the
+     translation.  If this is not possible use single digits.  The
+     string needs to 8 bytes long. Here is a description of the
+     functions:
+
+       s = Toggle signing capability
+       e = Toggle encryption capability
+       a = Toggle authentication capability
+       q = Finish
+  */
   const char *togglers=_("SsEeAaQq");
   char *answer=NULL;
   unsigned int current=0;
   unsigned int possible=openpgp_pk_algo_usage(algo);
 
   const char *togglers=_("SsEeAaQq");
   char *answer=NULL;
   unsigned int current=0;
   unsigned int possible=openpgp_pk_algo_usage(algo);
 
-  if(strlen(togglers)!=8)
-    BUG();
+  if ( strlen(togglers) != 8 )
+    {
+      tty_printf ("NOTE: Bad translation at %s:%d. "
+                  "Please report.\n", __FILE__, __LINE__);
+      togglers = "11223300";
+    }
+
+  /* Only primary keys may certify. */
+  if(subkey)
+    possible&=~PUBKEY_USAGE_CERT;
 
   /* Preload the current set with the possible set, minus
      authentication, since nobody really uses auth yet. */
 
   /* Preload the current set with the possible set, minus
      authentication, since nobody really uses auth yet. */
@@ -1274,7 +1606,7 @@ ask_key_flags(int algo)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
-                pubkey_algo_to_string(algo));
+                gcry_pk_algo_name (algo));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
@@ -1294,12 +1626,12 @@ ask_key_flags(int algo)
       tty_printf(_("   (%c) Finished\n"),togglers[6]);
       tty_printf("\n");
 
       tty_printf(_("   (%c) Finished\n"),togglers[6]);
       tty_printf("\n");
 
-      m_free(answer);
+      xfree(answer);
       answer = cpr_get("keygen.flags",_("Your selection? "));
       cpr_kill_prompt();
 
       if(strlen(answer)>1)
       answer = cpr_get("keygen.flags",_("Your selection? "));
       cpr_kill_prompt();
 
       if(strlen(answer)>1)
-       continue;
+       tty_printf(_("Invalid selection.\n"));
       else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7])
        break;
       else if((*answer==togglers[0] || *answer==togglers[1])
       else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7])
        break;
       else if((*answer==togglers[0] || *answer==togglers[1])
@@ -1326,109 +1658,150 @@ ask_key_flags(int algo)
          else
            current|=PUBKEY_USAGE_AUTH;
        }
          else
            current|=PUBKEY_USAGE_AUTH;
        }
+      else
+       tty_printf(_("Invalid selection.\n"));
     }
 
     }
 
-  m_free(answer);
+  xfree(answer);
 
   return current;
 }
 
 
 
   return current;
 }
 
 
-/****************
- * Returns: 0 to create both a DSA and a Elgamal key.
- *          and only if key flags are to be written the desired usage.
- */
+/* Ask for an algorithm.  The function returns the algorithm id to
+ * create. If ADDMODE is false the function won't show an option to
+ * create the primary and subkey combined and won't set R_USAGE
+ * either.  If a combined algorithm has been selected, the subkey
+ * algorithm is stored at R_SUBKEY_ALGO.  */
 static int
 static int
-ask_algo (int addmode, unsigned int *r_usage)
+ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage)
 {
 {
-    char *answer;
-    int algo;
-
-    *r_usage = 0;
-    tty_printf(_("Please select what kind of key you want:\n"));
-    if( !addmode )
-       tty_printf(_("   (%d) DSA and Elgamal (default)\n"), 1 );
-    tty_printf(    _("   (%d) DSA (sign only)\n"), 2 );
-    if (opt.expert)
-      tty_printf(  _("   (%d) DSA (set your own capabilities)\n"), 3 );
-    if( addmode )
-       tty_printf(_("   (%d) Elgamal (encrypt only)\n"), 4 );
-    tty_printf(    _("   (%d) RSA (sign only)\n"), 5 );
-    if (addmode)
-        tty_printf(_("   (%d) RSA (encrypt only)\n"), 6 );
-    if (opt.expert)
-      tty_printf(  _("   (%d) RSA (set your own capabilities)\n"), 7 );
+  char *answer;
+  int algo;
+  int dummy_algo;
 
 
-    for(;;) {
-       answer = cpr_get("keygen.algo",_("Your selection? "));
-       cpr_kill_prompt();
-       algo = *answer? atoi(answer): 1;
-       m_free(answer);
-       if( algo == 1 && !addmode ) {
-           algo = 0;   /* create both keys */
-           break;
+  if (!r_subkey_algo)
+    r_subkey_algo = &dummy_algo;
+  
+  tty_printf (_("Please select what kind of key you want:\n"));
+
+  if (!addmode)
+    tty_printf (_("   (%d) RSA and RSA (default)\n"), 1 );
+  if (!addmode)
+    tty_printf (_("   (%d) DSA and Elgamal\n"), 2 );
+
+  tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
+  tty_printf (_("   (%d) RSA (sign only)\n"), 4 );
+
+  if (addmode)
+    {
+      tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
+      tty_printf (_("   (%d) RSA (encrypt only)\n"), 6 );
+    }
+  if (opt.expert)
+    {
+      tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
+      tty_printf (_("   (%d) RSA (set your own capabilities)\n"), 8 );
+    }
+  
+  for(;;)
+    {
+      *r_usage = 0;
+      *r_subkey_algo = 0;
+      answer = cpr_get ("keygen.algo", _("Your selection? "));
+      cpr_kill_prompt ();
+      algo = *answer? atoi (answer) : 1;
+      xfree(answer);
+      if (algo == 1 && !addmode)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_subkey_algo = PUBKEY_ALGO_RSA;
+          break;
        }
        }
-       else if( algo == 7 && opt.expert ) {
-           algo = PUBKEY_ALGO_RSA;
-           *r_usage=ask_key_flags(algo);
-           break;
+      else if (algo == 2 && !addmode)
+        {
+          algo = PUBKEY_ALGO_DSA;
+          *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E;
+          break;
        }
        }
-       else if( algo == 6 && addmode ) {
-           algo = PUBKEY_ALGO_RSA;
-            *r_usage = PUBKEY_USAGE_ENC;
-           break;
+      else if (algo == 3)
+        {
+          algo = PUBKEY_ALGO_DSA;
+          *r_usage = PUBKEY_USAGE_SIG;
+          break;
        }
        }
-       else if( algo == 5 ) {
-           algo = PUBKEY_ALGO_RSA;
-            *r_usage = PUBKEY_USAGE_SIG;
-           break;
+      else if (algo == 4)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_usage = PUBKEY_USAGE_SIG;
+          break;
        }
        }
-       else if( algo == 4 && addmode ) {
-           algo = PUBKEY_ALGO_ELGAMAL_E;
-            *r_usage = PUBKEY_USAGE_ENC;
-           break;
+      else if (algo == 5 && addmode)
+        {
+          algo = PUBKEY_ALGO_ELGAMAL_E;
+          *r_usage = PUBKEY_USAGE_ENC;
+          break;
        }
        }
-       else if( algo == 3 && opt.expert ) {
-           algo = PUBKEY_ALGO_DSA;
-           *r_usage=ask_key_flags(algo);
-           break;
+      else if (algo == 6 && addmode)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_usage = PUBKEY_USAGE_ENC;
+          break;
        }
        }
-       else if( algo == 2 ) {
-           algo = PUBKEY_ALGO_DSA;
-            *r_usage = PUBKEY_USAGE_SIG;
-           break;
+      else if (algo == 7 && opt.expert)
+        {
+          algo = PUBKEY_ALGO_DSA;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
        }
        }
-       else
-           tty_printf(_("Invalid selection.\n"));
+      else if (algo == 8 && opt.expert)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
+       }
+      else
+        tty_printf (_("Invalid selection.\n"));
     }
     }
-
-    return algo;
+  
+  return algo;
 }
 
 
 }
 
 
+/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
+   is not 0, the function asks for the size of the encryption
+   subkey. */
 static unsigned
 static unsigned
-ask_keysize( int algo )
+ask_keysize (int algo, unsigned int primary_keysize)
 {
 {
-  unsigned nbits,min,def=2048,max=4096;
+  unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096;
+  int for_subkey = !!primary_keysize;
+  int autocomp = 0;
 
   if(opt.expert)
     min=512;
   else
     min=1024;
 
 
   if(opt.expert)
     min=512;
   else
     min=1024;
 
+  if (primary_keysize && !opt.expert)
+    {
+      /* Deduce the subkey size from the primary key size.  */
+      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
+        nbits = 3072; /* For performance reasons we don't support more
+                         than 3072 bit DSA.  However we won't see this
+                         case anyway because DSA can't be used as an
+                         encryption subkey ;-). */
+      else
+        nbits = primary_keysize;
+      autocomp = 1;
+      goto leave;
+    }
+
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      if(opt.expert)
-       {
-         def=1024;
-         max=1024;
-       }
-      else
-       {
-         tty_printf(_("DSA keypair will have %u bits.\n"),1024);
-         return 1024;
-       }
+      def=2048;
+      max=3072;
       break;
 
     case PUBKEY_ALGO_RSA:
       break;
 
     case PUBKEY_ALGO_RSA:
@@ -1437,43 +1810,44 @@ ask_keysize( int algo )
     }
 
   tty_printf(_("%s keys may be between %u and %u bits long.\n"),
     }
 
   tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-            pubkey_algo_to_string(algo),min,max);
+            gcry_pk_algo_name (algo), min, max);
 
   for(;;)
     {
 
   for(;;)
     {
-      char *prompt,*answer;
+      char *prompt, *answer;
 
 
-#define PROMPTSTRING _("What keysize do you want? (%u) ")
-
-      prompt=m_alloc(strlen(PROMPTSTRING)+20);
-      sprintf(prompt,PROMPTSTRING,def);
-
-#undef PROMPTSTRING
-
-      answer = cpr_get("keygen.size",prompt);
-      cpr_kill_prompt();
-      nbits = *answer? atoi(answer): def;
-      m_free(prompt);
-      m_free(answer);
+      if (for_subkey)
+        prompt = xasprintf (_("What keysize do you want "
+                              "for the subkey? (%u) "), def);
+      else
+        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
+      answer = cpr_get ("keygen.size", prompt);
+      cpr_kill_prompt ();
+      nbits = *answer? atoi (answer): def;
+      xfree(prompt);
+      xfree(answer);
       
       if(nbits<min || nbits>max)
        tty_printf(_("%s keysizes must be in the range %u-%u\n"),
       
       if(nbits<min || nbits>max)
        tty_printf(_("%s keysizes must be in the range %u-%u\n"),
-                  pubkey_algo_to_string(algo),min,max);
+                  gcry_pk_algo_name (algo), min, max);
       else
        break;
     }
 
   tty_printf(_("Requested keysize is %u bits\n"), nbits );
 
       else
        break;
     }
 
   tty_printf(_("Requested keysize is %u bits\n"), nbits );
 
+ leave:
   if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
     {
       nbits = ((nbits + 63) / 64) * 64;
   if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
     {
       nbits = ((nbits + 63) / 64) * 64;
-      tty_printf(_("rounded up to %u bits\n"), nbits );
+      if (!autocomp)
+        tty_printf(_("rounded up to %u bits\n"), nbits );
     }
   else if( (nbits % 32) )
     {
       nbits = ((nbits + 31) / 32) * 32;
     }
   else if( (nbits % 32) )
     {
       nbits = ((nbits + 31) / 32) * 32;
-      tty_printf(_("rounded up to %u bits\n"), nbits );
+      if (!autocomp)
+        tty_printf(_("rounded up to %u bits\n"), nbits );
     }
 
   return nbits;
     }
 
   return nbits;
@@ -1481,50 +1855,73 @@ ask_keysize( int algo )
 
 
 /****************
 
 
 /****************
- * Parse an expire string and return it's value in days.
- * Returns -1 on error.
+ * Parse an expire string and return its value in seconds.
+ * Returns (u32)-1 on error.
+ * This isn't perfect since scan_isodatestr returns unix time, and
+ * OpenPGP actually allows a 32-bit time *plus* a 32-bit offset.
+ * Because of this, we only permit setting expirations up to 2106, but
+ * OpenPGP could theoretically allow up to 2242.  I think we'll all
+ * just cope for the next few years until we get a 64-bit time_t or
+ * similar.
  */
  */
-static int
+u32
 parse_expire_string( const char *string )
 {
 parse_expire_string( const char *string )
 {
-    int mult;
-    u32 abs_date=0;
-    u32 curtime = make_timestamp();
-    int valid_days;
-
-    if( !*string )
-       valid_days = 0;
-    else if( (abs_date = scan_isodatestr(string)) && abs_date > curtime ) {
-       /* This calculation is not perfectly okay because we
-        * are later going to simply multiply by 86400 and don't
-        * correct for leapseconds.  A solution would be to change
-        * the whole implemenation to work with dates and not intervals
-        * which are required for v3 keys.
-        */
-       valid_days = abs_date/86400-curtime/86400+1;
-    }
-    else if( (mult=check_valid_days(string)) ) {
-       valid_days = atoi(string) * mult;
-       if( valid_days < 0 || valid_days > 39447 )
-           valid_days = 0;
-    }
-    else {
-       valid_days = -1;
+  int mult;
+  u32 seconds;
+  u32 abs_date = 0;
+  u32 curtime = make_timestamp ();
+  time_t tt;
+  
+  if (!*string)
+    seconds = 0;
+  else if (!strncmp (string, "seconds=", 8))
+    seconds = atoi (string+8);
+  else if ((abs_date = scan_isodatestr(string))
+           && (abs_date+86400/2) > curtime)
+    seconds = (abs_date+86400/2) - curtime;
+  else if ((tt = isotime2epoch (string)) != (time_t)(-1))
+    seconds = (u32)tt - curtime;
+  else if ((mult = check_valid_days (string)))
+    seconds = atoi (string) * 86400L * mult;
+  else
+    seconds = (u32)(-1);
+  
+  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 valid_days;
+  return seconds;
 }
 
 }
 
+
 /* object == 0 for a key, and 1 for a sig */
 u32
 /* object == 0 for a key, and 1 for a sig */
 u32
-ask_expire_interval(int object)
+ask_expire_interval(int object,const char *def_expire)
 {
 {
+    u32 interval;
     char *answer;
     char *answer;
-    int valid_days=0;
-    u32 interval = 0;
 
     switch(object)
       {
       case 0:
 
     switch(object)
       {
       case 0:
+       if(def_expire)
+         BUG();
        tty_printf(_("Please specify how long the key should be valid.\n"
                     "         0 = key does not expire\n"
                     "      <n>  = key expires in n days\n"
        tty_printf(_("Please specify how long the key should be valid.\n"
                     "         0 = key does not expire\n"
                     "      <n>  = key expires in n days\n"
@@ -1534,6 +1931,8 @@ ask_expire_interval(int object)
        break;
 
       case 1:
        break;
 
       case 1:
+       if(!def_expire)
+         BUG();
        tty_printf(_("Please specify how long the signature should be valid.\n"
                     "         0 = signature does not expire\n"
                     "      <n>  = signature expires in n days\n"
        tty_printf(_("Please specify how long the signature should be valid.\n"
                     "         0 = signature does not expire\n"
                     "      <n>  = signature expires in n days\n"
@@ -1551,88 +1950,142 @@ ask_expire_interval(int object)
      * date */
 
     answer = NULL;
      * date */
 
     answer = NULL;
-    for(;;) {
+    for(;;)
+      {
        u32 curtime=make_timestamp();
 
        u32 curtime=make_timestamp();
 
-       m_free(answer);
+       xfree(answer);
        if(object==0)
          answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
        else
        if(object==0)
          answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
        else
-         answer = cpr_get("siggen.valid",_("Signature is valid for? (0) "));
+         {
+           char *prompt;
+
+#define PROMPTSTRING _("Signature is valid for? (%s) ")
+           /* This will actually end up larger than necessary because
+              of the 2 bytes for '%s' */
+           prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1);
+           sprintf(prompt,PROMPTSTRING,def_expire);
+#undef PROMPTSTRING
+
+           answer = cpr_get("siggen.valid",prompt);
+           xfree(prompt);
+
+           if(*answer=='\0')
+             answer=xstrdup(def_expire);
+         }
        cpr_kill_prompt();
        trim_spaces(answer);
        cpr_kill_prompt();
        trim_spaces(answer);
-       valid_days = parse_expire_string( answer );
-       if( valid_days < 0 ) {
+       interval = parse_expire_string( answer );
+       if( interval == (u32)-1 )
+         {
            tty_printf(_("invalid value\n"));
            continue;
            tty_printf(_("invalid value\n"));
            continue;
-       }
+         }
 
 
-       if( !valid_days ) {
-           tty_printf(_("%s does not expire at all\n"),
-                      object==0?"Key":"Signature");
-           interval = 0;
-       }
-       else {
-           interval = valid_days * 86400L;
-           /* print the date when the key expires */
-           tty_printf(_("%s expires at %s\n"),
-                       object==0?"Key":"Signature",
-                       asctimestamp((ulong)(curtime + interval) ) );
-            /* FIXME: This check yields warning on alhas:
-               write a configure check and to this check here only for 32 bit machines */
-           if( (time_t)((ulong)(curtime+interval)) < 0 )
-               tty_printf(_("Your system can't display dates beyond 2038.\n"
-                   "However, it will be correctly handled up to 2106.\n"));
-       }
+       if( !interval )
+         {
+            tty_printf((object==0)
+                       ? _("Key does not expire at all\n")
+                       : _("Signature does not expire at all\n"));
+         }
+       else
+         {
+           tty_printf(object==0
+                      ? _("Key expires at %s\n")
+                      : _("Signature expires at %s\n"),
+                      asctimestamp((ulong)(curtime + interval) ) );
+#if SIZEOF_TIME_T <= 4
+           if ( (time_t)((ulong)(curtime+interval)) < 0 )
+             tty_printf (_("Your system can't display dates beyond 2038.\n"
+                            "However, it will be correctly handled up to"
+                            " 2106.\n"));
+            else
+#endif /*SIZEOF_TIME_T*/
+              if ( (time_t)((unsigned long)(curtime+interval)) < curtime )
+                {
+                  tty_printf (_("invalid value\n"));
+                  continue;
+                }
+         }
 
        if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay",
 
        if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay",
-                                           _("Is this correct? (y/N) ")) )
-           break;
-    }
-    m_free(answer);
+                                                  _("Is this correct? (y/N) ")) )
+         break;
+      }
+
+    xfree(answer);
     return interval;
 }
 
 u32
 ask_expiredate()
 {
     return interval;
 }
 
 u32
 ask_expiredate()
 {
-    u32 x = ask_expire_interval(0);
+    u32 x = ask_expire_interval(0,NULL);
     return x? make_timestamp() + x : 0;
 }
 
     return x? make_timestamp() + x : 0;
 }
 
-static int
-has_invalid_email_chars( const char *s )
+
+
+static PKT_user_id *
+uid_from_string (const char *string)
 {
 {
-    int at_seen=0;
-    static char valid_chars[] = "01234567890_-."
-                               "abcdefghijklmnopqrstuvwxyz"
-                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-    for( ; *s; s++ ) {
-       if( *s & 0x80 )
-           return 1;
-       if( *s == '@' )
-           at_seen=1;
-       else if( !at_seen && !( !!strchr( valid_chars, *s ) || *s == '+' ) )
-           return 1;
-       else if( at_seen && !strchr( valid_chars, *s ) )
-           return 1;
-    }
-    return 0;
+  size_t n;
+  PKT_user_id *uid;
+
+  n = strlen (string);
+  uid = xmalloc_clear (sizeof *uid + n);
+  uid->len = n;
+  strcpy (uid->name, string);
+  uid->ref = 1;
+  return uid;
 }
 
 
 }
 
 
+/* Ask for a user ID.  With a MODE of 1 an extra help prompt is
+   printed for use during a new key creation.  If KEYBLOCK is not NULL
+   the function prevents the creation of an already existing user
+   ID.  */
 static char *
 static char *
-ask_user_id( int mode )
+ask_user_id (int mode, KBNODE keyblock)
 {
     char *answer;
     char *aname, *acomment, *amail, *uid;
 
 {
     char *answer;
     char *aname, *acomment, *amail, *uid;
 
-    if( !mode )
-       tty_printf( _("\n"
-"You need a user ID to identify your key; the software constructs the user ID\n"
+    if ( !mode )
+      {
+        /* TRANSLATORS: This is the new string telling the user what
+           gpg is now going to do (i.e. ask for the parts of the user
+           ID).  Note that if you do not tyranslated this string, a
+           different string will be used used, which might still have
+           a correct transaltion.  */
+       const char *s1 =
+          N_("\n"
+             "GnuPG needs to construct a user ID to identify your key.\n"
+             "\n");
+        const char *s2 = _(s1);
+
+        if (!strcmp (s1, s2))
+          {
+            /* There is no translation for the string thus we to use
+               the old info text.  gettext has no way to tell whether
+               a translation is actually available, thus we need to
+               to compare again. */
+            /* TRANSLATORS: This string is in general not anymore used
+               but you should keep your existing translation.  In case
+               the new string is not translated this old string will
+               be used. */
+            const char *s3 = N_("\n"
+"You need a user ID to identify your key; "
+                                        "the software constructs the user ID\n"
 "from the Real Name, Comment and Email Address in this form:\n"
 "from the Real Name, Comment and Email Address in this form:\n"
-"    \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
+"    \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n");
+            const char *s4 = _(s3);
+            if (strcmp (s3, s4))
+              s2 = s3; /* A translation exists - use it. */
+          }
+        tty_printf ("%s", s2) ;
+      }
     uid = aname = acomment = amail = NULL;
     for(;;) {
        char *p;
     uid = aname = acomment = amail = NULL;
     for(;;) {
        char *p;
@@ -1640,7 +2093,7 @@ ask_user_id( int mode )
 
        if( !aname ) {
            for(;;) {
 
        if( !aname ) {
            for(;;) {
-               m_free(aname);
+               xfree(aname);
                aname = cpr_get("keygen.name",_("Real name: "));
                trim_spaces(aname);
                cpr_kill_prompt();
                aname = cpr_get("keygen.name",_("Real name: "));
                trim_spaces(aname);
                cpr_kill_prompt();
@@ -1660,26 +2113,21 @@ ask_user_id( int mode )
        }
        if( !amail ) {
            for(;;) {
        }
        if( !amail ) {
            for(;;) {
-               m_free(amail);
+               xfree(amail);
                amail = cpr_get("keygen.email",_("Email address: "));
                trim_spaces(amail);
                cpr_kill_prompt();
                if( !*amail || opt.allow_freeform_uid )
                    break;   /* no email address is okay */
                amail = cpr_get("keygen.email",_("Email address: "));
                trim_spaces(amail);
                cpr_kill_prompt();
                if( !*amail || opt.allow_freeform_uid )
                    break;   /* no email address is okay */
-               else if( has_invalid_email_chars(amail)
-                        || string_count_chr(amail,'@') != 1
-                        || *amail == '@'
-                        || amail[strlen(amail)-1] == '@'
-                        || amail[strlen(amail)-1] == '.'
-                        || strstr(amail, "..") )
-                   tty_printf(_("Not a valid email address\n"));
+               else if ( !is_valid_mailbox (amail) )
+                    tty_printf(_("Not a valid email address\n"));
                else
                    break;
            }
        }
        if( !acomment ) {
            for(;;) {
                else
                    break;
            }
        }
        if( !acomment ) {
            for(;;) {
-               m_free(acomment);
+               xfree(acomment);
                acomment = cpr_get("keygen.comment",_("Comment: "));
                trim_spaces(acomment);
                cpr_kill_prompt();
                acomment = cpr_get("keygen.comment",_("Comment: "));
                trim_spaces(acomment);
                cpr_kill_prompt();
@@ -1693,18 +2141,17 @@ ask_user_id( int mode )
        }
 
 
        }
 
 
-       m_free(uid);
-       uid = p = m_alloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
+       xfree(uid);
+       uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
        p = stpcpy(p, aname );
        if( *acomment )
            p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
        if( *amail )
            p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
 
        p = stpcpy(p, aname );
        if( *acomment )
            p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
        if( *amail )
            p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
 
-       /* append a warning if we do not have dev/random
-        * or it is switched into  quick testmode */
-       if( quick_random_gen(-1) )
-           strcpy(p, " (INSECURE!)" );
+       /* Append a warning if the RNG is switched into fake mode.  */
+        if ( random_is_faked ()  )
+          strcpy(p, " (insecure!)" );
 
        /* print a note in case that UTF8 mapping has to be done */
        for(p=uid; *p; p++ ) {
 
        /* print a note in case that UTF8 mapping has to be done */
        for(p=uid; *p; p++ ) {
@@ -1716,16 +2163,31 @@ ask_user_id( int mode )
        }
 
        tty_printf(_("You selected this USER-ID:\n    \"%s\"\n\n"), uid);
        }
 
        tty_printf(_("You selected this USER-ID:\n    \"%s\"\n\n"), uid);
-       /* fixme: add a warning if this user-id already exists */
+
        if( !*amail && !opt.allow_freeform_uid
            && (strchr( aname, '@' ) || strchr( acomment, '@'))) {
            fail = 1;
        if( !*amail && !opt.allow_freeform_uid
            && (strchr( aname, '@' ) || strchr( acomment, '@'))) {
            fail = 1;
-           tty_printf(_("Please don't put the email address "
-                         "into the real name or the comment\n") );
+            tty_printf(_("Please don't put the email address "
+                         "into the real name or the comment\n") );
        }
 
        }
 
+        if (!fail && keyblock)
+          {
+            PKT_user_id *uidpkt = uid_from_string (uid);
+            KBNODE node;
+
+            for (node=keyblock; node && !fail; node=node->next)
+              if (!is_deleted_kbnode (node)
+                  && node->pkt->pkttype == PKT_USER_ID
+                  && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id))
+               fail = 1;
+            if (fail)
+              tty_printf (_("Such a user ID already exists on this key!\n"));
+            free_user_id (uidpkt);
+          }
+
        for(;;) {
        for(;;) {
-            /* Note to translators: These are the allowed answers in
+            /* TRANSLATORS: These are the allowed answers in
                lower and uppercase.  Below you will find the matching
                string which should be translated accordingly and the
                letter changed to match the one in the answer string.
                lower and uppercase.  Below you will find the matching
                string which should be translated accordingly and the
                letter changed to match the one in the answer string.
@@ -1741,7 +2203,7 @@ ask_user_id( int mode )
            if( strlen(ansstr) != 10 )
                BUG();
            if( cpr_enabled() ) {
            if( strlen(ansstr) != 10 )
                BUG();
            if( cpr_enabled() ) {
-               answer = m_strdup(ansstr+6);
+                answer = xstrdup (ansstr + (fail?8:6));
                answer[1] = 0;
            }
            else {
                answer[1] = 0;
            }
            else {
@@ -1753,15 +2215,15 @@ ask_user_id( int mode )
            if( strlen(answer) > 1 )
                ;
            else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
            if( strlen(answer) > 1 )
                ;
            else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
-               m_free(aname); aname = NULL;
+               xfree(aname); aname = NULL;
                break;
            }
            else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
                break;
            }
            else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
-               m_free(acomment); acomment = NULL;
+               xfree(acomment); acomment = NULL;
                break;
            }
            else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
                break;
            }
            else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
-               m_free(amail); amail = NULL;
+               xfree(amail); amail = NULL;
                break;
            }
            else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
                break;
            }
            else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
@@ -1769,58 +2231,69 @@ ask_user_id( int mode )
                    tty_printf(_("Please correct the error first\n"));
                }
                else {
                    tty_printf(_("Please correct the error first\n"));
                }
                else {
-                   m_free(aname); aname = NULL;
-                   m_free(acomment); acomment = NULL;
-                   m_free(amail); amail = NULL;
+                   xfree(aname); aname = NULL;
+                   xfree(acomment); acomment = NULL;
+                   xfree(amail); amail = NULL;
                    break;
                }
            }
            else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
                    break;
                }
            }
            else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
-               m_free(aname); aname = NULL;
-               m_free(acomment); acomment = NULL;
-               m_free(amail); amail = NULL;
-               m_free(uid); uid = NULL;
+               xfree(aname); aname = NULL;
+               xfree(acomment); acomment = NULL;
+               xfree(amail); amail = NULL;
+               xfree(uid); uid = NULL;
                break;
            }
                break;
            }
-           m_free(answer);
+           xfree(answer);
        }
        }
-       m_free(answer);
+       xfree(answer);
        if( !amail && !acomment && !amail )
            break;
        if( !amail && !acomment && !amail )
            break;
-       m_free(uid); uid = NULL;
+       xfree(uid); uid = NULL;
     }
     if( uid ) {
        char *p = native_to_utf8( uid );
     }
     if( uid ) {
        char *p = native_to_utf8( uid );
-       m_free( uid );
+       xfree( uid );
        uid = p;
     }
     return uid;
 }
 
 
        uid = p;
     }
     return uid;
 }
 
 
-/* FIXME: We need a way to cancel this prompt. */
+/*  MODE  0 - standard
+          1 - Ask for passphrase of the card backup key.  */
 static DEK *
 static DEK *
-do_ask_passphrase( STRING2KEY **ret_s2k )
+do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
 {
     DEK *dek = NULL;
     STRING2KEY *s2k;
     const char *errtext = NULL;
 {
     DEK *dek = NULL;
     STRING2KEY *s2k;
     const char *errtext = NULL;
+    const char *custdesc = NULL;
 
     tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
 
 
     tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
 
-    s2k = m_alloc_secure( sizeof *s2k );
+    if (mode == 1)
+      custdesc = _("Please enter a passphrase to protect the off-card "
+                   "backup of the new encryption key.");
+
+    s2k = xmalloc_secure( sizeof *s2k );
     for(;;) {
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
     for(;;) {
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
-       dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,
-                                 errtext, NULL);
-       if( !dek ) {
+       dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
+                                     errtext, custdesc, NULL, r_canceled);
+        if (!dek && *r_canceled) {
+           xfree(dek); dek = NULL;
+           xfree(s2k); s2k = NULL;
+            break;
+        }
+       else if( !dek ) {
            errtext = N_("passphrase not correctly repeated; try again");
            tty_printf(_("%s.\n"), _(errtext));
        }
        else if( !dek->keylen ) {
            errtext = N_("passphrase not correctly repeated; try again");
            tty_printf(_("%s.\n"), _(errtext));
        }
        else if( !dek->keylen ) {
-           m_free(dek); dek = NULL;
-           m_free(s2k); s2k = NULL;
+           xfree(dek); dek = NULL;
+           xfree(s2k); s2k = NULL;
            tty_printf(_(
            "You don't want a passphrase - this is probably a *bad* idea!\n"
            "I will do it anyway.  You can change your passphrase at any time,\n"
            tty_printf(_(
            "You don't want a passphrase - this is probably a *bad* idea!\n"
            "I will do it anyway.  You can change your passphrase at any time,\n"
@@ -1835,10 +2308,12 @@ do_ask_passphrase( STRING2KEY **ret_s2k )
 }
 
 
 }
 
 
+/* Basic key generation.  Here we divert to the actual generation
+   routines based on the requested algorithm.  */
 static int
 static int
-do_createint algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
-          DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate,
-          int is_subkey )
+do_create (int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
+          DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, 
+           u32 timestamp, u32 expiredate, int is_subkey )
 {
   int rc=0;
 
 {
   int rc=0;
 
@@ -1850,50 +2325,33 @@ 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 )
 "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 )
   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 )
   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();
 
   else
     BUG();
 
-#ifdef ENABLE_COMMENT_PACKETS
-  if( !rc ) {
-    add_kbnode( pub_root,
-               make_comment_node("#created by GNUPG v" VERSION " ("
-                                 PRINTABLE_OS_NAME ")"));
-    add_kbnode( sec_root,
-               make_comment_node("#created by GNUPG v" VERSION " ("
-                                 PRINTABLE_OS_NAME ")"));
-  }
-#endif
   return rc;
 }
 
 
   return rc;
 }
 
 
-/****************
- * Generate a new user id packet, or return NULL if canceled
- */
+/* Generate a new user id packet or return NULL if canceled.  If
+   KEYBLOCK is not NULL the function prevents the creation of an
  already existing user ID.  */
 PKT_user_id *
 PKT_user_id *
-generate_user_id()
+generate_user_id (KBNODE keyblock)
 {
 {
-    PKT_user_id *uid;
-    char *p;
-    size_t n;
-
-    p = ask_user_id( 1 );
-    if( !p )
-       return NULL;
-    n = strlen(p);
-    uid = m_alloc_clear( sizeof *uid + n - 1 );
-    uid->len = n;
-    strcpy(uid->name, p);
-    uid->ref = 1;
-    return uid;
+  char *p;
+  
+  p = ask_user_id (1, keyblock);
+  if (!p)
+    return NULL;  /* Canceled. */
+  return uid_from_string (p);
 }
 
 
 }
 
 
@@ -1905,11 +2363,11 @@ release_parameter_list( struct para_data_s *r )
     for( ; r ; r = r2 ) {
        r2 = r->next;
        if( r->key == pPASSPHRASE_DEK )
     for( ; r ; r = r2 ) {
        r2 = r->next;
        if( r->key == pPASSPHRASE_DEK )
-           m_free( r->u.dek );
+           xfree( r->u.dek );
        else if( r->key == pPASSPHRASE_S2K )
        else if( r->key == pPASSPHRASE_S2K )
-           m_free( r->u.s2k );
+           xfree( r->u.s2k );
 
 
-       m_free(r);
+       xfree(r);
     }
 }
 
     }
 }
 
@@ -1931,23 +2389,42 @@ get_parameter_value( struct para_data_s *para, enum para_name key )
 }
 
 static int
 }
 
 static int
-get_parameter_algo( struct para_data_s *para, enum para_name key )
+get_parameter_algo( struct para_data_s *para, enum para_name key, 
+                    int *r_default)
 {
 {
-    int i;
-    struct para_data_s *r = get_parameter( para, key );
-    if( !r )
-       return -1;
-    if( digitp( r->u.value ) )
-       i = atoi( r->u.value );
-    else
-        i = string_to_pubkey_algo( r->u.value );
-    if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
-      i = 0; /* we don't want to allow generation of these algorithms */
-    return i;
+  int i;
+  struct para_data_s *r = get_parameter( para, key );
+
+  if (r_default)
+    *r_default = 0;
+
+  if (!r)
+    return -1;
+
+  if (!ascii_strcasecmp (r->u.value, "default"))
+    {
+      /* Note: If you change this default algo, remember to change it
+         also in gpg.c:gpgconf_list.  */
+      i = DEFAULT_STD_ALGO;
+      if (r_default)
+        *r_default = 1;
+    }
+  else if (digitp (r->u.value))
+    i = atoi( r->u.value );
+  else if (!strcmp (r->u.value, "ELG-E")
+           || !strcmp (r->u.value, "ELG"))
+    i = GCRY_PK_ELG_E;
+  else
+    i = gcry_pk_map_name (r->u.value);
+
+  if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
+    i = 0; /* we don't want to allow generation of these algorithms */
+  return i;
 }
 
 /* 
 }
 
 /* 
- * parse the usage parameter and set the keyflags.  Return true on error.
+ * Parse the usage parameter and set the keyflags.  Returns -1 on
+ * error, 0 for no usage given or 1 for usage available.
  */
 static int
 parse_parameter_usage (const char *fname,
  */
 static int
 parse_parameter_usage (const char *fname,
@@ -1977,7 +2454,7 @@ parse_parameter_usage (const char *fname,
         }
     }
     r->u.usage = use;
         }
     }
     r->u.usage = use;
-    return 0;
+    return 1;
 }
 
 static int
 }
 
 static int
@@ -2037,16 +2514,18 @@ parse_revocation_key (const char *fname,
 static u32
 get_parameter_u32( struct para_data_s *para, enum para_name key )
 {
 static u32
 get_parameter_u32( struct para_data_s *para, enum para_name key )
 {
-    struct para_data_s *r = get_parameter( para, key );
-
-    if( !r )
-       return 0;
-    if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
-       return r->u.expire;
-    if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
-       return r->u.usage;
+  struct para_data_s *r = get_parameter( para, key );
 
 
-    return (unsigned int)strtoul( r->u.value, NULL, 10 );
+  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;
+  
+  return (unsigned int)strtoul( r->u.value, NULL, 10 );
 }
 
 static unsigned int
 }
 
 static unsigned int
@@ -2080,118 +2559,264 @@ static int
 proc_parameter_file( struct para_data_s *para, const char *fname,
                      struct output_control_s *outctrl, int card )
 {
 proc_parameter_file( struct para_data_s *para, const char *fname,
                      struct output_control_s *outctrl, int card )
 {
-    struct para_data_s *r;
-    const char *s1, *s2, *s3;
-    size_t n;
-    char *p;
-    int i;
+  struct para_data_s *r;
+  const char *s1, *s2, *s3;
+  size_t n;
+  char *p;
+  int is_default = 0;
+  int have_user_id = 0;
+  int err, algo;
+
+  /* Check that we have all required parameters. */
+  r = get_parameter( para, pKEYTYPE );
+  if(r)
+    {
+      algo = get_parameter_algo (para, pKEYTYPE, &is_default);
+      if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG))
+       {
+         log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
+         return -1;
+       }
+    }
+  else
+    {
+      log_error ("%s: no Key-Type specified\n",fname);
+      return -1;
+    }
 
 
-    /* Check that we have all required parameters. */
-    assert( get_parameter( para, pKEYTYPE ) );
-    i = get_parameter_algo( para, pKEYTYPE );
-    if( i < 1 || check_pubkey_algo2( i, PUBKEY_USAGE_SIG ) ) {
-       r = get_parameter( para, pKEYTYPE );
-       log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
-       return -1;
+  err = parse_parameter_usage (fname, para, pKEYUSAGE);
+  if (!err)
+    {
+      /* Default to algo capabilities if key-usage is not provided and
+         no default algorithm has been requested.  */
+      r = xmalloc_clear(sizeof(*r));
+      r->key = pKEYUSAGE;
+      r->u.usage = (is_default
+                    ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG)
+                    : openpgp_pk_algo_usage(algo));
+      r->next = para;
+      para = r;
+    }
+  else if (err == -1)
+    return -1;
+  else
+    {
+      r = get_parameter (para, pKEYUSAGE);
+      if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo)))
+        {
+          log_error ("%s:%d: specified Key-Usage not allowed for algo %d\n",
+                     fname, r->lnr, algo);
+          return -1;
+        }
     }
 
     }
 
-    if (parse_parameter_usage (fname, para, pKEYUSAGE))
-        return -1;
+  is_default = 0;
+  r = get_parameter( para, pSUBKEYTYPE );
+  if(r)
+    {
+      algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default);
+      if (openpgp_pk_test_algo (algo))
+       {
+         log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
+         return -1;
+       }
 
 
-    i = get_parameter_algo( para, pSUBKEYTYPE );
-    if( i > 0 && check_pubkey_algo( i ) ) {
-       r = get_parameter( para, pSUBKEYTYPE );
-       log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
+      err = parse_parameter_usage (fname, para, pSUBKEYUSAGE);
+      if (!err)
+       {
+         /* Default to algo capabilities if subkey-usage is not
+            provided */
+         r = xmalloc_clear (sizeof(*r));
+         r->key = pSUBKEYUSAGE;
+         r->u.usage = (is_default
+                        ? PUBKEY_USAGE_ENC
+                        : openpgp_pk_algo_usage (algo));
+         r->next = para;
+         para = r;
+       }
+      else if (err == -1)
        return -1;
        return -1;
+      else
+        {
+          r = get_parameter (para, pSUBKEYUSAGE);
+          if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo)))
+            {
+              log_error ("%s:%d: specified Subkey-Usage not allowed"
+                         " for algo %d\n", fname, r->lnr, algo);
+              return -1;
+            }
+        }
     }
     }
-    if (i > 0 && parse_parameter_usage (fname, para, pSUBKEYUSAGE))
-        return -1;
 
 
 
 
-    if( !get_parameter_value( para, pUSERID ) ) {
-       /* create the formatted user ID */
-       s1 = get_parameter_value( para, pNAMEREAL );
-       s2 = get_parameter_value( para, pNAMECOMMENT );
-       s3 = get_parameter_value( para, pNAMEEMAIL );
-       if( s1 || s2 || s3 ) {
-           n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0);
-           r = m_alloc_clear( sizeof *r + n + 20 );
-           r->key = pUSERID;
-           p = r->u.value;
-           if( s1 )
-               p = stpcpy(p, s1 );
-           if( s2 )
-               p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
-           if( s3 )
-               p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
-           r->next = para;
-           para = r;
+  if( get_parameter_value( para, pUSERID ) )
+    have_user_id=1;
+  else
+    {
+      /* create the formatted user ID */
+      s1 = get_parameter_value( para, pNAMEREAL );
+      s2 = get_parameter_value( para, pNAMECOMMENT );
+      s3 = get_parameter_value( para, pNAMEEMAIL );
+      if( s1 || s2 || s3 )
+       {
+         n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0);
+         r = xmalloc_clear( sizeof *r + n + 20 );
+         r->key = pUSERID;
+         p = r->u.value;
+         if( s1 )
+           p = stpcpy(p, s1 );
+         if( s2 )
+           p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
+         if( s3 )
+           p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
+         r->next = para;
+         para = r;
+         have_user_id=1;
        }
     }
 
        }
     }
 
-    /* Set preferences, if any. */
-    keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0);
-
-    /* Set revoker, if any. */
-    if (parse_revocation_key (fname, para, pREVOKER))
+  if(!have_user_id)
+    {
+      log_error("%s: no User-ID specified\n",fname);
       return -1;
       return -1;
+    }
 
 
-    /* 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 */
-       STRING2KEY *s2k;
-       DEK *dek;
+  /* Set preferences, if any. */
+  keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0);
 
 
-       s2k = m_alloc_secure( sizeof *s2k );
-       s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = S2K_DIGEST_ALGO;
-       set_next_passphrase( r->u.value );
-       dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2,
-                                 NULL, NULL);
-       set_next_passphrase( NULL );
-       assert( dek );
-       memset( r->u.value, 0, strlen(r->u.value) );
-
-       r = m_alloc_clear( sizeof *r );
-       r->key = pPASSPHRASE_S2K;
-       r->u.s2k = s2k;
-       r->next = para;
-       para = r;
-       r = m_alloc_clear( sizeof *r );
-       r->key = pPASSPHRASE_DEK;
-       r->u.dek = dek;
-       r->next = para;
-       para = r;
+  /* Set keyserver, if any. */
+  s1=get_parameter_value( para, pKEYSERVER );
+  if(s1)
+    {
+      struct keyserver_spec *spec;
+
+      spec=parse_keyserver_uri(s1,1,NULL,0);
+      if(spec)
+       {
+         free_keyserver_spec(spec);
+         opt.def_keyserver_url=s1;
+       }
+      else
+       {
+         log_error("%s:%d: invalid keyserver url\n", fname, r->lnr );
+         return -1;
+       }
+    }
+
+  /* Set revoker, if any. */
+  if (parse_revocation_key (fname, para, pREVOKER))
+    return -1;
+
+  /* Make DEK and S2K from the Passphrase. */
+  if (outctrl->ask_passphrase)
+    {
+      /* %ask-passphrase is active - ignore pPASSPRASE and ask.  This
+         feature is required so that GUIs are able to do a key
+         creation but have gpg-agent ask for the passphrase.  */
+      int canceled = 0;
+      STRING2KEY *s2k;
+      DEK *dek;
+
+      dek = do_ask_passphrase (&s2k, 0, &canceled);
+      if (dek)
+        {
+          r = xmalloc_clear( sizeof *r );
+          r->key = pPASSPHRASE_DEK;
+          r->u.dek = dek;
+          r->next = para;
+          para = r;
+          r = xmalloc_clear( sizeof *r );
+          r->key = pPASSPHRASE_S2K;
+          r->u.s2k = s2k;
+          r->next = para;
+          para = r;
+        }
+
+      if (canceled) 
+        {
+         log_error ("%s:%d: key generation canceled\n", fname, r->lnr );
+          return -1;
+        }
+    }
+  else
+    {
+      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 in secure memory
+           * but because we do this always, why not here.  */
+          STRING2KEY *s2k;
+          DEK *dek;
+          
+          s2k = xmalloc_secure ( sizeof *s2k );
+          s2k->mode = opt.s2k_mode;
+          s2k->hash_algo = S2K_DIGEST_ALGO;
+          set_next_passphrase ( r->u.value );
+          dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
+                                   NULL, NULL);
+          set_next_passphrase (NULL );
+          assert (dek);
+          memset (r->u.value, 0, strlen(r->u.value));
+          
+          r = xmalloc_clear (sizeof *r);
+          r->key = pPASSPHRASE_S2K;
+          r->u.s2k = s2k;
+          r->next = para;
+          para = r;
+          r = xmalloc_clear (sizeof *r);
+          r->key = pPASSPHRASE_DEK;
+          r->u.dek = dek;
+          r->next = para;
+          para = r;
+        }
     }
 
     }
 
-    /* make KEYEXPIRE from Expire-Date */
-    r = get_parameter( para, pEXPIREDATE );
-    if( r && *r->u.value ) {
-       i = parse_expire_string( r->u.value );
-       if( i < 0 ) {
-           log_error("%s:%d: invalid expire date\n", fname, r->lnr );
-           return -1;
+  /* 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.expire = i * 86400L;
-       r->key = pKEYEXPIRE;  /* change hat entry */
-       /* also set it for the subkey */
-       r = m_alloc_clear( sizeof *r + 20 );
-       r->key = pSUBKEYEXPIRE;
-       r->u.expire = i * 86400L;
-       r->next = para;
-       para = r;
+      r->u.creation = seconds;
+      r->key = pKEYCREATIONDATE;  /* Change that entry. */
     }
 
     }
 
-    if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) {
-       log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr );
-       return -1;
+  /* Make KEYEXPIRE from Expire-Date.  */
+  r = get_parameter( para, pEXPIREDATE );
+  if( r && *r->u.value )
+    {
+      u32 seconds;
+
+      seconds = parse_expire_string( r->u.value );
+      if( seconds == (u32)-1 )
+       {
+         log_error("%s:%d: invalid expire date\n", fname, r->lnr );
+         return -1;
+       }
+      r->u.expire = seconds;
+      r->key = pKEYEXPIRE;  /* change hat entry */
+      /* also set it for the subkey */
+      r = xmalloc_clear( sizeof *r + 20 );
+      r->key = pSUBKEYEXPIRE;
+      r->u.expire = seconds;
+      r->next = para;
+      para = r;
     }
 
     }
 
-    do_generate_keypair( para, outctrl, card );
-    return 0;
+  if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) {
+    log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr );
+    return -1;
+  }
+
+  do_generate_keypair( para, outctrl, card );
+  return 0;
 }
 
 
 }
 
 
@@ -2216,10 +2841,12 @@ read_parameter_file( const char *fname )
        { "Name-Email",     pNAMEEMAIL },
        { "Name-Comment",   pNAMECOMMENT },
        { "Expire-Date",    pEXPIREDATE },
        { "Name-Email",     pNAMEEMAIL },
        { "Name-Comment",   pNAMECOMMENT },
        { "Expire-Date",    pEXPIREDATE },
+       { "Creation-Date",  pCREATIONDATE },
        { "Passphrase",     pPASSPHRASE },
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
         { "Handle",         pHANDLE },
        { "Passphrase",     pPASSPHRASE },
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
         { "Handle",         pHANDLE },
+       { "Keyserver",      pKEYSERVER },
        { NULL, 0 }
     };
     IOBUF fp;
        { NULL, 0 }
     };
     IOBUF fp;
@@ -2233,6 +2860,8 @@ read_parameter_file( const char *fname )
     struct output_control_s outctrl;
 
     memset( &outctrl, 0, sizeof( outctrl ) );
     struct output_control_s outctrl;
 
     memset( &outctrl, 0, sizeof( outctrl ) );
+    outctrl.pub.afx = new_armor_context ();
+    outctrl.sec.afx = new_armor_context ();
 
     if( !fname || !*fname)
       fname = "-";
 
     if( !fname || !*fname)
       fname = "-";
@@ -2248,7 +2877,7 @@ read_parameter_file( const char *fname )
       log_error (_("can't open `%s': %s\n"), fname, strerror(errno) );
       return;
     }
       log_error (_("can't open `%s': %s\n"), fname, strerror(errno) );
       return;
     }
-    iobuf_ioctl (fp, 3, 1, NULL); /* No file caching. */
+    iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
 
     lnr = 0;
     err = NULL;
 
     lnr = 0;
     err = NULL;
@@ -2281,6 +2910,10 @@ read_parameter_file( const char *fname )
                log_info("%s\n", value );
            else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
                outctrl.dryrun = 1;
                log_info("%s\n", value );
            else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
                outctrl.dryrun = 1;
+           else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) )
+               outctrl.ask_passphrase = 1;
+           else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) )
+               outctrl.ask_passphrase = 0;
            else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
                outctrl.lnr = lnr;
                if (proc_parameter_file( para, fname, &outctrl, 0 ))
            else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
                outctrl.lnr = lnr;
                if (proc_parameter_file( para, fname, &outctrl, 0 ))
@@ -2293,8 +2926,8 @@ read_parameter_file( const char *fname )
                if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) )
                    ; /* still the same file - ignore it */
                else {
                if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) )
                    ; /* still the same file - ignore it */
                else {
-                   m_free( outctrl.pub.newfname );
-                   outctrl.pub.newfname = m_strdup( value );
+                   xfree( outctrl.pub.newfname );
+                   outctrl.pub.newfname = xstrdup( value );
                    outctrl.use_files = 1;
                }
            }
                    outctrl.use_files = 1;
                }
            }
@@ -2302,8 +2935,8 @@ read_parameter_file( const char *fname )
                if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
                    ; /* still the same file - ignore it */
                else {
                if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
                    ; /* still the same file - ignore it */
                else {
-                  m_free( outctrl.sec.newfname );
-                  outctrl.sec.newfname = m_strdup( value );
+                  xfree( outctrl.sec.newfname );
+                  outctrl.sec.newfname = xstrdup( value );
                   outctrl.use_files = 1;
                }
            }
                   outctrl.use_files = 1;
                }
            }
@@ -2361,7 +2994,7 @@ read_parameter_file( const char *fname )
                break;
            }
        }
                break;
            }
        }
-       r = m_alloc_clear( sizeof *r + strlen( value ) );
+       r = xmalloc_clear( sizeof *r + strlen( value ) );
        r->lnr = lnr;
        r->key = keywords[i].key;
        strcpy( r->u.value, value );
        r->lnr = lnr;
        r->key = keywords[i].key;
        strcpy( r->u.value, value );
@@ -2385,24 +3018,28 @@ read_parameter_file( const char *fname )
 
         /* Must invalidate that ugly cache to actually close it.  */
         if (outctrl.pub.fname)
 
         /* Must invalidate that ugly cache to actually close it.  */
         if (outctrl.pub.fname)
-          iobuf_ioctl (NULL, 2, 0, (char*)outctrl.pub.fname);
+          iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 
+                       0, (char*)outctrl.pub.fname);
         if (outctrl.sec.fname)
         if (outctrl.sec.fname)
-          iobuf_ioctl (NULL, 2, 0, (char*)outctrl.sec.fname);
+          iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
+                       0, (char*)outctrl.sec.fname);
 
 
-       m_free( outctrl.pub.fname );
-       m_free( outctrl.pub.newfname );
-       m_free( outctrl.sec.fname );
-       m_free( outctrl.sec.newfname );
+       xfree( outctrl.pub.fname );
+       xfree( outctrl.pub.newfname );
+       xfree( outctrl.sec.fname );
+       xfree( outctrl.sec.newfname );
     }
 
     release_parameter_list( para );
     iobuf_close (fp);
     }
 
     release_parameter_list( para );
     iobuf_close (fp);
+    release_armor_context (outctrl.pub.afx);
+    release_armor_context (outctrl.sec.afx);
 }
 
 
 /*
  * Generate a keypair (fname is only used in batch mode) If
 }
 
 
 /*
  * Generate a keypair (fname is only used in batch mode) If
- * CARD_SERIALNO is not NULL the fucntion will create the keys on an
+ * CARD_SERIALNO is not NULL the function will create the keys on an
  * OpenPGP Card.  If BACKUP_ENCRYPTION_DIR has been set and
  * CARD_SERIALNO is NOT NULL, the encryption key for the card gets
  * generate in software, imported to the card and a backup file
  * OpenPGP Card.  If BACKUP_ENCRYPTION_DIR has been set and
  * CARD_SERIALNO is NOT NULL, the encryption key for the card gets
  * generate in software, imported to the card and a backup file
@@ -2423,6 +3060,7 @@ generate_keypair (const char *fname, const char *card_serialno,
   struct para_data_s *para = NULL;
   struct para_data_s *r;
   struct output_control_s outctrl;
   struct para_data_s *para = NULL;
   struct para_data_s *r;
   struct output_control_s outctrl;
+  int canceled;
   
   memset( &outctrl, 0, sizeof( outctrl ) );
   
   
   memset( &outctrl, 0, sizeof( outctrl ) );
   
@@ -2490,34 +3128,36 @@ generate_keypair (const char *fname, const char *card_serialno,
     }
   else
     {
     }
   else
     {
-      algo = ask_algo( 0, &use );
-      if( !algo )
-        { /* default: DSA with ElG subkey of the specified size */
+      int subkey_algo; 
+
+      algo = ask_algo (0, &subkey_algo, &use);
+      if (subkey_algo)
+        { 
+          /* Create primary and subkey at once.  */
           both = 1;
           both = 1;
-          r = m_alloc_clear( sizeof *r + 20 );
+          r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYTYPE;
           r->key = pKEYTYPE;
-          sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
-          r->next = para;
-          para = r;
-          tty_printf(_("DSA keypair will have %u bits.\n"),1024);
-          r = m_alloc_clear( sizeof *r + 20 );
-          r->key = pKEYLENGTH;
-          strcpy( r->u.value, "1024" );
+          sprintf( r->u.value, "%d", algo );
           r->next = para;
           para = r;
           r->next = para;
           para = r;
-          r = m_alloc_clear( sizeof *r + 20 );
+         nbits = ask_keysize (algo, 0);
+         r = xmalloc_clear( sizeof *r + 20 );
+         r->key = pKEYLENGTH;
+         sprintf( r->u.value, "%u", nbits);
+         r->next = para;
+         para = r;
+          r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
           r->next = para;
           para = r;
            
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
           r->next = para;
           para = r;
            
-          algo = PUBKEY_ALGO_ELGAMAL_E;
-          r = m_alloc_clear( sizeof *r + 20 );
+          r = xmalloc_clear( sizeof *r + 20 );
           r->key = pSUBKEYTYPE;
           r->key = pSUBKEYTYPE;
-          sprintf( r->u.value, "%d", algo );
+          sprintf( r->u.value, "%d", subkey_algo);
           r->next = para;
           para = r;
           r->next = para;
           para = r;
-          r = m_alloc_clear( sizeof *r + 20 );
+          r = xmalloc_clear( sizeof *r + 20 );
           r->key = pSUBKEYUSAGE;
           strcpy( r->u.value, "encrypt" );
           r->next = para;
           r->key = pSUBKEYUSAGE;
           strcpy( r->u.value, "encrypt" );
           r->next = para;
@@ -2525,7 +3165,7 @@ generate_keypair (const char *fname, const char *card_serialno,
         }
       else 
         {
         }
       else 
         {
-          r = m_alloc_clear( sizeof *r + 20 );
+          r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYTYPE;
           sprintf( r->u.value, "%d", algo );
           r->next = para;
           r->key = pKEYTYPE;
           sprintf( r->u.value, "%d", algo );
           r->next = para;
@@ -2533,7 +3173,7 @@ generate_keypair (const char *fname, const char *card_serialno,
            
           if (use)
             {
            
           if (use)
             {
-              r = m_alloc_clear( sizeof *r + 25 );
+              r = xmalloc_clear( sizeof *r + 25 );
               r->key = pKEYUSAGE;
               sprintf( r->u.value, "%s%s%s",
                        (use & PUBKEY_USAGE_SIG)? "sign ":"",
               r->key = pKEYUSAGE;
               sprintf( r->u.value, "%s%s%s",
                        (use & PUBKEY_USAGE_SIG)? "sign ":"",
@@ -2542,58 +3182,62 @@ generate_keypair (const char *fname, const char *card_serialno,
               r->next = para;
               para = r;
             }
               r->next = para;
               para = r;
             }
-           
+          nbits = 0;
         }
         }
-       
-      nbits = ask_keysize( algo );
-      r = m_alloc_clear( sizeof *r + 20 );
+
+      nbits = ask_keysize (both? subkey_algo : algo, nbits);
+      r = xmalloc_clear( sizeof *r + 20 );
       r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
       sprintf( r->u.value, "%u", nbits);
       r->next = para;
       para = r;
     }
    
       r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
       sprintf( r->u.value, "%u", nbits);
       r->next = para;
       para = r;
     }
    
-  expire = ask_expire_interval(0);
-  r = m_alloc_clear( sizeof *r + 20 );
+  expire = ask_expire_interval(0,NULL);
+  r = xmalloc_clear( sizeof *r + 20 );
   r->key = pKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
   para = r;
   r->key = pKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
   para = r;
-  r = m_alloc_clear( sizeof *r + 20 );
+  r = xmalloc_clear( sizeof *r + 20 );
   r->key = pSUBKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
   para = r;
 
   r->key = pSUBKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
   para = r;
 
-  uid = ask_user_id(0);
+  uid = ask_user_id (0, NULL);
   if( !uid ) 
     {
       log_error(_("Key generation canceled.\n"));
       release_parameter_list( para );
       return;
     }
   if( !uid ) 
     {
       log_error(_("Key generation canceled.\n"));
       release_parameter_list( para );
       return;
     }
-  r = m_alloc_clear( sizeof *r + strlen(uid) );
+  r = xmalloc_clear( sizeof *r + strlen(uid) );
   r->key = pUSERID;
   strcpy( r->u.value, uid );
   r->next = para;
   para = r;
     
   r->key = pUSERID;
   strcpy( r->u.value, uid );
   r->next = para;
   para = r;
     
-  dek = card_serialno? NULL : do_ask_passphrase( &s2k );
+  canceled = 0;
+  dek = card_serialno? NULL : do_ask_passphrase (&s2k, 0, &canceled);
   if( dek )
     {
   if( dek )
     {
-      r = m_alloc_clear( sizeof *r );
+      r = xmalloc_clear( sizeof *r );
       r->key = pPASSPHRASE_DEK;
       r->u.dek = dek;
       r->next = para;
       para = r;
       r->key = pPASSPHRASE_DEK;
       r->u.dek = dek;
       r->next = para;
       para = r;
-      r = m_alloc_clear( sizeof *r );
+      r = xmalloc_clear( sizeof *r );
       r->key = pPASSPHRASE_S2K;
       r->u.s2k = s2k;
       r->next = para;
       para = r;
     }
       r->key = pPASSPHRASE_S2K;
       r->u.s2k = s2k;
       r->next = para;
       para = r;
     }
-    
-  proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
+
+  if (canceled) 
+    log_error (_("Key generation canceled.\n"));
+  else
+    proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
   release_parameter_list( para );
 }
 
   release_parameter_list( para );
 }
 
@@ -2614,6 +3258,8 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
   PKT_secret_key *sk = NULL;
   int i;
   size_t nskey, npkey;
   PKT_secret_key *sk = NULL;
   int i;
   size_t nskey, npkey;
+  gcry_sexp_t s_parms, s_key;
+  int canceled;
 
   npkey = pubkey_get_npkey (algo);
   nskey = pubkey_get_nskey (algo);
 
   npkey = pubkey_get_npkey (algo);
   nskey = pubkey_get_nskey (algo);
@@ -2631,37 +3277,54 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
       log_info(_("keysize rounded up to %u bits\n"), nbits );
     }
 
       log_info(_("keysize rounded up to %u bits\n"), nbits );
     }
 
-  dek = do_ask_passphrase (&s2k);
+  dek = do_ask_passphrase (&s2k, 1, &canceled);
+  if (canceled)
+    {
+      rc = gpg_error (GPG_ERR_CANCELED);
+      goto leave;
+    }
 
 
-  sk = m_alloc_clear (sizeof *sk);
+  sk = xmalloc_clear (sizeof *sk);
   sk->timestamp = created_at;
   sk->version = 4;
   sk->pubkey_algo = algo;
 
   sk->timestamp = created_at;
   sk->version = 4;
   sk->pubkey_algo = algo;
 
-  rc = pubkey_generate (algo, nbits, sk->skey, NULL);
+  if ( !is_RSA (algo) )
+    {
+      log_error ("only RSA is supported for offline generated keys\n");
+      rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+      goto leave;
+    }
+  rc = gcry_sexp_build (&s_parms, NULL,
+                        "(genkey(rsa(nbits %d)))",
+                        (int)nbits);
+  if (rc)
+    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&s_key, s_parms);
+  gcry_sexp_release (s_parms);
   if (rc)
     {
   if (rc)
     {
-      log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
+      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
       goto leave;
     }
       goto leave;
     }
-
+  rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
+  gcry_sexp_release (s_key);
+  if (rc) 
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      goto leave;
+    }
+  
   for (i=npkey; i < nskey; i++)
     sk->csum += checksum_mpi (sk->skey[i]);
 
   if (r_sk_unprotected) 
     *r_sk_unprotected = copy_secret_key (NULL, sk);
 
   for (i=npkey; i < nskey; i++)
     sk->csum += checksum_mpi (sk->skey[i]);
 
   if (r_sk_unprotected) 
     *r_sk_unprotected = copy_secret_key (NULL, sk);
 
-  if (dek)
-    {
-      sk->protect.algo = dek->algo;
-      sk->protect.s2k = *s2k;
-      rc = protect_secret_key (sk, dek);
-      if (rc)
-        {
-          log_error ("protect_secret_key failed: %s\n", g10_errstr(rc));
-          goto leave;
-       }
-    }
+  rc = genhelp_protect (dek, s2k, sk);
+  if (rc)
+    goto leave;
+
   if (r_sk_protected)
     {
       *r_sk_protected = sk;
   if (r_sk_protected)
     {
       *r_sk_protected = sk;
@@ -2671,420 +3334,515 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
  leave:
   if (sk)
     free_secret_key (sk);
  leave:
   if (sk)
     free_secret_key (sk);
-  m_free (dek);
-  m_free (s2k);
+  xfree (dek);
+  xfree (s2k);
   return rc;
 }
 #endif /* ENABLE_CARD_SUPPORT */
 
   return rc;
 }
 #endif /* ENABLE_CARD_SUPPORT */
 
+/* Create and delete a dummy packet to start off a list of kbnodes. */
+static void
+start_tree(KBNODE *tree)
+{
+  PACKET *pkt;
+
+  pkt=xmalloc_clear(sizeof(*pkt));
+  pkt->pkttype=PKT_NONE;
+  *tree=new_kbnode(pkt);
+  delete_kbnode(*tree);
+}
+
 
 static void
 
 static void
-do_generate_keypairstruct para_data_s *para,
-                    struct output_control_s *outctrl, 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;
-    PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
-    const char *s;
-    struct revocation_key *revkey;
-    int rc;
-    int did_sub = 0;
-
-    if( outctrl->dryrun ) {
-       log_info("dry-run mode - key generation skipped\n");
-       return;
-    }
-
-
-    if( outctrl->use_files ) {
-       if( outctrl->pub.newfname ) {
-           iobuf_close(outctrl->pub.stream);
-           outctrl->pub.stream = NULL;
-            if (outctrl->pub.fname)
-              iobuf_ioctl (NULL, 2, 0, (char*)outctrl->pub.fname);
-           m_free( outctrl->pub.fname );
-           outctrl->pub.fname =  outctrl->pub.newfname;
-           outctrl->pub.newfname = NULL;
-
-            if (is_secured_filename (outctrl->pub.fname) ) {
-                outctrl->pub.stream = NULL;
-                errno = EPERM;
+  KBNODE pub_root = NULL;
+  KBNODE sec_root = NULL;
+  PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
+  const char *s;
+  struct revocation_key *revkey;
+  int rc;
+  int did_sub = 0;
+  u32 timestamp;
+
+  if( outctrl->dryrun )
+    {
+      log_info("dry-run mode - key generation skipped\n");
+      return;
+    }
+  
+  if ( outctrl->use_files ) 
+    {
+      if ( outctrl->pub.newfname ) 
+        {
+          iobuf_close(outctrl->pub.stream);
+          outctrl->pub.stream = NULL;
+          if (outctrl->pub.fname)
+            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
+                         0, (char*)outctrl->pub.fname);
+          xfree( outctrl->pub.fname );
+          outctrl->pub.fname =  outctrl->pub.newfname;
+          outctrl->pub.newfname = NULL;
+          
+          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 ) {
-               log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
-                                                    strerror(errno) );
-               return;
-           }
-           if( opt.armor ) {
-               outctrl->pub.afx.what = 1;
-               iobuf_push_filter( outctrl->pub.stream, armor_filter,
-                                                   &outctrl->pub.afx );
-           }
-       }
-       if( outctrl->sec.newfname ) {
-            mode_t oldmask;
-
-           iobuf_close(outctrl->sec.stream);
-           outctrl->sec.stream = NULL;
-            if (outctrl->sec.fname)
-              iobuf_ioctl (NULL, 2, 0, (char*)outctrl->sec.fname);
-           m_free( outctrl->sec.fname );
-           outctrl->sec.fname =  outctrl->sec.newfname;
-           outctrl->sec.newfname = NULL;
-
-           oldmask = umask (077);
-            if (is_secured_filename (outctrl->sec.fname) ) {
-                outctrl->sec.stream = NULL;
-                errno = EPERM;
+          else
+            outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
+          if (!outctrl->pub.stream)
+            {
+              log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
+                        strerror(errno) );
+              return;
+            }
+          if (opt.armor)
+            {
+              outctrl->pub.afx->what = 1;
+              push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
+            }
+        }
+      if (outctrl->sec.newfname)
+        {
+          mode_t oldmask;
+          
+          iobuf_close(outctrl->sec.stream);
+          outctrl->sec.stream = NULL;
+          if (outctrl->sec.fname)
+            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
+                         0, (char*)outctrl->sec.fname);
+          xfree( outctrl->sec.fname );
+          outctrl->sec.fname =  outctrl->sec.newfname;
+          outctrl->sec.newfname = NULL;
+
+          oldmask = umask (077);
+          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)
+            {
+              log_error(_("can't create `%s': %s\n"), outctrl->sec.newfname,
+                        strerror(errno) );
+              return;
+            }
+          if (opt.armor)
+            {
+              outctrl->sec.afx->what = 5;
+              push_armor_filter (outctrl->sec.afx, outctrl->sec.stream);
             }
             }
-            else
-                outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
-            umask (oldmask);
-           if( !outctrl->sec.stream ) {
-               log_error(_("can't create `%s': %s\n"), outctrl->sec.newfname,
-                                                    strerror(errno) );
-               return;
-           }
-           if( opt.armor ) {
-               outctrl->sec.afx.what = 5;
-               iobuf_push_filter( outctrl->sec.stream, armor_filter,
-                                                   &outctrl->sec.afx );
-           }
-       }
-       assert( outctrl->pub.stream );
-       assert( outctrl->sec.stream );
-        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"),
-                        outctrl->sec.fname);
-            else
-              log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
+        }
+      assert( outctrl->pub.stream );
+      assert( outctrl->sec.stream );
+      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"),
+                      outctrl->sec.fname);
+          else
+            log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
         }
     }
 
 
         }
     }
 
 
-    /* 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 comment packet which we flag
-     * as deleted.  The very first packet must always be a KEY packet.
-     */
-    pub_root = make_comment_node("#"); delete_kbnode(pub_root);
-    sec_root = make_comment_node("#"); delete_kbnode(sec_root);
+  /* 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 ();
+
+  /* Note that, depending on the backend (i.e. the used scdaemon
+     version), the card key generation may update TIMESTAMP for each
+     key.  Thus we need to pass TIMESTAMP to all signing function to
+     make sure that the binding signature is done using the timestamp
+     of the corresponding (sub)key and not that of the primary key.
+     An alternative implementation could tell the signing function the
+     node of the subkey but that is more work than just to pass the
+     current timestamp.  */
+
+  if (!card)
+    {
+      rc = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
+                      get_parameter_uint( para, pKEYLENGTH ),
+                      pub_root, sec_root,
+                      get_parameter_dek( para, pPASSPHRASE_DEK ),
+                      get_parameter_s2k( para, pPASSPHRASE_S2K ),
+                      &pri_sk,
+                      timestamp,
+                      get_parameter_u32( para, pKEYEXPIRE ), 0 );
+    }
+  else
+    {
+      rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL,
+                         &timestamp,
+                         get_parameter_u32 (para, pKEYEXPIRE), para);
+      if (!rc)
+        {
+          pri_sk = sec_root->next->pkt->pkt.secret_key;
+          assert (pri_sk);
+        }
+    }
 
 
-    if (!card)
-      {
-        rc = do_create( get_parameter_algo( para, pKEYTYPE ),
-                        get_parameter_uint( para, pKEYLENGTH ),
-                        pub_root, sec_root,
-                        get_parameter_dek( para, pPASSPHRASE_DEK ),
-                        get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                        &pri_sk,
-                        get_parameter_u32( para, pKEYEXPIRE ), 0 );
-      }
-    else
-      {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root,
-                           get_parameter_u32 (para, pKEYEXPIRE), para);
-        if (!rc)
-          {
-            pri_sk = sec_root->next->pkt->pkt.secret_key;
-            assert (pri_sk);
-          }
-      }
+  if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
+    {
+      rc = write_direct_sig (pub_root, pub_root, pri_sk, revkey, timestamp);
+      if (!rc)
+        rc = write_direct_sig (sec_root, pub_root, pri_sk, revkey, timestamp);
+    }
 
 
-    if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
-      {
-       rc=write_direct_sig(pub_root,pub_root,pri_sk,revkey);
-       if(!rc)
-         write_direct_sig(sec_root,pub_root,pri_sk,revkey);
-      }
+  if( !rc && (s=get_parameter_value(para, pUSERID)) )
+    {
+      write_uid (pub_root, s );
+      write_uid (sec_root, s );
 
 
-    if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
-       write_uid(pub_root, s );
-       if( !rc )
-           write_uid(sec_root, s );
-       if( !rc )
-           rc = write_selfsig(pub_root, pub_root, pri_sk,
-                               get_parameter_uint (para, pKEYUSAGE));
-       if( !rc )
-           rc = write_selfsig(sec_root, pub_root, pri_sk,
-                               get_parameter_uint (para, pKEYUSAGE));
+      rc = write_selfsigs (sec_root, pub_root, pri_sk,
+                           get_parameter_uint (para, pKEYUSAGE), timestamp);
     }
 
     }
 
-    if( get_parameter( para, pSUBKEYTYPE ) )
-      {
-        if (!card)
-          {
-            rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ),
-                            get_parameter_uint( para, pSUBKEYLENGTH ),
-                            pub_root, sec_root,
-                            get_parameter_dek( para, pPASSPHRASE_DEK ),
-                            get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                            &sub_sk,
-                            get_parameter_u32( para, pSUBKEYEXPIRE ), 1 );
-          }
-        else
-          {
-            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
-                   the card.  Write a backup file. */
-                rc = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0,
-                                               pub_root, sec_root,
-                                               get_parameter_u32 (para,
-                                                                  pKEYEXPIRE),
-                                               para, s);
-              }
-            else
-              rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
-                                 get_parameter_u32 (para, pKEYEXPIRE), para);
-          }
-
-        if( !rc )
-          rc = write_keybinding(pub_root, pub_root, pri_sk, sub_sk,
-                                get_parameter_uint (para, pSUBKEYUSAGE));
-        if( !rc )
-          rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk,
-                                get_parameter_uint (para, pSUBKEYUSAGE));
-        did_sub = 1;
-      }
+  /* Write the auth key to the card before the encryption key.  This
+     is a partial workaround for a PGP bug (as of this writing, all
+     versions including 8.1), that causes it to try and encrypt to
+     the most recent subkey regardless of whether that subkey is
+     actually an encryption type.  In this case, the auth key is an
+     RSA key so it succeeds. */
 
 
-    if (card && get_parameter (para, pAUTHKEYTYPE))
-      {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root,
-                           get_parameter_u32 (para, pKEYEXPIRE), para);
+  if (!rc && card && get_parameter (para, pAUTHKEYTYPE))
+    {
+      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);
-        if (!rc)
-          rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
-      }
-    
-    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 ) {
-           rc = write_keyblock( outctrl->sec.stream, sec_root );
-           if( rc )
-               log_error("can't write secret key: %s\n", g10_errstr(rc) );
-       }
+      if (!rc)
+        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, timestamp);
+    }
+
+  if( !rc && get_parameter( para, pSUBKEYTYPE ) )
+    {
+      if (!card)
+        {
+          rc = do_create( get_parameter_algo( para, pSUBKEYTYPE, NULL ),
+                          get_parameter_uint( para, pSUBKEYLENGTH ),
+                          pub_root, sec_root,
+                          get_parameter_dek( para, pPASSPHRASE_DEK ),
+                          get_parameter_s2k( para, pPASSPHRASE_S2K ),
+                          &sub_sk,
+                          timestamp,
+                          get_parameter_u32( para, pSUBKEYEXPIRE ), 1 );
+        }
+      else
+        {
+          if ((s = get_parameter_value (para, pBACKUPENCDIR)))
+            {
+              /* A backup of the encryption key has been requested.
+                 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
+            {
+              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),
+                              timestamp);
+      if( !rc )
+        rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk,
+                              get_parameter_uint (para, pSUBKEYUSAGE),
+                              timestamp);
+      did_sub = 1;
     }
     }
-    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"),
+  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) 
+        {
+          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.  */
+    {
+      KEYDB_HANDLE pub_hd = keydb_new (0);
+      KEYDB_HANDLE sec_hd = keydb_new (1);
+
+      rc = keydb_locate_writable (pub_hd, NULL);
+      if (rc) 
+        log_error (_("no writable public keyring found: %s\n"),
+                   g10_errstr (rc));
+
+      if (!rc) 
+        {  
+          rc = keydb_locate_writable (sec_hd, NULL);
+          if (rc) 
+            log_error (_("no writable secret keyring found: %s\n"),
                        g10_errstr (rc));
                        g10_errstr (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) {
-            log_info(_("writing public key to `%s'\n"),
-                     keydb_get_resource_name (pub_hd));
-            if (card)
-              log_info (_("writing secret key stub to `%s'\n"),
-                        keydb_get_resource_name (sec_hd));
-            else
-              log_info(_("writing secret key to `%s'\n"),
-                       keydb_get_resource_name (sec_hd));
+      
+      if (!rc && opt.verbose)
+        {
+          log_info (_("writing public key to `%s'\n"),
+                    keydb_get_resource_name (pub_hd));
+          if (card)
+            log_info (_("writing secret key stub to `%s'\n"),
+                      keydb_get_resource_name (sec_hd));
+          else
+            log_info (_("writing secret key to `%s'\n"),
+                      keydb_get_resource_name (sec_hd));
         }
         }
-
-        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) 
+        {
+          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) {
-           rc = keydb_insert_keyblock (sec_hd, sec_root);
-            if (rc)
-                log_error (_("error writing secret keyring `%s': %s\n"),
-                           keydb_get_resource_name (pub_hd), g10_errstr(rc));
+      
+      if (!rc)
+        {
+          rc = keydb_insert_keyblock (sec_hd, sec_root);
+          if (rc)
+            log_error (_("error writing secret keyring `%s': %s\n"),
+                       keydb_get_resource_name (pub_hd), g10_errstr(rc));
         }
 
         }
 
-        keydb_release (pub_hd);
-        keydb_release (sec_hd);
+      keydb_release (pub_hd);
+      keydb_release (sec_hd);
+      
+      if (!rc)
+        {
+          int no_enc_rsa;
+          PKT_public_key *pk;
+
+          no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL)
+                         == PUBKEY_ALGO_RSA)
+                        && get_parameter_uint (para, pKEYUSAGE)
+                        && !((get_parameter_uint (para, pKEYUSAGE)
+                              & PUBKEY_USAGE_ENC)) );
 
 
-       if (!rc) {
-            int 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;
+          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);
+          keyid_from_pk(pk,pk->main_keyid);
+          register_trusted_keyid(pk->main_keyid);
 
 
-           update_ownertrust (pk,
-                              ((get_ownertrust (pk) & ~TRUST_MASK)
-                               | TRUST_ULTIMATE ));
+          update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
+                                  | TRUST_ULTIMATE ));
 
 
-           if (!opt.batch) {
-                tty_printf(_("public and secret key created and signed.\n") );
-               tty_printf("\n");
-               list_keyblock(pub_root,0,1,NULL);
+          if (!opt.batch) 
+            {
+              tty_printf (_("public and secret key created and signed.\n") );
+              tty_printf ("\n");
+              list_keyblock(pub_root,0,1,NULL);
             }
             
             }
             
-
-           if( !opt.batch
-               && ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
-                     || no_enc_rsa )
-               && !get_parameter( para, pSUBKEYTYPE ) )
-           {
-               tty_printf(_("Note that this key cannot be used for "
-                            "encryption.  You may want to use\n"
-                            "the command \"--edit-key\" to generate a "
-                            "secondary key for this purpose.\n") );
-           }
-       }
+          
+          if (!opt.batch
+              && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
+                  || no_enc_rsa )
+              && !get_parameter (para, pSUBKEYTYPE) )
+            {
+              tty_printf(_("Note that this key cannot be used for "
+                           "encryption.  You may want to use\n"
+                           "the command \"--edit-key\" to generate a "
+                           "subkey for this purpose.\n") );
+            }
+        }
     }
 
     }
 
-    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) );
+  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) );
+      write_status_errcode (card? "card_key_generate":"key_generate", rc);
+      print_status_key_not_created ( get_parameter_value (para, pHANDLE) );
     }
     }
-    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,
-                                  get_parameter_value (para, pHANDLE));
-    }
-    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( sub_sk )
-       free_secret_key(sub_sk);
+  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,
+                                get_parameter_value (para, pHANDLE));
+    }
+  release_kbnode( pub_root );
+  release_kbnode( sec_root );
+  
+  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
 int
-generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
+generate_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock)
 {
 {
-    int okay=0, rc=0;
-    KBNODE node;
-    PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
-    int algo;
-    unsigned int use;
-    u32 expire;
-    unsigned nbits;
-    char *passphrase = NULL;
-    DEK *dek = NULL;
-    STRING2KEY *s2k = NULL;
-    u32 cur_time;
-
-    /* break out the primary secret key */
-    node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
-    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 */
-    pri_sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
-
-    cur_time = make_timestamp();
-    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 ) {
-           rc = G10ERR_TIME_CONFLICT;
-           goto leave;
-       }
+  int okay=0, rc=0;
+  KBNODE node;
+  PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
+  int algo;
+  unsigned int use;
+  u32 expire;
+  unsigned nbits;
+  char *passphrase = NULL;
+  DEK *dek = NULL;
+  STRING2KEY *s2k = NULL;
+  u32 cur_time;
+  int ask_pass = 0;
+  int canceled;
+
+  /* Break out the primary secret key.  */
+  node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
+  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. */
+  pri_sk = copy_secret_key (NULL, node->pkt->pkt.secret_key);
+
+  cur_time = make_timestamp();
+
+  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)
+        {
+          rc = G10ERR_TIME_CONFLICT;
+          goto leave;
+        }
     }
 
     }
 
-    if (pri_sk->version < 4) {
-        log_info (_("NOTE: creating subkeys for v3 keys "
-                    "is not OpenPGP compliant\n"));
-       goto leave;
+  if (pri_sk->version < 4) 
+    {
+      log_info (_("NOTE: creating subkeys for v3 keys "
+                  "is not OpenPGP compliant\n"));
+      goto leave;
     }
 
     }
 
-    /* unprotect to get the passphrase */
-    switch( is_secret_key_protected( pri_sk ) ) {
-      case -1:
-       rc = G10ERR_PUBKEY_ALGO;
-       break;
-      case 0:
-       tty_printf("This key is not protected.\n");
-       break;
-      default:
-       tty_printf("Key is protected.\n");
-       rc = check_secret_key( pri_sk, 0 );
-       if( !rc )
-           passphrase = get_last_passphrase();
-       break;
+  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;
     }
     }
-    if( rc )
-       goto leave;
 
 
-    algo = ask_algo( 1, &use );
-    assert(algo);
-    nbits = ask_keysize( algo );
-    expire = ask_expire_interval(0);
-    if( !cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
-                                                 _("Really create? (y/N) ")))
-       goto leave;
 
 
-    if( passphrase ) {
-       s2k = m_alloc_secure( sizeof *s2k );
-       s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = S2K_DIGEST_ALGO;
-       set_next_passphrase( passphrase );
-       dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2,
-                                 NULL, NULL );
-    }
-
-    rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
-                                     dek, s2k, &sub_sk, expire, 1 );
-    if( !rc )
-       rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
-    if( !rc )
-       rc = write_keybinding(sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
-    if( !rc ) {
-       okay = 1;
-        write_status_text (STATUS_KEY_CREATED, "S");
-    }
-
-  leave:
-    if( rc )
-       log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
-    m_free( passphrase );
-    m_free( dek );
-    m_free( s2k );
-    /* release the copy of the (now unprotected) secret keys */
-    if( pri_sk )
-       free_secret_key(pri_sk);
-    if( sub_sk )
-       free_secret_key(sub_sk);
-    set_next_passphrase( NULL );
-    return okay;
+  /* Unprotect to get the passphrase.  */
+  switch (is_secret_key_protected (pri_sk) )
+    {
+    case -1:
+      rc = G10ERR_PUBKEY_ALGO;
+      break;
+    case 0:
+      tty_printf (_("This key is not protected.\n"));
+      break;
+    case -2:
+      tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+      ask_pass = 1;
+      break;
+    default:
+      tty_printf (_("Key is protected.\n"));
+      rc = check_secret_key ( pri_sk, 0 );
+      if (!rc)
+        passphrase = get_last_passphrase();
+      break;
+    }
+  if (rc)
+    goto leave;
+
+  algo = ask_algo (1, NULL, &use);
+  assert (algo);
+  nbits = ask_keysize (algo, 0);
+  expire = ask_expire_interval (0, NULL);
+  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
+                                               _("Really create? (y/N) ")))
+    goto leave;
+  
+  canceled = 0;
+  if (ask_pass)
+    dek = do_ask_passphrase (&s2k, 0, &canceled);
+  else if (passphrase)
+    {
+      s2k = xmalloc_secure ( sizeof *s2k );
+      s2k->mode = opt.s2k_mode;
+      s2k->hash_algo = S2K_DIGEST_ALGO;
+      set_next_passphrase ( passphrase );
+      dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
+                               NULL, NULL );
+    }
+  
+  if (canceled)
+    rc = GPG_ERR_CANCELED;
+  
+  if (!rc)
+    rc = do_create (algo, nbits, pub_keyblock, sec_keyblock,
+                    dek, s2k, &sub_sk, cur_time, expire, 1 );
+  if (!rc)
+    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, cur_time);
+  if (!rc) 
+    {
+      okay = 1;
+      write_status_text (STATUS_KEY_CREATED, "S");
+    }
+
+ leave:
+  if (rc)
+    log_error (_("Key generation failed: %s\n"), g10_errstr(rc) );
+  xfree (passphrase);
+  xfree (dek);
+  xfree (s2k);
+  /* Release the copy of the (now unprotected) secret keys.  */
+  if (pri_sk)
+    free_secret_key (pri_sk);
+  if (sub_sk)
+    free_secret_key (sub_sk);
+  set_next_passphrase (NULL);
+  return okay;
 }
 
 
 }
 
 
@@ -3096,7 +3854,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 {
   int okay=0, rc=0;
   KBNODE node;
 {
   int okay=0, rc=0;
   KBNODE node;
-  PKT_secret_key *pri_sk = NULL;
+  PKT_secret_key *pri_sk = NULL, *sub_sk;
   int algo;
   unsigned int use;
   u32 expire;
   int algo;
   unsigned int use;
   u32 expire;
@@ -3111,8 +3869,8 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
   strcpy (para->u.value, serialno);
 
   /* Break out the primary secret key */
   strcpy (para->u.value, serialno);
 
   /* Break out the primary secret key */
-  node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
-  if(!node)
+  node = find_kbnode (sec_keyblock, PKT_SECRET_KEY);
+  if (!node)
     {
       log_error("Oops; secret key not found anymore!\n");
       goto leave;
     {
       log_error("Oops; secret key not found anymore!\n");
       goto leave;
@@ -3163,7 +3921,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
     goto leave;
 
   algo = PUBKEY_ALGO_RSA;
     goto leave;
 
   algo = PUBKEY_ALGO_RSA;
-  expire = ask_expire_interval (0);
+  expire = ask_expire_interval (0,NULL);
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
   else if (keyno == 2)
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
   else if (keyno == 2)
@@ -3176,11 +3934,17 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 
   if (passphrase)
     set_next_passphrase (passphrase);
 
   if (passphrase)
     set_next_passphrase (passphrase);
-  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock, expire, para);
+
+  /* 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, &cur_time, expire, para);
   if (!rc)
   if (!rc)
-    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, NULL, use);
+    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, 
+                           use, cur_time);
   if (!rc)
   if (!rc)
-    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, NULL, use);
+    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, 
+                           use, cur_time);
   if (!rc)
     {
       okay = 1;
   if (!rc)
     {
       okay = 1;
@@ -3190,7 +3954,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
  leave:
   if (rc)
     log_error (_("Key generation failed: %s\n"), g10_errstr(rc) );
  leave:
   if (rc)
     log_error (_("Key generation failed: %s\n"), g10_errstr(rc) );
-  m_free (passphrase);
+  xfree (passphrase);
   /* Release the copy of the (now unprotected) secret keys. */
   if (pri_sk)
     free_secret_key (pri_sk);
   /* Release the copy of the (now unprotected) secret keys. */
   if (pri_sk)
     free_secret_key (pri_sk);
@@ -3201,28 +3965,35 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 #endif /* !ENABLE_CARD_SUPPORT */
 
 
 #endif /* !ENABLE_CARD_SUPPORT */
 
 
-/****************
+/*
  * Write a keyblock to an output stream
  */
 static int
 write_keyblock( IOBUF out, KBNODE node )
 {
  * Write a keyblock to an output stream
  */
 static int
 write_keyblock( IOBUF out, KBNODE node )
 {
-    for( ; node ; node = node->next ) {
-       int rc = build_packet( out, node->pkt );
-       if( rc ) {
-           log_error("build_packet(%d) failed: %s\n",
+  for( ; node ; node = node->next )
+    {
+      if(!is_deleted_kbnode(node))
+       {
+         int rc = build_packet( out, node->pkt );
+         if( rc )
+           {
+             log_error("build_packet(%d) failed: %s\n",
                        node->pkt->pkttype, g10_errstr(rc) );
                        node->pkt->pkttype, g10_errstr(rc) );
-           return G10ERR_WRITE_FILE;
+             return rc;
+           }
        }
     }
        }
     }
-    return 0;
+
+  return 0;
 }
 
 
 }
 
 
+/* Note that timestamp is an in/out arg. */
 static int
 gen_card_key (int algo, int keyno, int is_primary,
 static int
 gen_card_key (int algo, int keyno, int is_primary,
-              KBNODE pub_root, KBNODE sec_root,
-              u32 expireval, struct para_data_s *para)
+              KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk,
+              u32 *timestamp, u32 expireval, struct para_data_s *para)
 {
 #ifdef ENABLE_CARD_SUPPORT
   int rc;
 {
 #ifdef ENABLE_CARD_SUPPORT
   int rc;
@@ -3234,8 +4005,8 @@ gen_card_key (int algo, int keyno, int is_primary,
 
   assert (algo == PUBKEY_ALGO_RSA);
   
 
   assert (algo == PUBKEY_ALGO_RSA);
   
-
-  rc = agent_scd_genkey (&info, keyno, 1);
+  /* Fixme: We don't have the serialnumber available, thus passing NULL. */
+  rc = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
 /*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
 /*      { */
 /*        tty_printf ("\n"); */
 /*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
 /*      { */
 /*        tty_printf ("\n"); */
@@ -3254,11 +4025,14 @@ gen_card_key (int algo, int keyno, int is_primary,
   if ( !info.n || !info.e )
     {
       log_error ("communication error with SCD\n");
   if ( !info.n || !info.e )
     {
       log_error ("communication error with SCD\n");
-      mpi_free (info.n);
-      mpi_free (info.e);
+      gcry_mpi_release (info.n);
+      gcry_mpi_release (info.e);
       return gpg_error (GPG_ERR_GENERAL);
     }
   
       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 );
 
   pk = xcalloc (1, sizeof *pk );
   sk = xcalloc (1, sizeof *sk );
@@ -3269,9 +4043,9 @@ gen_card_key (int algo, int keyno, int is_primary,
   sk->pubkey_algo = pk->pubkey_algo = algo;
   pk->pkey[0] = info.n;
   pk->pkey[1] = info.e; 
   sk->pubkey_algo = pk->pubkey_algo = algo;
   pk->pkey[0] = info.n;
   pk->pkey[1] = info.e; 
-  sk->skey[0] = mpi_copy (pk->pkey[0]);
-  sk->skey[1] = mpi_copy (pk->pkey[1]);
-  sk->skey[2] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+  sk->skey[0] = gcry_mpi_copy (pk->pkey[0]);
+  sk->skey[1] = gcry_mpi_copy (pk->pkey[1]);
+  sk->skey[2] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
   sk->is_protected = 1;
   sk->protect.s2k.mode = 1002;
   s = get_parameter_value (para, pSERIALNO);
   sk->is_protected = 1;
   sk->protect.s2k.mode = 1002;
   s = get_parameter_value (para, pSERIALNO);
@@ -3282,6 +4056,9 @@ gen_card_key (int algo, int keyno, int is_primary,
         sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
     }
 
         sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
     }
 
+  if( ret_sk )
+    *ret_sk = sk;
+
   pkt = xcalloc (1,sizeof *pkt);
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
   pkt = xcalloc (1,sizeof *pkt);
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
@@ -3303,6 +4080,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,
 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)
 {
                           u32 expireval, struct para_data_s *para,
                           const char *backup_dir)
 {
@@ -3310,23 +4088,39 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
   int rc;
   const char *s;
   PACKET *pkt;
   int rc;
   const char *s;
   PACKET *pkt;
-  PKT_secret_key *sk, *sk_unprotected, *sk_protected;
+  PKT_secret_key *sk, *sk_unprotected = NULL, *sk_protected = NULL;
   PKT_public_key *pk;
   size_t n;
   int i;
   PKT_public_key *pk;
   size_t n;
   int i;
+  unsigned int nbits;
+    
+  /* Get the size of the key directly from the card.  */
+  {
+    struct agent_card_info_s info;
+    
+    memset (&info, 0, sizeof info);
+    if (!agent_scd_getattr ("KEY-ATTR", &info)
+        && info.key_attr[1].algo)
+      nbits = info.key_attr[1].nbits;
+    else
+      nbits = 1024; /* All pre-v2.0 cards.  */
+    agent_release_card_info (&info);
+  }
 
 
-  rc = generate_raw_key (algo, 1024, make_timestamp (),
+  /* Create a key of this size in memory.  */
+  rc = generate_raw_key (algo, nbits, timestamp,
                          &sk_unprotected, &sk_protected);
   if (rc)
     return rc;
 
                          &sk_unprotected, &sk_protected);
   if (rc)
     return rc;
 
-  /* First, store the key to the card. */
+  /* Store the key to the card. */
   rc = save_unprotected_key_to_card (sk_unprotected, keyno);
   if (rc)
     {
       log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
       free_secret_key (sk_unprotected);
       free_secret_key (sk_protected);
   rc = save_unprotected_key_to_card (sk_unprotected, keyno);
   if (rc)
     {
       log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
       free_secret_key (sk_unprotected);
       free_secret_key (sk_protected);
+      write_status_errcode ("save_key_to_card", rc);
       return rc;
     }
 
       return rc;
     }
 
@@ -3335,11 +4129,11 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
   n = pubkey_get_nskey (sk->pubkey_algo);
   for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
     {
   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);
       sk->skey[i] = NULL;
     }
   i = pubkey_get_npkey (sk->pubkey_algo);
-  sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+  sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
   sk->is_protected = 1;
   sk->protect.s2k.mode = 1002;
   s = get_parameter_value (para, pSERIALNO);
   sk->is_protected = 1;
   sk->protect.s2k.mode = 1002;
   s = get_parameter_value (para, pSERIALNO);
@@ -3356,8 +4150,8 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
     mode_t oldmask;
 
     keyid_from_sk (sk, NULL);
     mode_t oldmask;
 
     keyid_from_sk (sk, NULL);
-    sprintf (name_buffer,"sk_%08lX%08lX.gpg",
-             (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
+    snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg",
+              (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
 
     fname = make_filename (backup_dir, name_buffer, NULL);
     oldmask = umask (077);
 
     fname = make_filename (backup_dir, name_buffer, NULL);
     oldmask = umask (077);
@@ -3371,12 +4165,13 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
     umask (oldmask);
     if (!fp) 
       {
     umask (oldmask);
     if (!fp) 
       {
+        rc = gpg_error_from_syserror ();
        log_error (_("can't create backup file `%s': %s\n"),
                    fname, strerror(errno) );
        log_error (_("can't create backup file `%s': %s\n"),
                    fname, strerror(errno) );
-        m_free (fname);
+        xfree (fname);
         free_secret_key (sk_unprotected);
         free_secret_key (sk_protected);
         free_secret_key (sk_unprotected);
         free_secret_key (sk_protected);
-        return G10ERR_OPEN_FILE;
+        return rc;
       }
 
     pkt = xcalloc (1, sizeof *pkt);
       }
 
     pkt = xcalloc (1, sizeof *pkt);
@@ -3392,13 +4187,29 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
       }
     else
       {
       }
     else
       {
+        unsigned char array[MAX_FINGERPRINT_LEN];
+        char *fprbuf, *p;
+       
         iobuf_close (fp);
         iobuf_close (fp);
-        iobuf_ioctl (NULL, 2, 0, (char*)fname);
+        iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
         log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
         log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+
+        fingerprint_from_sk (sk, array, &n);
+        p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1);
+        for (i=0; i < n ; i++, p += 2)
+          sprintf (p, "%02X", array[i]);
+        *p++ = ' ';
+        *p = 0;
+
+        write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED,
+                                      fprbuf,
+                                      fname, strlen (fname),
+                                      0);
+        xfree (fprbuf);
       }
     free_packet (pkt);
       }
     free_packet (pkt);
-    m_free (pkt);
-    m_free (fname);
+    xfree (pkt);
+    xfree (fname);
     if (rc)
       {
         free_secret_key (sk_unprotected);
     if (rc)
       {
         free_secret_key (sk_unprotected);
@@ -3440,104 +4251,70 @@ int
 save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
 {
   int rc;
 save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
 {
   int rc;
-  size_t n;
-  MPI rsa_n, rsa_e, rsa_p, rsa_q;
-  unsigned int nbits;
-  unsigned char *template = NULL;
-  unsigned char *tp;
-  unsigned char m[128], e[4];
-  size_t mlen, elen;
+  unsigned char *rsa_n = NULL;
+  unsigned char *rsa_e = NULL;
+  unsigned char *rsa_p = NULL;
+  unsigned char *rsa_q = NULL;
+  size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
+  unsigned char *sexp = NULL;
+  unsigned char *p;
+  char numbuf[55], numbuf2[50];
 
   assert (is_RSA (sk->pubkey_algo));
   assert (!sk->is_protected);
 
 
   assert (is_RSA (sk->pubkey_algo));
   assert (!sk->is_protected);
 
-  rc = -1;
-  /* Some basic checks on the key parameters. */
-  rsa_n = sk->skey[0];
-  rsa_e = sk->skey[1];
-  rsa_p = sk->skey[3];
-  rsa_q = sk->skey[4];
-
-  nbits = GET_NBITS (rsa_n);
-  if (nbits != 1024)
-    {
-      log_error (_("length of RSA modulus is not %d\n"), 1024);
-      goto leave;
-    }
-  nbits = GET_NBITS (rsa_e);
-  if (nbits < 2 || nbits > 32)
-    {
-      log_error (_("public exponent too large (more than 32 bits)\n"));
-      goto leave;
-    }
-  nbits = GET_NBITS (rsa_p);
-  if (nbits != 512)
-    {
-      log_error (_("length of an RSA prime is not %d\n"), 512);
-      goto leave;
-    }
-  nbits = GET_NBITS (rsa_q);
-  if (nbits != 512)
+  /* 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[3]);
+  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]);
+  if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
     {
     {
-      log_error (_("length of an RSA prime is not %d\n"), 512);
+      rc = G10ERR_INV_ARG;
       goto leave;
     }
 
       goto leave;
     }
 
-  
-  /* We need the modulus later to calculate the fingerprint. */
-  rc = copy_mpi (rsa_n, m, 128, &n);
-  if (rc)
-    goto leave;
-  assert (n == 128);
-  mlen = 128;
-
-  /* Build the private key template as described in section 4.3.3.6 of
-     the OpenPGP card specs:
-         0xC0   <length> public exponent
-         0xC1   <length> prime p 
-         0xC2   <length> prime q 
-  */
-  template = tp = xmalloc_secure (1+2 + 1+1+4 + 1+1+(512/8) + 1+1+(512/8));
-  *tp++ = 0xC0;
-  *tp++ = 4;
-  rc = copy_mpi (rsa_e, tp, 4, &n);
-  if (rc)
-    goto leave;
-  assert (n <= 4);
-  memcpy (e, tp, n);  /* Save a copy of the exponent for later use.  */
-  elen = n;
-  if (n != 4)
-    {
-      memmove (tp+4-n, tp, 4-n);
-      memset (tp, 0, 4-n);
-    }                 
-  tp += 4;
-
-  *tp++ = 0xC1;
-  *tp++ = 64;
-  rc = copy_mpi (rsa_p, tp, 64, &n);
-  if (rc)
-    goto leave;
-  assert (n == 64);
-  tp += 64;
-
-  *tp++ = 0xC2;
-  *tp++ = 64;
-  rc = copy_mpi (rsa_q, tp, 64, &n);
-  if (rc)
-    goto leave;
-  assert (n == 64);
-  tp += 64;
-  assert (tp - template == 138);
-
-  rc = agent_openpgp_storekey (keyno,
-                               template, tp - template,
-                               sk->timestamp,
-                               m, mlen,
-                               e, elen);
+   /* Put the key into an S-expression. */
+  sexp = p = xmalloc_secure (30
+                             + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
+                             + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
+
+  p = stpcpy (p,"(11:private-key(3:rsa(1:n");
+  sprintf (numbuf, "%u:", (unsigned int)rsa_n_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_n, rsa_n_len);
+  p += rsa_n_len;
+
+  sprintf (numbuf, ")(1:e%u:", (unsigned int)rsa_e_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_e, rsa_e_len);
+  p += rsa_e_len;
+
+  sprintf (numbuf, ")(1:p%u:", (unsigned int)rsa_p_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_p, rsa_p_len);
+  p += rsa_p_len;
+
+  sprintf (numbuf, ")(1:q%u:", (unsigned int)rsa_q_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_q, rsa_q_len);
+  p += rsa_q_len;
+
+  p = stpcpy (p,"))(10:created-at");
+  sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp);
+  sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2));
+  p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
+
+  /* Fixme: Unfortunately we don't have the serialnumber available -
+     thus we can't pass it down to the agent. */ 
+  rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
 
  leave:
 
  leave:
-  xfree (template);
+  xfree (sexp);
+  xfree (rsa_n);
+  xfree (rsa_e);
+  xfree (rsa_p);
+  xfree (rsa_q);
   return rc;
 }
 #endif /*ENABLE_CARD_SUPPORT*/
   return rc;
 }
 #endif /*ENABLE_CARD_SUPPORT*/