* keygen.c (gen_card_key): Add optional argument to return a pointer
[gnupg.git] / g10 / keygen.c
index a20c48c..d240856 100644 (file)
@@ -1,6 +1,6 @@
 /* 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 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -16,7 +16,8 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -121,6 +122,7 @@ 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,
+                        PKT_secret_key **ret_sk,
                          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,
@@ -128,42 +130,6 @@ static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
                                      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)
 {
@@ -209,11 +175,11 @@ print_status_key_not_created (const char *handle)
 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;
-    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);
@@ -225,9 +191,6 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
 {
     byte buf[1];
 
-    if (!use) 
-        return;
-
     buf[0] = 0;
 
     /* The spec says that all primary keys MUST be able to certify. */
@@ -240,6 +203,10 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
         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);
 }
 
@@ -255,7 +222,7 @@ keygen_add_key_expire( PKT_signature *sig, void *opaque )
         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;
@@ -325,7 +292,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. */
-    char dummy_string[45]; /* enough for 15 items */
+    char dummy_string[45+1]; /* Enough for 15 items. */
 
     if (!string || !ascii_strcasecmp (string, "default"))
       {
@@ -335,8 +302,21 @@ keygen_set_std_prefs (const char *string,int personal)
          {
            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
-              could overflow the size of dummy_string. */
+              could overflow the size of dummy_string.  We currently
+              have at most 12. */
            if(!check_cipher_algo(CIPHER_ALGO_AES256))
              strcat(dummy_string,"S9 ");
            if(!check_cipher_algo(CIPHER_ALGO_AES192))
@@ -356,8 +336,23 @@ keygen_set_std_prefs (const char *string,int personal)
            if(!check_cipher_algo(CIPHER_ALGO_IDEA))
              strcat(dummy_string,"S1 ");
 
-           /* SHA-1, RIPEMD160, ZLIB, ZIP */
-           strcat(dummy_string,"H2 H3 Z2 Z1");
+           /* SHA-1 */
+           strcat(dummy_string,"H2 ");
+
+           if(!check_digest_algo(DIGEST_ALGO_SHA256))
+             strcat(dummy_string,"H8 ");
+
+           /* RIPEMD160 */
+           strcat(dummy_string,"H3 ");
+
+           /* ZLIB */
+           strcat(dummy_string,"Z2 ");
+
+           if(!check_compress_algo(COMPRESS_ALGO_BZIP2))
+             strcat(dummy_string,"Z3 ");
+
+           /* ZIP */
+           strcat(dummy_string,"Z1");
 
            string=dummy_string;
          }
@@ -369,7 +364,7 @@ keygen_set_std_prefs (const char *string,int personal)
       {
        char *tok,*prefstring;
 
-       prefstring=m_strdup(string); /* need a writable string! */
+       prefstring=xstrdup(string); /* need a writable string! */
 
        while((tok=strsep(&prefstring," ,")))
          {
@@ -409,7 +404,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
          }
 
-       m_free(prefstring);
+       xfree(prefstring);
       }
 
     if(!rc)
@@ -418,7 +413,7 @@ keygen_set_std_prefs (const char *string,int personal)
          {
            if(personal==PREFTYPE_SYM)
              {
-               m_free(opt.personal_cipher_prefs);
+               xfree(opt.personal_cipher_prefs);
 
                if(nsym==0)
                  opt.personal_cipher_prefs=NULL;
@@ -427,7 +422,7 @@ keygen_set_std_prefs (const char *string,int personal)
                    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++)
                      {
@@ -441,7 +436,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
            else if(personal==PREFTYPE_HASH)
              {
-               m_free(opt.personal_digest_prefs);
+               xfree(opt.personal_digest_prefs);
 
                if(nhash==0)
                  opt.personal_digest_prefs=NULL;
@@ -450,7 +445,7 @@ keygen_set_std_prefs (const char *string,int personal)
                    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++)
                      {
@@ -464,7 +459,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
            else if(personal==PREFTYPE_ZIP)
              {
-               m_free(opt.personal_compress_prefs);
+               xfree(opt.personal_compress_prefs);
 
                if(nzip==0)
                  opt.personal_compress_prefs=NULL;
@@ -473,7 +468,7 @@ keygen_set_std_prefs (const char *string,int personal)
                    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++)
                      {
@@ -505,14 +500,14 @@ keygen_set_std_prefs (const char *string,int personal)
 PKT_user_id *keygen_get_std_prefs(void)
 {
   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);
 
   uid->ref=1;
 
-  uid->prefs=m_alloc((sizeof(prefitem_t *)*
+  uid->prefs=xmalloc((sizeof(prefitem_t *)*
                      (nsym_prefs+nhash_prefs+nzip_prefs+1)));
 
   for(i=0;i<nsym_prefs;i++,j++)
@@ -536,8 +531,8 @@ PKT_user_id *keygen_get_std_prefs(void)
   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;
 }
@@ -558,10 +553,10 @@ add_feature_mdc (PKT_signature *sig,int enabled)
 
     if (!s || !n) { /* create a new one */
         n = 1;
-        buf = m_alloc_clear (n);
+        buf = xmalloc_clear (n);
     }
     else {
-        buf = m_alloc (n);
+        buf = xmalloc (n);
         memcpy (buf, s, n);
     }
 
@@ -580,7 +575,7 @@ add_feature_mdc (PKT_signature *sig,int enabled)
     else
       build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
 
-    m_free (buf);
+    xfree (buf);
 }
 
 static void
@@ -602,10 +597,10 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
 
   if (!s || !n) { /* create a new one */
     n = 1;
-    buf = m_alloc_clear (n);
+    buf = xmalloc_clear (n);
   }
   else {
-    buf = m_alloc (n);
+    buf = xmalloc (n);
     memcpy (buf, s, n);
   }
 
@@ -624,7 +619,7 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
   else
     build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n);
 
-  m_free (buf);
+  xfree (buf);
 }
 
 int
@@ -696,6 +691,55 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
 }
 
 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;
@@ -717,26 +761,18 @@ keygen_add_revkey(PKT_signature *sig, void *opaque)
   return 0;
 }
 
-static int
-make_backsig(PKT_signature *sig, PKT_public_key *pk,
-            PKT_public_key *sub_pk, PKT_secret_key *sub_sk)
+int
+make_backsig(PKT_signature *sig,PKT_public_key *pk,
+            PKT_public_key *sub_pk,PKT_secret_key *sub_sk)
 {
   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,0,0,NULL,NULL);
+  if(rc)
+    log_error("make_keysig_packet failed for backsig: %s\n",g10_errstr(rc));
   else
     {
       /* get it into a binary packed form. */
@@ -846,7 +882,7 @@ write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
        return rc;
     }
 
-    pkt = m_alloc_clear( sizeof *pkt );
+    pkt = xmalloc_clear( sizeof *pkt );
     pkt->pkttype = PKT_SIGNATURE;
     pkt->pkt.signature = sig;
     add_kbnode( root, new_kbnode( pkt ) );
@@ -854,8 +890,8 @@ write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
 }
 
 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 )
 {
     PACKET *pkt;
     PKT_signature *sig;
@@ -868,7 +904,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
        log_info(_("writing self signature\n"));
 
     /* get the uid packet from the list */
-    node = find_kbnode( root, PKT_USER_ID );
+    node = find_kbnode( pub_root, PKT_USER_ID );
     if( !node )
        BUG(); /* no user id packet in tree */
     uid = node->pkt->pkt.user_id;
@@ -890,14 +926,18 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
        return rc;
     }
 
-    pkt = m_alloc_clear( sizeof *pkt );
+    pkt = xmalloc_clear( sizeof *pkt );
     pkt->pkttype = PKT_SIGNATURE;
     pkt->pkt.signature = sig;
-    add_kbnode( root, new_kbnode( pkt ) );
+    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) */
 static int
 write_keybinding( KBNODE root, KBNODE pub_root,
                  PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
@@ -949,7 +989,7 @@ write_keybinding( KBNODE root, KBNODE pub_root,
          return rc;
       }
 
-    pkt = m_alloc_clear( sizeof *pkt );
+    pkt = xmalloc_clear( sizeof *pkt );
     pkt->pkttype = PKT_SIGNATURE;
     pkt->pkt.signature = sig;
     add_kbnode( root, new_kbnode( pkt ) );
@@ -962,7 +1002,6 @@ 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)
 {
     int rc;
-    int i;
     PACKET *pkt;
     PKT_secret_key *sk;
     PKT_public_key *pk;
@@ -987,8 +1026,8 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        return rc;
     }
 
-    sk = m_alloc_clear( sizeof *sk );
-    pk = m_alloc_clear( sizeof *pk );
+    sk = xmalloc_clear( sizeof *sk );
+    pk = xmalloc_clear( sizeof *pk );
     sk->timestamp = pk->timestamp = make_timestamp();
     sk->version = pk->version = 4;
     if( expireval ) {
@@ -1021,20 +1060,17 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        }
     }
 
-    pkt = m_alloc_clear(sizeof *pkt);
+    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) */
-    pkt = m_alloc_clear(sizeof *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 ));
-    for(i=0; factors[i]; i++ )
-       add_kbnode( sec_root,
-                   make_mpi_comment_node("#:ELG_factor:", factors[i] ));
 
     return 0;
 }
@@ -1048,36 +1084,70 @@ 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)
 {
     int rc;
-    int i;
     PACKET *pkt;
     PKT_secret_key *sk;
     PKT_public_key *pk;
     MPI skey[5];
     MPI *factors;
+    unsigned int qbits;
 
-    if( nbits > 1024 || nbits < 512 ) {
+    if( nbits < 512 || (!opt.flags.dsa2 && nbits > 1024))
+      {
        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) ) {
+    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) );
+    /*
+      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 2048, 224 for nbits over 1024
+      but less than 2048, and 160 for 1024 (DSA1).
+    */
+
+    if(nbits>2048)
+      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 = dsa2_generate( PUBKEY_ALGO_DSA, nbits, qbits, skey, &factors );
+    if( rc )
+      {
+       log_error("dsa2_generate failed: %s\n", g10_errstr(rc) );
        return rc;
-    }
+      }
 
-    sk = m_alloc_clear( sizeof *sk );
-    pk = m_alloc_clear( sizeof *pk );
+    sk = xmalloc_clear( sizeof *sk );
+    pk = xmalloc_clear( sizeof *pk );
     sk->timestamp = pk->timestamp = make_timestamp();
     sk->version = pk->version = 4;
-    if( expireval ) {
-       sk->expiredate = pk->expiredate = sk->timestamp + expireval;
-    }
+    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] );
@@ -1107,7 +1177,7 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        }
     }
 
-    pkt = m_alloc_clear(sizeof *pkt);
+    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 ));
@@ -1118,13 +1188,10 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
      * 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 = 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 ));
-    for(i=1; factors[i]; i++ ) /* the first one is q */
-       add_kbnode( sec_root,
-                   make_mpi_comment_node("#:DSA_factor:", factors[i] ));
 
     return 0;
 }
@@ -1162,8 +1229,8 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        return rc;
     }
 
-    sk = m_alloc_clear( sizeof *sk );
-    pk = m_alloc_clear( sizeof *pk );
+    sk = xmalloc_clear( sizeof *sk );
+    pk = xmalloc_clear( sizeof *pk );
     sk->timestamp = pk->timestamp = make_timestamp();
     sk->version = pk->version = 4;
     if( expireval ) {
@@ -1200,12 +1267,12 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
        }
     }
 
-    pkt = m_alloc_clear(sizeof *pkt);
+    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 = m_alloc_clear(sizeof *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 ));
@@ -1248,6 +1315,9 @@ print_key_flags(int flags)
   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"));
 
@@ -1258,7 +1328,7 @@ print_key_flags(int flags)
 
 /* Returns the key flags */
 static unsigned int
-ask_key_flags(int algo)
+ask_key_flags(int algo,int subkey)
 {
   const char *togglers=_("SsEeAaQq");
   char *answer=NULL;
@@ -1268,6 +1338,10 @@ ask_key_flags(int algo)
   if(strlen(togglers)!=8)
     BUG();
 
+  /* 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. */
   current=possible&~PUBKEY_USAGE_AUTH;
@@ -1296,12 +1370,12 @@ ask_key_flags(int algo)
       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)
-       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])
@@ -1328,9 +1402,11 @@ ask_key_flags(int algo)
          else
            current|=PUBKEY_USAGE_AUTH;
        }
+      else
+       tty_printf(_("Invalid selection.\n"));
     }
 
-  m_free(answer);
+  xfree(answer);
 
   return current;
 }
@@ -1365,14 +1441,14 @@ ask_algo (int addmode, unsigned int *r_usage)
        answer = cpr_get("keygen.algo",_("Your selection? "));
        cpr_kill_prompt();
        algo = *answer? atoi(answer): 1;
-       m_free(answer);
+       xfree(answer);
        if( algo == 1 && !addmode ) {
            algo = 0;   /* create both keys */
            break;
        }
        else if( algo == 7 && opt.expert ) {
            algo = PUBKEY_ALGO_RSA;
-           *r_usage=ask_key_flags(algo);
+           *r_usage=ask_key_flags(algo,addmode);
            break;
        }
        else if( algo == 6 && addmode ) {
@@ -1392,7 +1468,7 @@ ask_algo (int addmode, unsigned int *r_usage)
        }
        else if( algo == 3 && opt.expert ) {
            algo = PUBKEY_ALGO_DSA;
-           *r_usage=ask_key_flags(algo);
+           *r_usage=ask_key_flags(algo,addmode);
            break;
        }
        else if( algo == 2 ) {
@@ -1421,10 +1497,10 @@ ask_keysize( int algo )
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      if(opt.expert)
+      if(opt.flags.dsa2)
        {
          def=1024;
-         max=1024;
+         max=3072;
        }
       else
        {
@@ -1447,7 +1523,7 @@ ask_keysize( int algo )
 
 #define PROMPTSTRING _("What keysize do you want? (%u) ")
 
-      prompt=m_alloc(strlen(PROMPTSTRING)+20);
+      prompt=xmalloc(strlen(PROMPTSTRING)+20);
       sprintf(prompt,PROMPTSTRING,def);
 
 #undef PROMPTSTRING
@@ -1455,8 +1531,8 @@ ask_keysize( int algo )
       answer = cpr_get("keygen.size",prompt);
       cpr_kill_prompt();
       nbits = *answer? atoi(answer): def;
-      m_free(prompt);
-      m_free(answer);
+      xfree(prompt);
+      xfree(answer);
       
       if(nbits<min || nbits>max)
        tty_printf(_("%s keysizes must be in the range %u-%u\n"),
@@ -1483,50 +1559,47 @@ 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 )
 {
     int mult;
-    u32 abs_date=0;
-    u32 curtime = make_timestamp();
-    int valid_days;
+    u32 seconds,abs_date=0,curtime = make_timestamp();
 
     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;
-    }
-    return valid_days;
+      seconds = 0;
+    else if ( !strncmp (string, "seconds=", 8) )
+      seconds = atoi (string+8);
+    else if( (abs_date = scan_isodatestr(string)) && abs_date > curtime )
+      seconds = abs_date - curtime;
+    else if( (mult=check_valid_days(string)) )
+      seconds = atoi(string) * 86400L * mult;
+    else
+      seconds=(u32)-1;
+
+    return seconds;
 }
 
 /* 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;
-    int valid_days=0;
-    u32 interval = 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"
@@ -1536,6 +1609,8 @@ ask_expire_interval(int object)
        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"
@@ -1553,80 +1628,75 @@ ask_expire_interval(int object)
      * date */
 
     answer = NULL;
-    for(;;) {
+    for(;;)
+      {
        u32 curtime=make_timestamp();
 
-       m_free(answer);
+       xfree(answer);
        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);
-       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;
-       }
+         }
 
-       if( !valid_days )
+       if( !interval )
          {
             tty_printf((object==0)
                        ? _("Key does not expire at all\n")
                        : _("Signature does not expire at all\n"));
-           interval = 0;
          }
-       else {
-           interval = valid_days * 86400L;
-
+       else
+         {
            tty_printf(object==0
-                       ? _("Key expires at %s\n")
+                      ? _("Key expires at %s\n")
                       : _("Signature expires at %s\n"),
-                       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 */
+                      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"));
-       }
+             tty_printf(_("Your system can't display dates beyond 2038.\n"
+                          "However, it will be correctly handled up to 2106.\n"));
+         }
 
        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()
 {
-    u32 x = ask_expire_interval(0);
+    u32 x = ask_expire_interval(0,NULL);
     return x? make_timestamp() + x : 0;
 }
 
-static int
-has_invalid_email_chars( const char *s )
-{
-    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;
-}
-
 
 static char *
 ask_user_id( int mode )
@@ -1636,7 +1706,8 @@ ask_user_id( int mode )
 
     if( !mode )
        tty_printf( _("\n"
-"You need a user ID to identify your key; the software constructs the user ID\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"
 "    \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
     uid = aname = acomment = amail = NULL;
@@ -1646,7 +1717,7 @@ ask_user_id( int mode )
 
        if( !aname ) {
            for(;;) {
-               m_free(aname);
+               xfree(aname);
                aname = cpr_get("keygen.name",_("Real name: "));
                trim_spaces(aname);
                cpr_kill_prompt();
@@ -1666,26 +1737,21 @@ ask_user_id( int mode )
        }
        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 */
-               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(;;) {
-               m_free(acomment);
+               xfree(acomment);
                acomment = cpr_get("keygen.comment",_("Comment: "));
                trim_spaces(acomment);
                cpr_kill_prompt();
@@ -1699,8 +1765,8 @@ 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),")");
@@ -1731,7 +1797,7 @@ ask_user_id( int mode )
        }
 
        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.
@@ -1747,7 +1813,7 @@ ask_user_id( int mode )
            if( strlen(ansstr) != 10 )
                BUG();
            if( cpr_enabled() ) {
-               answer = m_strdup(ansstr+6);
+               answer = xstrdup(ansstr+6);
                answer[1] = 0;
            }
            else {
@@ -1759,15 +1825,15 @@ ask_user_id( int mode )
            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] ) {
-               m_free(acomment); acomment = NULL;
+               xfree(acomment); acomment = NULL;
                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] ) {
@@ -1775,29 +1841,29 @@ ask_user_id( int mode )
                    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] ) {
-               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;
            }
-           m_free(answer);
+           xfree(answer);
        }
-       m_free(answer);
+       xfree(answer);
        if( !amail && !acomment && !amail )
            break;
-       m_free(uid); uid = NULL;
+       xfree(uid); uid = NULL;
     }
     if( uid ) {
        char *p = native_to_utf8( uid );
-       m_free( uid );
+       xfree( uid );
        uid = p;
     }
     return uid;
@@ -1814,7 +1880,7 @@ do_ask_passphrase( STRING2KEY **ret_s2k )
 
     tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
 
-    s2k = m_alloc_secure( sizeof *s2k );
+    s2k = xmalloc_secure( sizeof *s2k );
     for(;;) {
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
@@ -1825,8 +1891,8 @@ do_ask_passphrase( STRING2KEY **ret_s2k )
            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"
@@ -1867,16 +1933,6 @@ do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
   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;
 }
 
@@ -1895,7 +1951,7 @@ generate_user_id()
     if( !p )
        return NULL;
     n = strlen(p);
-    uid = m_alloc_clear( sizeof *uid + n - 1 );
+    uid = xmalloc_clear( sizeof *uid + n - 1 );
     uid->len = n;
     strcpy(uid->name, p);
     uid->ref = 1;
@@ -1911,11 +1967,11 @@ release_parameter_list( struct para_data_s *r )
     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 )
-           m_free( r->u.s2k );
+           xfree( r->u.s2k );
 
-       m_free(r);
+       xfree(r);
     }
 }
 
@@ -1983,7 +2039,7 @@ parse_parameter_usage (const char *fname,
         }
     }
     r->u.usage = use;
-    return 0;
+    return 1;
 }
 
 static int
@@ -2086,118 +2142,166 @@ static int
 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 have_user_id=0,err,algo;
 
-    /* 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;
+  /* Check that we have all required parameters. */
+  r = get_parameter( para, pKEYTYPE );
+  if(r)
+    {
+      algo=get_parameter_algo(para,pKEYTYPE);
+      if(check_pubkey_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;
     }
 
-    if (parse_parameter_usage (fname, para, pKEYUSAGE))
-        return -1;
+  err=parse_parameter_usage (fname, para, pKEYUSAGE);
+  if(err==0)
+    {
+      /* Default to algo capabilities if key-usage is not provided */
+      r=xmalloc_clear(sizeof(*r));
+      r->key=pKEYUSAGE;
+      r->u.usage=openpgp_pk_algo_usage(algo);
+      r->next=para;
+      para=r;
+    }
+  else if(err==-1)
+    return -1;
+
+  r = get_parameter( para, pSUBKEYTYPE );
+  if(r)
+    {
+      algo=get_parameter_algo( para, pSUBKEYTYPE);
+      if(check_pubkey_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==0)
+       {
+         /* Default to algo capabilities if subkey-usage is not
+            provided */
+         r=xmalloc_clear(sizeof(*r));
+         r->key=pSUBKEYUSAGE;
+         r->u.usage=openpgp_pk_algo_usage(algo);
+         r->next=para;
+         para=r;
+       }
+      else if(err==-1)
        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;
+    }
 
-    /* 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 revoker, if any. */
+  if (parse_revocation_key (fname, para, pREVOKER))
+    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;
+
+    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 )
+    {
+      u32 seconds;
 
-    /* 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;
+      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 = 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.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;
     }
 
-    if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) {
-       log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr );
-       return -1;
-    }
+  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;
+  do_generate_keypair( para, outctrl, card );
+  return 0;
 }
 
 
@@ -2299,8 +2403,8 @@ read_parameter_file( const char *fname )
                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;
                }
            }
@@ -2308,8 +2412,8 @@ read_parameter_file( const char *fname )
                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;
                }
            }
@@ -2367,7 +2471,7 @@ read_parameter_file( const char *fname )
                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 );
@@ -2395,10 +2499,10 @@ read_parameter_file( const char *fname )
         if (outctrl.sec.fname)
           iobuf_ioctl (NULL, 2, 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 );
@@ -2500,30 +2604,30 @@ generate_keypair (const char *fname, const char *card_serialno,
       if( !algo )
         { /* default: DSA with ElG subkey of the specified size */
           both = 1;
-          r = m_alloc_clear( sizeof *r + 20 );
+          r = xmalloc_clear( sizeof *r + 20 );
           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" );
-          r->next = para;
-          para = r;
-          r = m_alloc_clear( sizeof *r + 20 );
+         nbits = ask_keysize( PUBKEY_ALGO_DSA );
+         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;
            
           algo = PUBKEY_ALGO_ELGAMAL_E;
-          r = m_alloc_clear( sizeof *r + 20 );
+          r = xmalloc_clear( sizeof *r + 20 );
           r->key = pSUBKEYTYPE;
           sprintf( r->u.value, "%d", algo );
           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;
@@ -2531,7 +2635,7 @@ generate_keypair (const char *fname, const char *card_serialno,
         }
       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;
@@ -2539,7 +2643,7 @@ generate_keypair (const char *fname, const char *card_serialno,
            
           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 ":"",
@@ -2550,22 +2654,22 @@ generate_keypair (const char *fname, const char *card_serialno,
             }
            
         }
-       
+
       nbits = ask_keysize( algo );
-      r = m_alloc_clear( sizeof *r + 20 );
+      r = xmalloc_clear( sizeof *r + 20 );
       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 = m_alloc_clear( sizeof *r + 20 );
+  r = xmalloc_clear( sizeof *r + 20 );
   r->key = pSUBKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
@@ -2578,7 +2682,7 @@ generate_keypair (const char *fname, const char *card_serialno,
       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;
@@ -2587,12 +2691,12 @@ generate_keypair (const char *fname, const char *card_serialno,
   dek = card_serialno? NULL : do_ask_passphrase( &s2k );
   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 = m_alloc_clear( sizeof *r );
+      r = xmalloc_clear( sizeof *r );
       r->key = pPASSPHRASE_S2K;
       r->u.s2k = s2k;
       r->next = para;
@@ -2639,7 +2743,7 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
 
   dek = do_ask_passphrase (&s2k);
 
-  sk = m_alloc_clear (sizeof *sk);
+  sk = xmalloc_clear (sizeof *sk);
   sk->timestamp = created_at;
   sk->version = 4;
   sk->pubkey_algo = algo;
@@ -2677,12 +2781,23 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
  leave:
   if (sk)
     free_secret_key (sk);
-  m_free (dek);
-  m_free (s2k);
+  xfree (dek);
+  xfree (s2k);
   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
 do_generate_keypair( struct para_data_s *para,
@@ -2696,11 +2811,11 @@ do_generate_keypair( struct para_data_s *para,
     int rc;
     int did_sub = 0;
 
-    if( outctrl->dryrun ) {
+    if( outctrl->dryrun )
+      {
        log_info("dry-run mode - key generation skipped\n");
        return;
-    }
-
+      }
 
     if( outctrl->use_files ) {
        if( outctrl->pub.newfname ) {
@@ -2708,7 +2823,7 @@ do_generate_keypair( struct para_data_s *para,
            outctrl->pub.stream = NULL;
             if (outctrl->pub.fname)
               iobuf_ioctl (NULL, 2, 0, (char*)outctrl->pub.fname);
-           m_free( outctrl->pub.fname );
+           xfree( outctrl->pub.fname );
            outctrl->pub.fname =  outctrl->pub.newfname;
            outctrl->pub.newfname = NULL;
 
@@ -2736,7 +2851,7 @@ do_generate_keypair( struct para_data_s *para,
            outctrl->sec.stream = NULL;
             if (outctrl->sec.fname)
               iobuf_ioctl (NULL, 2, 0, (char*)outctrl->sec.fname);
-           m_free( outctrl->sec.fname );
+           xfree( outctrl->sec.fname );
            outctrl->sec.fname =  outctrl->sec.newfname;
            outctrl->sec.newfname = NULL;
 
@@ -2772,13 +2887,14 @@ do_generate_keypair( struct para_data_s *para,
     }
 
 
-    /* we create the packets as a tree of kbnodes. Because the structure
-     * we create is known in advance we simply generate a linked list
-     * The first packet is a dummy comment packet which we flag
+    /* 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.
      */
-    pub_root = make_comment_node("#"); delete_kbnode(pub_root);
-    sec_root = make_comment_node("#"); delete_kbnode(sec_root);
+    
+    start_tree(&pub_root);
+    start_tree(&sec_root);
 
     if (!card)
       {
@@ -2792,7 +2908,7 @@ do_generate_keypair( struct para_data_s *para,
       }
     else
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root,
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL,
                            get_parameter_u32 (para, pKEYEXPIRE), para);
         if (!rc)
           {
@@ -2808,17 +2924,34 @@ do_generate_keypair( struct para_data_s *para,
          write_direct_sig(sec_root,pub_root,pri_sk,revkey);
       }
 
-    if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
+    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));
+         write_uid(sec_root, s );
+
        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));
+      }
+
+    /* 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 (!rc && card && get_parameter (para, pAUTHKEYTYPE))
+      {
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root, NULL,
+                           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 && get_parameter( para, pSUBKEYTYPE ) )
       {
@@ -2847,6 +2980,7 @@ do_generate_keypair( struct para_data_s *para,
               }
             else
               rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
+                                NULL,
                                  get_parameter_u32 (para, pKEYEXPIRE), para);
           }
 
@@ -2859,17 +2993,6 @@ do_generate_keypair( struct para_data_s *para,
         did_sub = 1;
       }
 
-    if (!rc && 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)
-          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 )
@@ -3002,6 +3125,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     DEK *dek = NULL;
     STRING2KEY *s2k = NULL;
     u32 cur_time;
+    int ask_pass = 0;
 
     /* break out the primary secret key */
     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
@@ -3032,20 +3156,31 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
        goto leave;
     }
 
-    /* unprotect to get the passphrase */
+    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;
+    }
+
+
+    /* 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");
+       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;
+        tty_printf(_("Key is protected.\n"));
+        rc = check_secret_key( pri_sk, 0 );
+        if( !rc )
+            passphrase = get_last_passphrase();
+        break;
     }
     if( rc )
        goto leave;
@@ -3053,13 +3188,15 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     algo = ask_algo( 1, &use );
     assert(algo);
     nbits = ask_keysize( algo );
-    expire = ask_expire_interval(0);
+    expire = ask_expire_interval(0,NULL);
     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 );
+    if (ask_pass)
+        dek = do_ask_passphrase (&s2k);
+    else if (passphrase) {
+       s2k = xmalloc_secure( sizeof *s2k );
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
        set_next_passphrase( passphrase );
@@ -3068,7 +3205,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     }
 
     rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
-                                     dek, s2k, &sub_sk, expire, 1 );
+                   dek, s2k, &sub_sk, expire, 1 );
     if( !rc )
        rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
     if( !rc )
@@ -3081,9 +3218,9 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
   leave:
     if( rc )
        log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
-    m_free( passphrase );
-    m_free( dek );
-    m_free( s2k );
+    xfree( passphrase );
+    xfree( dek );
+    xfree( s2k );
     /* release the copy of the (now unprotected) secret keys */
     if( pri_sk )
        free_secret_key(pri_sk);
@@ -3102,7 +3239,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 {
   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;
@@ -3169,7 +3306,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
     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)
@@ -3182,11 +3319,12 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 
   if (passphrase)
     set_next_passphrase (passphrase);
-  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock, expire, para);
+  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock,
+                    &sub_sk, expire, para);
   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);
   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);
   if (!rc)
     {
       okay = 1;
@@ -3196,7 +3334,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
  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);
@@ -3213,21 +3351,27 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 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) );
-           return G10ERR_WRITE_FILE;
+             return G10ERR_WRITE_FILE;
+           }
        }
     }
-    return 0;
+
+  return 0;
 }
 
 
 static int
 gen_card_key (int algo, int keyno, int is_primary,
-              KBNODE pub_root, KBNODE sec_root,
+              KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk,
               u32 expireval, struct para_data_s *para)
 {
 #ifdef ENABLE_CARD_SUPPORT
@@ -3240,8 +3384,8 @@ gen_card_key (int algo, int keyno, int is_primary,
 
   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);
 /*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
 /*      { */
 /*        tty_printf ("\n"); */
@@ -3288,6 +3432,9 @@ gen_card_key (int algo, int keyno, int is_primary,
         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;
@@ -3379,7 +3526,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
       {
        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);
         return G10ERR_OPEN_FILE;
@@ -3398,13 +3545,29 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
       }
     else
       {
+        byte array[MAX_FINGERPRINT_LEN];
+        char *fprbuf, *p;
+       
         iobuf_close (fp);
         iobuf_ioctl (NULL, 2, 0, (char*)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);
-    m_free (pkt);
-    m_free (fname);
+    xfree (pkt);
+    xfree (fname);
     if (rc)
       {
         free_secret_key (sk_unprotected);
@@ -3446,104 +3609,70 @@ int
 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;
+  unsigned int 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);
 
-  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. */
+  rsa_n = mpi_get_secure_buffer (sk->skey[0], &rsa_n_len, NULL);
+  rsa_e = mpi_get_secure_buffer (sk->skey[1], &rsa_e_len, NULL);
+  rsa_p = mpi_get_secure_buffer (sk->skey[3], &rsa_p_len, NULL);
+  rsa_q = mpi_get_secure_buffer (sk->skey[4], &rsa_q_len, NULL);
+  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;
     }
 
-  
-  /* 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;
+  /* 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);
 
-  *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);
+  p = stpcpy (p,"(11:private-key(3:rsa(1:n");
+  sprintf (numbuf, "%u:", rsa_n_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_n, rsa_n_len);
+  p += rsa_n_len;
+
+  sprintf (numbuf, ")(1:e%u:", rsa_e_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_e, rsa_e_len);
+  p += rsa_e_len;
+
+  sprintf (numbuf, ")(1:p%u:", rsa_p_len);
+  p = stpcpy (p, numbuf);
+  memcpy (p, rsa_p, rsa_p_len);
+  p += rsa_p_len;
+
+  sprintf (numbuf, ")(1:q%u:", 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), "))");
 
-  rc = agent_openpgp_storekey (keyno,
-                               template, tp - template,
-                               sk->timestamp,
-                               m, mlen,
-                               e, elen);
+  /* 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:
-  xfree (template);
+  xfree (sexp);
+  xfree (rsa_n);
+  xfree (rsa_e);
+  xfree (rsa_p);
+  xfree (rsa_q);
   return rc;
 }
 #endif /*ENABLE_CARD_SUPPORT*/