another s/unsigned char*/byte*/
[gnupg.git] / g10 / keygen.c
index 970d476..c53256c 100644 (file)
@@ -1,6 +1,6 @@
 /* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- *                                               Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -26,6 +26,9 @@
 #include <ctype.h>
 #include <errno.h>
 #include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include "util.h"
 #include "main.h"
 #include "packet.h"
@@ -60,7 +63,9 @@ enum para_name {
   pPASSPHRASE,
   pPASSPHRASE_DEK,
   pPASSPHRASE_S2K,
-  pSERIALNO
+  pSERIALNO,
+  pBACKUPENCDIR,
+  pHANDLE
 };
 
 struct para_data_s {
@@ -114,8 +119,92 @@ static int mdc_available,ks_modify;
 static void do_generate_keypair( struct para_data_s *para,
                                 struct output_control_s *outctrl, int card );
 static int  write_keyblock( IOBUF out, KBNODE node );
-static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+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);
+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,
+                                     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)
+{
+  byte array[MAX_FINGERPRINT_LEN], *s;
+  char *buf, *p;
+  size_t i, n;
+  
+  if (!handle)
+    handle = "";
+
+  buf = xmalloc (MAX_FINGERPRINT_LEN*2+31 + strlen (handle) + 1);
+
+  p = buf;
+  if (letter || pk)
+    {
+      *p++ = letter;
+      *p++ = ' ';
+      fingerprint_from_pk (pk, array, &n);
+      s = array;
+      for (i=0; i < n ; i++, s++, p += 2)
+        sprintf (p, "%02X", *s);
+    }
+  if (*handle)
+    {
+      *p++ = ' ';
+      for (i=0; handle[i] && i < 100; i++)
+        *p++ = isspace ((unsigned int)handle[i])? '_':handle[i];
+    }
+  *p = 0;
+  write_status_text ((letter || pk)?STATUS_KEY_CREATED:STATUS_KEY_NOT_CREATED,
+                     buf);
+  xfree (buf);
+}
+
+static void
+print_status_key_not_created (const char *handle)
+{
+  print_status_key_created (0, NULL, handle);
+}
+
+
 
 static void
 write_uid( KBNODE root, const char *s )
@@ -140,13 +229,13 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
         return;
 
     buf[0] = 0;
+
+    /* The spec says that all primary keys MUST be able to certify. */
+    if(sig->sig_class!=0x18)
+      buf[0] |= 0x01;
+
     if (use & PUBKEY_USAGE_SIG)
-      {
-       if(sig->sig_class==0x18)
-         buf[0] |= 0x02; /* Don't set the certify flag for subkeys */
-       else
-         buf[0] |= 0x01 | 0x02;
-      }
+      buf[0] |= 0x02;
     if (use & PUBKEY_USAGE_ENC)
         buf[0] |= 0x04 | 0x08;
     if (use & PUBKEY_USAGE_AUTH)
@@ -223,18 +312,6 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
     return 0;
 }
 
-#ifdef USE_AES
-#define AES "S9 S8 S7 "
-#else
-#define AES ""
-#endif
-
-#ifdef USE_CAST5
-#define CAST5 "S3 "
-#else
-#define CAST5 ""
-#endif
-
 /*
  * Parse the supplied string and use it to set the standard
  * preferences.  The string may be in a form like the one printed by
@@ -248,23 +325,43 @@ 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 */
 
-    if (!string || !ascii_strcasecmp (string, "default")) {
-      if (opt.def_preference_list)
-       string=opt.def_preference_list;
-      else if ( !check_cipher_algo(CIPHER_ALGO_IDEA) )
-        string = AES CAST5 "S2 S1 H2 H3 Z2 Z1";
-      else
-        string = AES CAST5 "S2 H2 H3 Z2 Z1";
-
-      /* If we have it, IDEA goes *after* 3DES so it won't be used
-         unless we're encrypting along with a V3 key.  Ideally, we
-         would only put the S1 preference in if the key was RSA and
-         <=2048 bits, as that is what won't 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 (!string || !ascii_strcasecmp (string, "default"))
+      {
+       if (opt.def_preference_list)
+         string=opt.def_preference_list;
+       else
+         {
+           dummy_string[0]='\0';
+
+           /* 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))
+             strcat(dummy_string,"S9 ");
+           if(!check_cipher_algo(CIPHER_ALGO_AES192))
+             strcat(dummy_string,"S8 ");
+           if(!check_cipher_algo(CIPHER_ALGO_AES))
+             strcat(dummy_string,"S7 ");
+           if(!check_cipher_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
+              used unless we're encrypting along with a V3 key.
+              Ideally, we would only put the S1 preference in if the
+              key was RSA and <=2048 bits, as that is what won't
+              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))
+             strcat(dummy_string,"S1 ");
+
+           /* SHA-1, RIPEMD160, ZLIB, ZIP */
+           strcat(dummy_string,"H2 H3 Z2 Z1");
+
+           string=dummy_string;
+         }
+      }
     else if (!ascii_strcasecmp (string, "none"))
         string = "";
 
@@ -403,9 +500,6 @@ keygen_set_std_prefs (const char *string,int personal)
     return rc;
 }
 
-#undef CAST5
-#undef AES
-
 /* Return a fake user ID containing the preferences.  Caller must
    free. */
 PKT_user_id *keygen_get_std_prefs(void)
@@ -591,7 +685,10 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
 {
   const char *url=opaque;
 
-  build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url));
+  if(url)
+    build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url));
+  else
+    delete_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS);
 
   return 0;
 }
@@ -619,6 +716,104 @@ keygen_add_revkey(PKT_signature *sig, void *opaque)
 }
 
 static 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);
+
+  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. */
+      IOBUF backsig_out=iobuf_temp();
+      PACKET backsig_pkt;
+      init_packet(&backsig_pkt);
+      backsig_pkt.pkttype=PKT_SIGNATURE;
+      backsig_pkt.pkt.signature=backsig;
+      rc=build_packet(backsig_out,&backsig_pkt);
+      free_packet(&backsig_pkt);
+      if(rc)
+       log_error("build_packet failed for backsig: %s\n",g10_errstr(rc));
+      else
+       {
+         size_t pktlen=0;
+         byte *buf=iobuf_get_temp_buffer(backsig_out);
+         /* Remove the packet header */
+         if(buf[0]&0x40)
+           {
+             if(buf[1]<192)
+               {
+                 pktlen=buf[1];
+                 buf+=2;
+               }
+             else if(buf[1]<224)
+               {
+                 pktlen=(buf[1]-192)*256;
+                 pktlen+=buf[2]+192;
+                 buf+=3;
+               }
+             else if(buf[1]==255)
+               {
+                 pktlen =buf[2] << 24;
+                 pktlen|=buf[3] << 16;
+                 pktlen|=buf[4] << 8;
+                 pktlen|=buf[5];
+                 buf+=6;
+               }
+             else
+               BUG();
+           }
+         else
+           {
+             int mark=1;
+             switch(buf[0]&3)
+               {
+               case 3:
+                 BUG();
+                 break;
+               case 2:
+                 pktlen =buf[mark++] << 24;
+                 pktlen|=buf[mark++] << 16;
+               case 1:
+                 pktlen|=buf[mark++] << 8;
+               case 0:
+                 pktlen|=buf[mark++];
+               }
+             buf+=mark;
+           }
+         /* now make the binary blob into a subpacket */
+         build_sig_subpkt(sig,SIGSUBPKT_SIGNATURE,buf,pktlen);
+
+         iobuf_close(backsig_out);
+       }
+    }
+  return rc;
+}
+
+
+static int
 write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
                  struct revocation_key *revkey )
 {
@@ -700,15 +895,17 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
     return rc;
 }
 
+/* sub_sk is currently unused (reserved for backsigs) */
 static int
-write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
+write_keybinding( KBNODE root, KBNODE pub_root,
+                 PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
                   unsigned int use )
 {
     PACKET *pkt;
     PKT_signature *sig;
     int rc=0;
     KBNODE node;
-    PKT_public_key *pk, *subpk;
+    PKT_public_key *pri_pk, *sub_pk;
     struct opaque_data_usage_and_pk oduap;
 
     if( opt.verbose )
@@ -718,30 +915,38 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
     node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
     if( !node )
        BUG();
-    pk = node->pkt->pkt.public_key;
+    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 (pk);
+    cache_public_key (pri_pk);
  
     /* find the last subkey */
-    subpk = NULL;
+    sub_pk = NULL;
     for(node=pub_root; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           subpk = node->pkt->pkt.public_key;
+           sub_pk = node->pkt->pkt.public_key;
     }
-    if( !subpk )
+    if( !sub_pk )
        BUG();
 
     /* and make the signature */
     oduap.usage = use;
-    oduap.pk = subpk;
-    rc = make_keysig_packet( &sig, pk, NULL, subpk, sk, 0x18, 0, 0, 0, 0,
-                            keygen_add_key_flags_and_expire, &oduap );
+    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 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;
@@ -752,7 +957,7 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
 
 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 )
+       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
 {
     int rc;
     int i;
@@ -799,7 +1004,7 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     sk->protect.algo = 0;
 
     sk->csum = checksum_mpi( sk->skey[3] );
-    if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
+    if( ret_sk ) /* return an unprotected version of the sk */
        *ret_sk = copy_secret_key( NULL, sk );
 
     if( dek ) {
@@ -815,14 +1020,14 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     }
 
     pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+    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 = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+    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++ )
@@ -838,7 +1043,7 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
  */
 static int
 gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
-           STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
+       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
 {
     int rc;
     int i;
@@ -885,7 +1090,7 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     sk->protect.algo = 0;
 
     sk->csum = checksum_mpi ( sk->skey[4] );
-    if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
+    if( ret_sk ) /* return an unprotected version of the sk */
        *ret_sk = copy_secret_key( NULL, sk );
 
     if( dek ) {
@@ -901,7 +1106,7 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     }
 
     pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
     pkt->pkt.public_key = pk;
     add_kbnode(pub_root, new_kbnode( pkt ));
 
@@ -912,7 +1117,7 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
      * are known.
      */
     pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+    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 */
@@ -928,7 +1133,7 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
  */
 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 )
+       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
 {
     int rc;
     PACKET *pkt;
@@ -978,7 +1183,7 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     sk->csum += checksum_mpi (sk->skey[3] );
     sk->csum += checksum_mpi (sk->skey[4] );
     sk->csum += checksum_mpi (sk->skey[5] );
-    if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
+    if( ret_sk ) /* return an unprotected version of the sk */
        *ret_sk = copy_secret_key( NULL, sk );
 
     if( dek ) {
@@ -994,12 +1199,12 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     }
 
     pkt = m_alloc_clear(sizeof *pkt);
-    pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+    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->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
     pkt->pkt.secret_key = sk;
     add_kbnode(sec_root, new_kbnode( pkt ));
 
@@ -1035,8 +1240,102 @@ check_valid_days( const char *s )
 }
 
 
+static void
+print_key_flags(int flags)
+{
+  if(flags&PUBKEY_USAGE_SIG)
+    tty_printf("%s ",_("Sign"));
+
+  if(flags&PUBKEY_USAGE_ENC)
+    tty_printf("%s ",_("Encrypt"));
+
+  if(flags&PUBKEY_USAGE_AUTH)
+    tty_printf("%s ",_("Authenticate"));
+}
+
+
+/* Returns the key flags */
+static unsigned int
+ask_key_flags(int 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();
+
+  /* Preload the current set with the possible set, minus
+     authentication, since nobody really uses auth yet. */
+  current=possible&~PUBKEY_USAGE_AUTH;
+
+  for(;;)
+    {
+      tty_printf("\n");
+      tty_printf(_("Possible actions for a %s key: "),
+                pubkey_algo_to_string(algo));
+      print_key_flags(possible);
+      tty_printf("\n");
+      tty_printf(_("Current allowed actions: "));
+      print_key_flags(current);
+      tty_printf("\n\n");
+
+      if(possible&PUBKEY_USAGE_SIG)
+       tty_printf(_("   (%c) Toggle the sign capability\n"),
+                  togglers[0]);
+      if(possible&PUBKEY_USAGE_ENC)
+       tty_printf(_("   (%c) Toggle the encrypt capability\n"),
+                  togglers[2]);
+      if(possible&PUBKEY_USAGE_AUTH)
+       tty_printf(_("   (%c) Toggle the authenticate capability\n"),
+                  togglers[4]);
+
+      tty_printf(_("   (%c) Finished\n"),togglers[6]);
+      tty_printf("\n");
+
+      m_free(answer);
+      answer = cpr_get("keygen.flags",_("Your selection? "));
+      cpr_kill_prompt();
+
+      if(strlen(answer)>1)
+       continue;
+      else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7])
+       break;
+      else if((*answer==togglers[0] || *answer==togglers[1])
+             && possible&PUBKEY_USAGE_SIG)
+       {
+         if(current&PUBKEY_USAGE_SIG)
+           current&=~PUBKEY_USAGE_SIG;
+         else
+           current|=PUBKEY_USAGE_SIG;
+       }
+      else if((*answer==togglers[2] || *answer==togglers[3])
+             && possible&PUBKEY_USAGE_ENC)
+       {
+         if(current&PUBKEY_USAGE_ENC)
+           current&=~PUBKEY_USAGE_ENC;
+         else
+           current|=PUBKEY_USAGE_ENC;
+       }
+      else if((*answer==togglers[4] || *answer==togglers[5])
+             && possible&PUBKEY_USAGE_AUTH)
+       {
+         if(current&PUBKEY_USAGE_AUTH)
+           current&=~PUBKEY_USAGE_AUTH;
+         else
+           current|=PUBKEY_USAGE_AUTH;
+       }
+    }
+
+  m_free(answer);
+
+  return current;
+}
+
+
 /****************
- * Returns: 0 to create both a DSA and a ElGamal key.
+ * Returns: 0 to create both a DSA and a Elgamal key.
  *          and only if key flags are to be written the desired usage.
  */
 static int
@@ -1048,15 +1347,15 @@ ask_algo (int addmode, unsigned int *r_usage)
     *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 and Elgamal (default)\n"), 1 );
     tty_printf(    _("   (%d) DSA (sign only)\n"), 2 );
     if( addmode )
-       tty_printf(    _("   (%d) ElGamal (encrypt only)\n"), 3 );
+       tty_printf(    _("   (%d) Elgamal (encrypt only)\n"), 3 );
     tty_printf(    _("   (%d) RSA (sign only)\n"), 4 );
     if (addmode)
         tty_printf(    _("   (%d) RSA (encrypt only)\n"), 5 );
     if (opt.expert)
-      tty_printf(    _("   (%d) RSA (sign and encrypt)\n"), 6 );
+      tty_printf(    _("   (%d) RSA (set your own capabilities)\n"), 6 );
 
     for(;;) {
        answer = cpr_get("keygen.algo",_("Your selection? "));
@@ -1069,7 +1368,7 @@ ask_algo (int addmode, unsigned int *r_usage)
        }
        else if( algo == 6 && opt.expert ) {
            algo = PUBKEY_ALGO_RSA;
-           *r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG;
+           *r_usage=ask_key_flags(algo);
            break;
        }
        else if( algo == 5 && addmode ) {
@@ -1095,6 +1394,7 @@ ask_algo (int addmode, unsigned int *r_usage)
        else
            tty_printf(_("Invalid selection.\n"));
     }
+
     return algo;
 }
 
@@ -1144,12 +1444,13 @@ ask_keysize( int algo )
                _("Keysizes larger than 2048 are not suggested because\n"
                  "computations take REALLY long!\n"));
            if( cpr_get_answer_is_yes("keygen.size.huge.okay",_(
-                       "Are you sure that you want this keysize? ")) ) {
+                       "Are you sure that you want this keysize? (y/N) ")) )
+             {
                tty_printf(_("Okay, but keep in mind that your monitor "
                             "and keyboard radiation is also very vulnerable "
                             "to attacks!\n"));
                break;
-           }
+             }
        }
        else
            break;
@@ -1273,7 +1574,7 @@ ask_expire_interval(int object)
        }
 
        if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay",
-                                           _("Is this correct (y/n)? ")) )
+                                           _("Is this correct? (y/N) ")) )
            break;
     }
     m_free(answer);
@@ -1317,8 +1618,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"
-"from Real Name, Comment and Email Address in this form:\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;
     for(;;) {
@@ -1474,6 +1775,7 @@ ask_user_id( int mode )
 }
 
 
+/* FIXME: We need a way to cancel this prompt. */
 static DEK *
 do_ask_passphrase( STRING2KEY **ret_s2k )
 {
@@ -1486,7 +1788,7 @@ do_ask_passphrase( STRING2KEY **ret_s2k )
     s2k = m_alloc_secure( sizeof *s2k );
     for(;;) {
        s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = opt.s2k_digest_algo;
+       s2k->hash_algo = S2K_DIGEST_ALGO;
        dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,
                                  errtext, NULL);
        if( !dek ) {
@@ -1512,37 +1814,41 @@ do_ask_passphrase( STRING2KEY **ret_s2k )
 
 static int
 do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
-          DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate )
+          DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate,
+          int is_subkey )
 {
-    int rc=0;
+  int rc=0;
 
-    if( !opt.batch )
-       tty_printf(_(
+  if( !opt.batch )
+    tty_printf(_(
 "We need to generate a lot of random bytes. It is a good idea to perform\n"
 "some other action (type on the keyboard, move the mouse, utilize the\n"
 "disks) during the prime generation; this gives the random number\n"
 "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);
-    else if( algo == PUBKEY_ALGO_DSA )
-       rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
-    else if( algo == PUBKEY_ALGO_RSA )
-       rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
-    else
-       BUG();
+  if( algo == PUBKEY_ALGO_ELGAMAL_E )
+    rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
+                is_subkey);
+  else if( algo == PUBKEY_ALGO_DSA )
+    rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
+                is_subkey);
+  else if( algo == PUBKEY_ALGO_RSA )
+    rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
+                is_subkey);
+  else
+    BUG();
 
 #ifdef ENABLE_COMMENT_PACKETS
-    if( !rc ) {
-       add_kbnode( pub_root,
+  if( !rc ) {
+    add_kbnode( pub_root,
                make_comment_node("#created by GNUPG v" VERSION " ("
-                                           PRINTABLE_OS_NAME ")"));
-       add_kbnode( sec_root,
+                                 PRINTABLE_OS_NAME ")"));
+    add_kbnode( sec_root,
                make_comment_node("#created by GNUPG v" VERSION " ("
-                                           PRINTABLE_OS_NAME ")"));
-    }
+                                 PRINTABLE_OS_NAME ")"));
+  }
 #endif
-    return rc;
+  return rc;
 }
 
 
@@ -1757,7 +2063,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
     char *p;
     int i;
 
-    /* check that we have all required parameters */
+    /* 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 ) ) {
@@ -1818,7 +2124,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
 
        s2k = m_alloc_secure( sizeof *s2k );
        s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = opt.s2k_digest_algo;
+       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);
@@ -1868,7 +2174,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
 
 /****************
  * Kludge to allow non interactive key generation controlled
- * by a parameter file (which currently is only stdin)
+ * by a parameter file.
  * Note, that string parameters are expected to be in UTF-8
  */
 static void
@@ -1890,10 +2196,13 @@ read_parameter_file( const char *fname )
        { "Passphrase",     pPASSPHRASE },
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
+        { "Handle",         pHANDLE },
        { NULL, 0 }
     };
-    FILE *fp;
-    char line[1024], *p;
+    IOBUF fp;
+    byte *line;
+    unsigned int maxlen, nline;
+    char *p;
     int lnr;
     const char *err = NULL;
     struct para_data_s *para, *r;
@@ -1902,26 +2211,32 @@ read_parameter_file( const char *fname )
 
     memset( &outctrl, 0, sizeof( outctrl ) );
 
-    if( !fname || !*fname || !strcmp(fname,"-") ) {
-       fp = stdin;
-       fname = "-";
-    }
-    else {
-       fp = fopen( fname, "r" );
-       if( !fp ) {
-           log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
-           return;
-       }
+    if( !fname || !*fname)
+      fname = "-";
+
+    fp = iobuf_open (fname);
+    if (fp && is_secured_file (iobuf_get_fd (fp)))
+      {
+        iobuf_close (fp);
+        fp = NULL;
+        errno = EPERM;
+      }
+    if (!fp) {
+      log_error (_("can't open `%s': %s\n"), fname, strerror(errno) );
+      return;
     }
+    iobuf_ioctl (fp, 3, 1, NULL); /* No file caching. */
 
     lnr = 0;
     err = NULL;
     para = NULL;
-    while( fgets( line, DIM(line)-1, fp ) ) {
+    maxlen = 1024;
+    line = NULL;
+    while ( iobuf_read_line (fp, &line, &nline, &maxlen) ) {
        char *keyword, *value;
 
        lnr++;
-       if( *line && line[strlen(line)-1] != '\n' ) {
+       if( !maxlen ) {
            err = "line too long";
            break;
        }
@@ -1945,7 +2260,9 @@ read_parameter_file( const char *fname )
                outctrl.dryrun = 1;
            else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
                outctrl.lnr = lnr;
-               proc_parameter_file( para, fname, &outctrl, 0 );
+               if (proc_parameter_file( para, fname, &outctrl, 0 ))
+                  print_status_key_not_created 
+                    (get_parameter_value (para, pHANDLE));
                release_parameter_list( para );
                para = NULL;
            }
@@ -2005,7 +2322,9 @@ read_parameter_file( const char *fname )
 
        if( keywords[i].key == pKEYTYPE && para ) {
            outctrl.lnr = lnr;
-           proc_parameter_file( para, fname, &outctrl, 0 );
+           if (proc_parameter_file( para, fname, &outctrl, 0 ))
+              print_status_key_not_created
+                (get_parameter_value (para, pHANDLE));
            release_parameter_list( para );
            para = NULL;
        }
@@ -2028,17 +2347,25 @@ read_parameter_file( const char *fname )
     }
     if( err )
        log_error("%s:%d: %s\n", fname, lnr, err );
-    else if( ferror(fp) ) {
-       log_error("%s:%d: read error: %s\n", fname, lnr, strerror(errno) );
+    else if( iobuf_error (fp) ) {
+       log_error("%s:%d: read error\n", fname, lnr);
     }
     else if( para ) {
        outctrl.lnr = lnr;
-       proc_parameter_file( para, fname, &outctrl, 0 );
+       if (proc_parameter_file( para, fname, &outctrl, 0 ))
+          print_status_key_not_created (get_parameter_value (para, pHANDLE));
     }
 
     if( outctrl.use_files ) { /* close open streams */
        iobuf_close( outctrl.pub.stream );
        iobuf_close( outctrl.sec.stream );
+
+        /* Must invalidate that ugly cache to actually close it.  */
+        if (outctrl.pub.fname)
+          iobuf_ioctl (NULL, 2, 0, (char*)outctrl.pub.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 );
@@ -2046,18 +2373,21 @@ read_parameter_file( const char *fname )
     }
 
     release_parameter_list( para );
-    if( strcmp( fname, "-" ) )
-       fclose(fp);
+    iobuf_close (fp);
 }
 
 
 /*
  * Generate a keypair (fname is only used in batch mode) If
  * CARD_SERIALNO is not NULL the fucntion will create the keys on an
- * OpenPGP Card.
+ * 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
+ * written to directory given by this argument .
  */
 void
-generate_keypair( const char *fname, const char *card_serialno )
+generate_keypair (const char *fname, const char *card_serialno, 
+                  const char *backup_encryption_dir)
 {
   unsigned int nbits;
   char *uid = NULL;
@@ -2080,178 +2410,250 @@ generate_keypair( const char *fname, const char *card_serialno )
       return;
     }
   
-   if (opt.batch)
-     {
-       read_parameter_file( fname );
-       return;
-     }
-
-   if (card_serialno)
-     {
+  if (opt.batch)
+    {
+      read_parameter_file( fname );
+      return;
+    }
+
+  if (card_serialno)
+    {
 #ifdef ENABLE_CARD_SUPPORT
-       r = xcalloc (1, sizeof *r + strlen (card_serialno) );
-       r->key = pSERIALNO;
-       strcpy( r->u.value, card_serialno);
-       r->next = para;
-       para = r;
+      r = xcalloc (1, sizeof *r + strlen (card_serialno) );
+      r->key = pSERIALNO;
+      strcpy( r->u.value, card_serialno);
+      r->next = para;
+      para = r;
        
-       algo = PUBKEY_ALGO_RSA;
+      algo = PUBKEY_ALGO_RSA;
        
-       r = xcalloc (1, sizeof *r + 20 );
-       r->key = pKEYTYPE;
-       sprintf( r->u.value, "%d", algo );
-       r->next = para;
-       para = r;
-       r = xcalloc (1, sizeof *r + 20 );
-       r->key = pKEYUSAGE;
-       strcpy (r->u.value, "sign");
-       r->next = para;
-       para = r;
+      r = xcalloc (1, sizeof *r + 20 );
+      r->key = pKEYTYPE;
+      sprintf( r->u.value, "%d", algo );
+      r->next = para;
+      para = r;
+      r = xcalloc (1, sizeof *r + 20 );
+      r->key = pKEYUSAGE;
+      strcpy (r->u.value, "sign");
+      r->next = para;
+      para = r;
        
-       r = xcalloc (1, sizeof *r + 20 );
-       r->key = pSUBKEYTYPE;
-       sprintf( r->u.value, "%d", algo );
-       r->next = para;
-       para = r;
-       r = xcalloc (1, sizeof *r + 20 );
-       r->key = pSUBKEYUSAGE;
-       strcpy (r->u.value, "encrypt");
-       r->next = para;
-       para = r;
+      r = xcalloc (1, sizeof *r + 20 );
+      r->key = pSUBKEYTYPE;
+      sprintf( r->u.value, "%d", algo );
+      r->next = para;
+      para = r;
+      r = xcalloc (1, sizeof *r + 20 );
+      r->key = pSUBKEYUSAGE;
+      strcpy (r->u.value, "encrypt");
+      r->next = para;
+      para = r;
        
-       r = xcalloc (1, sizeof *r + 20 );
-       r->key = pAUTHKEYTYPE;
-       sprintf( r->u.value, "%d", algo );
-       r->next = para;
-       para = r;
+      r = xcalloc (1, sizeof *r + 20 );
+      r->key = pAUTHKEYTYPE;
+      sprintf( r->u.value, "%d", algo );
+      r->next = para;
+      para = r;
+
+      if (backup_encryption_dir)
+        {
+          r = xcalloc (1, sizeof *r + strlen (backup_encryption_dir) );
+          r->key = pBACKUPENCDIR;
+          strcpy (r->u.value, backup_encryption_dir);
+          r->next = para;
+          para = r;
+        }
 #endif /*ENABLE_CARD_SUPPORT*/
-     }
-   else
-     {
-       algo = ask_algo( 0, &use );
-       if( !algo )
-         { /* default: DSA with ElG subkey of the specified size */
-           both = 1;
-           r = m_alloc_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 1024 bits.\n"));
-           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 );
-           r->key = pKEYUSAGE;
-           strcpy( r->u.value, "sign" );
-           r->next = para;
-           para = r;
+    }
+  else
+    {
+      algo = ask_algo( 0, &use );
+      if( !algo )
+        { /* default: DSA with ElG subkey of the specified size */
+          both = 1;
+          r = m_alloc_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 1024 bits.\n"));
+          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 );
+          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->key = pSUBKEYTYPE;
-           sprintf( r->u.value, "%d", algo );
-           r->next = para;
-           para = r;
-           r = m_alloc_clear( sizeof *r + 20 );
-           r->key = pSUBKEYUSAGE;
-           strcpy( r->u.value, "encrypt" );
-           r->next = para;
-           para = r;
-         }
-       else 
-         {
-           r = m_alloc_clear( sizeof *r + 20 );
-           r->key = pKEYTYPE;
-           sprintf( r->u.value, "%d", algo );
-           r->next = para;
-           para = r;
+          algo = PUBKEY_ALGO_ELGAMAL_E;
+          r = m_alloc_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->key = pSUBKEYUSAGE;
+          strcpy( r->u.value, "encrypt" );
+          r->next = para;
+          para = r;
+        }
+      else 
+        {
+          r = m_alloc_clear( sizeof *r + 20 );
+          r->key = pKEYTYPE;
+          sprintf( r->u.value, "%d", algo );
+          r->next = para;
+          para = r;
            
-           if (use)
-             {
-               r = m_alloc_clear( sizeof *r + 20 );
-               r->key = pKEYUSAGE;
-               sprintf( r->u.value, "%s%s",
-                        (use & PUBKEY_USAGE_SIG)? "sign ":"",
-                        (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
-               r->next = para;
-               para = r;
-             }
+          if (use)
+            {
+              r = m_alloc_clear( sizeof *r + 25 );
+              r->key = pKEYUSAGE;
+              sprintf( r->u.value, "%s%s%s",
+                       (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
+                       (use & PUBKEY_USAGE_AUTH)? "auth":"" );
+              r->next = para;
+              para = r;
+            }
            
-         }
+        }
        
-       nbits = ask_keysize( algo );
-       r = m_alloc_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 );
-    r->key = pKEYEXPIRE;
-    r->u.expire = expire;
-    r->next = para;
-    para = r;
-    r = m_alloc_clear( sizeof *r + 20 );
-    r->key = pSUBKEYEXPIRE;
-    r->u.expire = expire;
-    r->next = para;
-    para = r;
-
-    uid = ask_user_id(0);
-    if( !uid ) 
-      {
-       log_error(_("Key generation canceled.\n"));
-       release_parameter_list( para );
-       return;
-      }
-    r = m_alloc_clear( sizeof *r + strlen(uid) );
-    r->key = pUSERID;
-    strcpy( r->u.value, uid );
-    r->next = para;
-    para = r;
+      nbits = ask_keysize( algo );
+      r = m_alloc_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 );
+  r->key = pKEYEXPIRE;
+  r->u.expire = expire;
+  r->next = para;
+  para = r;
+  r = m_alloc_clear( sizeof *r + 20 );
+  r->key = pSUBKEYEXPIRE;
+  r->u.expire = expire;
+  r->next = para;
+  para = r;
+
+  uid = ask_user_id(0);
+  if( !uid ) 
+    {
+      log_error(_("Key generation canceled.\n"));
+      release_parameter_list( para );
+      return;
+    }
+  r = m_alloc_clear( sizeof *r + strlen(uid) );
+  r->key = pUSERID;
+  strcpy( r->u.value, uid );
+  r->next = para;
+  para = r;
     
-    dek = card_serialno? NULL : do_ask_passphrase( &s2k );
-    if( dek )
-      {
-       r = m_alloc_clear( sizeof *r );
-       r->key = pPASSPHRASE_DEK;
-       r->u.dek = dek;
-       r->next = para;
-       para = r;
-       r = m_alloc_clear( sizeof *r );
-       r->key = pPASSPHRASE_S2K;
-       r->u.s2k = s2k;
-       r->next = para;
-       para = r;
-      }
+  dek = card_serialno? NULL : do_ask_passphrase( &s2k );
+  if( dek )
+    {
+      r = m_alloc_clear( sizeof *r );
+      r->key = pPASSPHRASE_DEK;
+      r->u.dek = dek;
+      r->next = para;
+      para = r;
+      r = m_alloc_clear( sizeof *r );
+      r->key = pPASSPHRASE_S2K;
+      r->u.s2k = s2k;
+      r->next = para;
+      para = r;
+    }
     
-    proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
-    release_parameter_list( para );
+  proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
+  release_parameter_list( para );
 }
 
 
-static void
-print_status_key_created (int letter, PKT_public_key *pk)
+#ifdef ENABLE_CARD_SUPPORT
+/* Generate a raw key and return it as a secret key packet.  The
+   function will ask for the passphrase and return a protected as well
+   as an unprotected copy of a new secret key packet.  0 is returned
+   on success and the caller must then free the returned values.  */
+static int
+generate_raw_key (int algo, unsigned int nbits, u32 created_at,
+                  PKT_secret_key **r_sk_unprotected,
+                  PKT_secret_key **r_sk_protected)
 {
-  byte array[MAX_FINGERPRINT_LEN], *s;
-  char buf[MAX_FINGERPRINT_LEN*2+30], *p;
-  size_t i, n;
-  
-  p = buf;
-  *p++ = letter;
-  *p++ = ' ';
-  fingerprint_from_pk (pk, array, &n);
-  s = array;
-  for (i=0; i < n ; i++, s++, p += 2)
-    sprintf (p, "%02X", *s);
-  *p = 0;
-  write_status_text (STATUS_KEY_CREATED, buf);
+  int rc;
+  DEK *dek = NULL;
+  STRING2KEY *s2k = NULL;
+  PKT_secret_key *sk = NULL;
+  int i;
+  size_t nskey, npkey;
+
+  npkey = pubkey_get_npkey (algo);
+  nskey = pubkey_get_nskey (algo);
+  assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);
+
+  if (nbits < 512)
+    {
+      nbits = 512;
+      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 );
+    }
+
+  dek = do_ask_passphrase (&s2k);
+
+  sk = m_alloc_clear (sizeof *sk);
+  sk->timestamp = created_at;
+  sk->version = 4;
+  sk->pubkey_algo = algo;
+
+  rc = pubkey_generate (algo, nbits, sk->skey, NULL);
+  if (rc)
+    {
+      log_error("pubkey_generate failed: %s\n", g10_errstr(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);
+
+  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;
+       }
+    }
+  if (r_sk_protected)
+    {
+      *r_sk_protected = sk;
+      sk = NULL;
+    }
+
+ leave:
+  if (sk)
+    free_secret_key (sk);
+  m_free (dek);
+  m_free (s2k);
+  return rc;
 }
+#endif /* ENABLE_CARD_SUPPORT */
+
 
 static void
 do_generate_keypair( struct para_data_s *para,
@@ -2259,7 +2661,7 @@ do_generate_keypair( struct para_data_s *para,
 {
     KBNODE pub_root = NULL;
     KBNODE sec_root = NULL;
-    PKT_secret_key *sk = NULL;
+    PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
     const char *s;
     struct revocation_key *revkey;
     int rc;
@@ -2275,13 +2677,20 @@ do_generate_keypair( struct para_data_s *para,
        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;
 
-           outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
+            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,
+               log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
                                                     strerror(errno) );
                return;
            }
@@ -2292,15 +2701,26 @@ do_generate_keypair( struct para_data_s *para,
            }
        }
        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;
 
-           outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
+           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,
+               log_error(_("can't create `%s': %s\n"), outctrl->sec.newfname,
                                                     strerror(errno) );
                return;
            }
@@ -2338,25 +2758,25 @@ do_generate_keypair( struct para_data_s *para,
                         pub_root, sec_root,
                         get_parameter_dek( para, pPASSPHRASE_DEK ),
                         get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                        &sk,
-                        get_parameter_u32( para, pKEYEXPIRE ) );
+                        &pri_sk,
+                        get_parameter_u32( para, pKEYEXPIRE ), 0 );
       }
     else
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, pub_root, sec_root,
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root,
                            get_parameter_u32 (para, pKEYEXPIRE), para);
         if (!rc)
           {
-            sk = sec_root->next->pkt->pkt.secret_key;
-            assert (sk);
+            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,sk,revkey);
+       rc=write_direct_sig(pub_root,pub_root,pri_sk,revkey);
        if(!rc)
-         write_direct_sig(sec_root,pub_root,sk,revkey);
+         write_direct_sig(sec_root,pub_root,pri_sk,revkey);
       }
 
     if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
@@ -2364,10 +2784,10 @@ do_generate_keypair( struct para_data_s *para,
        if( !rc )
            write_uid(sec_root, s );
        if( !rc )
-           rc = write_selfsig(pub_root, pub_root, sk,
+           rc = write_selfsig(pub_root, pub_root, pri_sk,
                                get_parameter_uint (para, pKEYUSAGE));
        if( !rc )
-           rc = write_selfsig(sec_root, pub_root, sk,
+           rc = write_selfsig(sec_root, pub_root, pri_sk,
                                get_parameter_uint (para, pKEYUSAGE));
     }
 
@@ -2380,33 +2800,45 @@ do_generate_keypair( struct para_data_s *para,
                             pub_root, sec_root,
                             get_parameter_dek( para, pPASSPHRASE_DEK ),
                             get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                            NULL,
-                            get_parameter_u32( para, pSUBKEYEXPIRE ) );
+                            &sub_sk,
+                            get_parameter_u32( para, pSUBKEYEXPIRE ), 1 );
           }
         else
           {
-            rc = gen_card_key (PUBKEY_ALGO_RSA, 2, pub_root, sec_root,
-                               get_parameter_u32 (para, pKEYEXPIRE), para);
+            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, sk,
+          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, sk,
+          rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk,
                                 get_parameter_uint (para, pSUBKEYUSAGE));
         did_sub = 1;
       }
 
     if (card && get_parameter (para, pAUTHKEYTYPE))
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, pub_root, sec_root,
+        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, sk, PUBKEY_USAGE_AUTH);
+          rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
         if (!rc)
-          rc = write_keybinding (sec_root, pub_root, sk, PUBKEY_USAGE_AUTH);
+          rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
       }
     
     if( !rc && outctrl->use_files ) { /* direct write to specified files */
@@ -2505,16 +2937,21 @@ do_generate_keypair( struct para_data_s *para,
            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) );
     }
     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);
+        print_status_key_created (did_sub? 'B':'P', pk,
+                                  get_parameter_value (para, pHANDLE));
     }
     release_kbnode( pub_root );
     release_kbnode( sec_root );
-    if( sk && !card) /* the unprotected  secret key unless we have a */
-      free_secret_key(sk); /* shallow copy in card mode. */
+
+    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);
 }
 
 
@@ -2527,7 +2964,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
 {
     int okay=0, rc=0;
     KBNODE node;
-    PKT_secret_key *sk = NULL; /* this is the primary sk */
+    PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
     int algo;
     unsigned int use;
     u32 expire;
@@ -2545,11 +2982,11 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     }
 
     /* make a copy of the sk to keep the protected one in the keyblock */
-    sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
+    pri_sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
 
     cur_time = make_timestamp();
-    if( sk->timestamp > cur_time ) {
-       ulong d = sk->timestamp - cur_time;
+    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 "
@@ -2560,14 +2997,14 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
        }
     }
 
-    if (sk->version < 4) {
+    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( sk ) ) {
+    switch( is_secret_key_protected( pri_sk ) ) {
       case -1:
        rc = G10ERR_PUBKEY_ALGO;
        break;
@@ -2576,7 +3013,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
        break;
       default:
        tty_printf("Key is protected.\n");
-       rc = check_secret_key( sk, 0 );
+       rc = check_secret_key( pri_sk, 0 );
        if( !rc )
            passphrase = get_last_passphrase();
        break;
@@ -2584,30 +3021,29 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     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? ") ) )
+                                                 _("Really create? (y/N) ")))
        goto leave;
 
     if( passphrase ) {
        s2k = m_alloc_secure( sizeof *s2k );
        s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = opt.s2k_digest_algo;
+       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, NULL, expire );
+                                     dek, s2k, &sub_sk, expire, 1 );
     if( !rc )
-       rc = write_keybinding(pub_keyblock, pub_keyblock, sk, use);
+       rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
     if( !rc )
-       rc = write_keybinding(sec_keyblock, pub_keyblock, sk, use);
+       rc = write_keybinding(sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
     if( !rc ) {
        okay = 1;
         write_status_text (STATUS_KEY_CREATED, "S");
@@ -2619,12 +3055,129 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     m_free( passphrase );
     m_free( dek );
     m_free( s2k );
-    if( sk ) /* release the copy of the (now unprotected) secret key */
-       free_secret_key(sk);
+    /* 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;
 }
 
+
+#ifdef ENABLE_CARD_SUPPORT
+/* Generate a subkey on a card. */
+int
+generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
+                          int keyno, const char *serialno)
+{
+  int okay=0, rc=0;
+  KBNODE node;
+  PKT_secret_key *pri_sk = NULL;
+  int algo;
+  unsigned int use;
+  u32 expire;
+  char *passphrase = NULL;
+  u32 cur_time;
+  struct para_data_s *para = NULL;
+
+  assert (keyno >= 1 && keyno <= 3);
+
+  para = xcalloc (1, sizeof *para + strlen (serialno) );
+  para->key = pSERIALNO;
+  strcpy (para->u.value, serialno);
+
+  /* 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;
+    }
+
+  /* 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 (rc)
+    goto leave;
+
+  algo = PUBKEY_ALGO_RSA;
+  expire = ask_expire_interval (0);
+  if (keyno == 1)
+    use = PUBKEY_USAGE_SIG;
+  else if (keyno == 2)
+    use = PUBKEY_USAGE_ENC;
+  else
+    use = PUBKEY_USAGE_AUTH;
+  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay",
+                                               _("Really create? (y/N) ")))
+    goto leave;
+
+  if (passphrase)
+    set_next_passphrase (passphrase);
+  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock, expire, para);
+  if (!rc)
+    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, NULL, use);
+  if (!rc)
+    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, NULL, 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);
+  /* Release the copy of the (now unprotected) secret keys. */
+  if (pri_sk)
+    free_secret_key (pri_sk);
+  set_next_passphrase( NULL );
+  release_parameter_list (para);
+  return okay;
+}
+#endif /* !ENABLE_CARD_SUPPORT */
+
+
 /****************
  * Write a keyblock to an output stream
  */
@@ -2644,7 +3197,8 @@ write_keyblock( IOBUF out, KBNODE node )
 
 
 static int
-gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+gen_card_key (int algo, int keyno, int is_primary,
+              KBNODE pub_root, KBNODE sec_root,
               u32 expireval, struct para_data_s *para)
 {
 #ifdef ENABLE_CARD_SUPPORT
@@ -2656,6 +3210,7 @@ gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
   PKT_public_key *pk;
 
   assert (algo == PUBKEY_ALGO_RSA);
+  
 
   rc = agent_scd_genkey (&info, keyno, 1);
 /*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
@@ -2705,12 +3260,148 @@ gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
     }
 
   pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = keyno == 1 ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+  pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+  pkt->pkt.public_key = pk;
+  add_kbnode(pub_root, new_kbnode( pkt ));
+
+  pkt = xcalloc (1,sizeof *pkt);
+  pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+  pkt->pkt.secret_key = sk;
+  add_kbnode(sec_root, new_kbnode( pkt ));
+
+  return 0;
+#else
+  return -1;
+#endif /*!ENABLE_CARD_SUPPORT*/
+}
+
+
+
+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,
+                          const char *backup_dir)
+{
+#ifdef ENABLE_CARD_SUPPORT
+  int rc;
+  const char *s;
+  PACKET *pkt;
+  PKT_secret_key *sk, *sk_unprotected, *sk_protected;
+  PKT_public_key *pk;
+  size_t n;
+  int i;
+
+  rc = generate_raw_key (algo, 1024, make_timestamp (),
+                         &sk_unprotected, &sk_protected);
+  if (rc)
+    return rc;
+
+  /* First, 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);
+      return rc;
+    }
+
+  /* Get rid of the secret key parameters and store the serial numer. */
+  sk = sk_unprotected;
+  n = pubkey_get_nskey (sk->pubkey_algo);
+  for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
+    {
+      mpi_free (sk->skey[i]);
+      sk->skey[i] = NULL;
+    }
+  i = pubkey_get_npkey (sk->pubkey_algo);
+  sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+  sk->is_protected = 1;
+  sk->protect.s2k.mode = 1002;
+  s = get_parameter_value (para, pSERIALNO);
+  assert (s);
+  for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+       sk->protect.ivlen++, s += 2)
+    sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+
+  /* Now write the *protected* secret key to the file.  */
+  {
+    char name_buffer[50];
+    char *fname;
+    IOBUF fp;
+    mode_t oldmask;
+
+    keyid_from_sk (sk, NULL);
+    sprintf (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);
+    if (is_secured_filename (fname))
+      {
+        fp = NULL;
+        errno = EPERM;
+      }
+    else
+      fp = iobuf_create (fname);
+    umask (oldmask);
+    if (!fp) 
+      {
+       log_error (_("can't create backup file `%s': %s\n"),
+                   fname, strerror(errno) );
+        m_free (fname);
+        free_secret_key (sk_unprotected);
+        free_secret_key (sk_protected);
+        return G10ERR_OPEN_FILE;
+      }
+
+    pkt = xcalloc (1, sizeof *pkt);
+    pkt->pkttype = PKT_SECRET_KEY;
+    pkt->pkt.secret_key = sk_protected;
+    sk_protected = NULL;
+
+    rc = build_packet (fp, pkt);
+    if (rc)
+      {
+        log_error("build packet failed: %s\n", g10_errstr(rc) );
+        iobuf_cancel (fp);
+      }
+    else
+      {
+        iobuf_close (fp);
+        iobuf_ioctl (NULL, 2, 0, (char*)fname);
+        log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+      }
+    free_packet (pkt);
+    m_free (pkt);
+    m_free (fname);
+    if (rc)
+      {
+        free_secret_key (sk_unprotected);
+        return rc;
+      }
+  }
+
+  /* Create the public key from the secret key. */
+  pk = xcalloc (1, sizeof *pk );
+  pk->timestamp = sk->timestamp;
+  pk->version = sk->version;
+  if (expireval)
+      pk->expiredate = sk->expiredate = sk->timestamp + expireval;
+  pk->pubkey_algo = sk->pubkey_algo;
+  n = pubkey_get_npkey (sk->pubkey_algo);
+  for (i=0; i < n; i++)
+    pk->pkey[i] = mpi_copy (sk->skey[i]);
+
+  /* Build packets and add them to the node lists.  */
+  pkt = xcalloc (1,sizeof *pkt);
+  pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
   add_kbnode(pub_root, new_kbnode( pkt ));
 
   pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = keyno == 1 ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+  pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
   pkt->pkt.secret_key = sk;
   add_kbnode(sec_root, new_kbnode( pkt ));
 
@@ -2719,3 +3410,111 @@ gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
   return -1;
 #endif /*!ENABLE_CARD_SUPPORT*/
 }
+
+
+#ifdef ENABLE_CARD_SUPPORT
+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;
+
+  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)
+    {
+      log_error (_("length of an RSA prime is not %d\n"), 512);
+      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);
+
+ leave:
+  xfree (template);
+  return rc;
+}
+#endif /*ENABLE_CARD_SUPPORT*/