* keygen.c (keygen_set_std_prefs): Add SHA256 and BZip2 to default
[gnupg.git] / g10 / keygen.c
index 5929e29..26f3cc6 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 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -64,7 +64,8 @@ enum para_name {
   pPASSPHRASE_DEK,
   pPASSPHRASE_S2K,
   pSERIALNO,
-  pBACKUPENCDIR
+  pBACKUPENCDIR,
+  pHANDLE
 };
 
 struct para_data_s {
@@ -162,6 +163,49 @@ copy_mpi (MPI a, unsigned char *buffer, size_t len, size_t *ncopied)
 #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 )
 {
@@ -281,7 +325,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"))
       {
@@ -291,8 +335,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))
@@ -312,8 +369,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;
          }
@@ -466,6 +538,8 @@ PKT_user_id *keygen_get_std_prefs(void)
   if(!prefs_initialized)
     keygen_set_std_prefs(NULL,0);
 
+  uid->ref=1;
+
   uid->prefs=m_alloc((sizeof(prefitem_t *)*
                      (nsym_prefs+nhash_prefs+nzip_prefs+1)));
 
@@ -1305,13 +1379,15 @@ ask_algo (int addmode, unsigned int *r_usage)
     if( !addmode )
        tty_printf(_("   (%d) DSA and Elgamal (default)\n"), 1 );
     tty_printf(    _("   (%d) DSA (sign only)\n"), 2 );
+    if (opt.expert)
+      tty_printf(  _("   (%d) DSA (set your own capabilities)\n"), 3 );
     if( addmode )
-       tty_printf(    _("   (%d) Elgamal (encrypt only)\n"), 3 );
-    tty_printf(    _("   (%d) RSA (sign only)\n"), 4 );
+       tty_printf(_("   (%d) Elgamal (encrypt only)\n"), 4 );
+    tty_printf(    _("   (%d) RSA (sign only)\n"), 5 );
     if (addmode)
-        tty_printf(    _("   (%d) RSA (encrypt only)\n"), 5 );
+        tty_printf(_("   (%d) RSA (encrypt only)\n"), 6 );
     if (opt.expert)
-      tty_printf(    _("   (%d) RSA (set your own capabilities)\n"), 6 );
+      tty_printf(  _("   (%d) RSA (set your own capabilities)\n"), 7 );
 
     for(;;) {
        answer = cpr_get("keygen.algo",_("Your selection? "));
@@ -1322,26 +1398,31 @@ ask_algo (int addmode, unsigned int *r_usage)
            algo = 0;   /* create both keys */
            break;
        }
-       else if( algo == 6 && opt.expert ) {
+       else if( algo == 7 && opt.expert ) {
            algo = PUBKEY_ALGO_RSA;
            *r_usage=ask_key_flags(algo);
            break;
        }
-       else if( algo == 5 && addmode ) {
+       else if( algo == 6 && addmode ) {
            algo = PUBKEY_ALGO_RSA;
             *r_usage = PUBKEY_USAGE_ENC;
            break;
        }
-       else if( algo == 4 ) {
+       else if( algo == 5 ) {
            algo = PUBKEY_ALGO_RSA;
             *r_usage = PUBKEY_USAGE_SIG;
            break;
        }
-       else if( algo == 3 && addmode ) {
+       else if( algo == 4 && addmode ) {
            algo = PUBKEY_ALGO_ELGAMAL_E;
             *r_usage = PUBKEY_USAGE_ENC;
            break;
        }
+       else if( algo == 3 && opt.expert ) {
+           algo = PUBKEY_ALGO_DSA;
+           *r_usage=ask_key_flags(algo);
+           break;
+       }
        else if( algo == 2 ) {
            algo = PUBKEY_ALGO_DSA;
             *r_usage = PUBKEY_USAGE_SIG;
@@ -1358,69 +1439,74 @@ ask_algo (int addmode, unsigned int *r_usage)
 static unsigned
 ask_keysize( int algo )
 {
-    char *answer;
-    unsigned nbits;
+  unsigned nbits,min,def=2048,max=4096;
 
-    if (algo != PUBKEY_ALGO_DSA && algo != PUBKEY_ALGO_RSA) {
-        tty_printf (_("About to generate a new %s keypair.\n"
-                      "              minimum keysize is  768 bits\n"
-                      "              default keysize is 1024 bits\n"
-                      "    highest suggested keysize is 2048 bits\n"),
-                    pubkey_algo_to_string(algo) );
-    }
+  if(opt.expert)
+    min=512;
+  else
+    min=1024;
 
-    for(;;) {
-       answer = cpr_get("keygen.size",
-                         _("What keysize do you want? (1024) "));
-       cpr_kill_prompt();
-       nbits = *answer? atoi(answer): 1024;
-       m_free(answer);
-       if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
-           tty_printf(_("DSA only allows keysizes from 512 to 1024\n"));
-       else if( algo == PUBKEY_ALGO_RSA && nbits < 1024 )
-           tty_printf(_("keysize too small;"
-                        " 1024 is smallest value allowed for RSA.\n"));
-       else if( nbits < 768 )
-           tty_printf(_("keysize too small;"
-                        " 768 is smallest value allowed.\n"));
-       else if( nbits > 4096 ) {
-           /* It is ridiculous and an annoyance to use larger key sizes!
-            * GnuPG can handle much larger sizes; but it takes an eternity
-            * to create such a key (but less than the time the Sirius
-            * Computer Corporation needs to process one of the usual
-            * complaints) and {de,en}cryption although needs some time.
-            * So, before you complain about this limitation, I suggest that
-            * you start a discussion with Marvin about this theme and then
-            * do whatever you want. */
-           tty_printf(_("keysize too large; %d is largest value allowed.\n"),
-                                                                        4096);
+  switch(algo)
+    {
+    case PUBKEY_ALGO_DSA:
+      if(opt.expert)
+       {
+         def=1024;
+         max=1024;
        }
-       else if( nbits > 2048 && !cpr_enabled() ) {
-           tty_printf(
-               _("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? (y/N) ")) )
-             {
-               tty_printf(_("Okay, but keep in mind that your monitor "
-                            "and keyboard radiation is also very vulnerable "
-                            "to attacks!\n"));
-               break;
-             }
+      else
+       {
+         tty_printf(_("DSA keypair will have %u bits.\n"),1024);
+         return 1024;
        }
-       else
-           break;
+      break;
+
+    case PUBKEY_ALGO_RSA:
+      min=1024;
+      break;
     }
-    tty_printf(_("Requested keysize is %u bits\n"), nbits );
-    if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
-       nbits = ((nbits + 63) / 64) * 64;
-       tty_printf(_("rounded up to %u bits\n"), nbits );
+
+  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
+            pubkey_algo_to_string(algo),min,max);
+
+  for(;;)
+    {
+      char *prompt,*answer;
+
+#define PROMPTSTRING _("What keysize do you want? (%u) ")
+
+      prompt=m_alloc(strlen(PROMPTSTRING)+20);
+      sprintf(prompt,PROMPTSTRING,def);
+
+#undef PROMPTSTRING
+
+      answer = cpr_get("keygen.size",prompt);
+      cpr_kill_prompt();
+      nbits = *answer? atoi(answer): def;
+      m_free(prompt);
+      m_free(answer);
+      
+      if(nbits<min || nbits>max)
+       tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+                  pubkey_algo_to_string(algo),min,max);
+      else
+       break;
     }
-    else if( (nbits % 32) ) {
-       nbits = ((nbits + 31) / 32) * 32;
-       tty_printf(_("rounded up to %u bits\n"), nbits );
+
+  tty_printf(_("Requested keysize is %u bits\n"), nbits );
+
+  if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
+    {
+      nbits = ((nbits + 63) / 64) * 64;
+      tty_printf(_("rounded up to %u bits\n"), nbits );
     }
-    return nbits;
+  else if( (nbits % 32) )
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      tty_printf(_("rounded up to %u bits\n"), nbits );
+    }
+
+  return nbits;
 }
 
 
@@ -1428,7 +1514,7 @@ ask_keysize( int algo )
  * Parse an expire string and return it's value in days.
  * Returns -1 on error.
  */
-static int
+int
 parse_expire_string( const char *string )
 {
     int mult;
@@ -1460,7 +1546,7 @@ parse_expire_string( const char *string )
 
 /* 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)
 {
     char *answer;
     int valid_days=0;
@@ -1469,6 +1555,8 @@ ask_expire_interval(int object)
     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"
@@ -1478,6 +1566,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"
@@ -1495,44 +1585,64 @@ ask_expire_interval(int object)
      * date */
 
     answer = NULL;
-    for(;;) {
+    for(;;)
+      {
        u32 curtime=make_timestamp();
 
        m_free(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=m_alloc(strlen(PROMPTSTRING)+strlen(def_expire)+1);
+           sprintf(prompt,PROMPTSTRING,def_expire);
+#undef PROMPTSTRING
+
+           answer = cpr_get("siggen.valid",prompt);
+           m_free(prompt);
+
+           if(*answer=='\0')
+             answer=m_strdup(def_expire);
+         }
        cpr_kill_prompt();
        trim_spaces(answer);
        valid_days = parse_expire_string( answer );
        if( valid_days < 0 ) {
-           tty_printf(_("invalid value\n"));
-           continue;
+         tty_printf(_("invalid value\n"));
+         continue;
        }
 
-       if( !valid_days ) {
-           tty_printf(_("%s does not expire at all\n"),
-                      object==0?"Key":"Signature");
+       if( !valid_days )
+         {
+            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;
-           /* print the date when the key expires */
-           tty_printf(_("%s expires at %s\n"),
-                       object==0?"Key":"Signature",
-                       asctimestamp((ulong)(curtime + interval) ) );
-            /* FIXME: This check yields warning on alhas:
-               write a configure check and to this check here only for 32 bit machines */
-           if( (time_t)((ulong)(curtime+interval)) < 0 )
-               tty_printf(_("Your system can't display dates beyond 2038.\n"
-                   "However, it will be correctly handled up to 2106.\n"));
+         interval = valid_days * 86400L;
+
+         tty_printf(object==0
+                    ? _("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 */
+         if( (time_t)((ulong)(curtime+interval)) < 0 )
+           tty_printf(_("Your system can't display dates beyond 2038.\n"
+                        "However, it will be correctly handled up to 2106.\n"));
        }
 
        if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay",
-                                           _("Is this correct? (y/N) ")) )
-           break;
-    }
+                                                  _("Is this correct? (y/N) ")) )
+         break;
+      }
     m_free(answer);
     return interval;
 }
@@ -1540,7 +1650,7 @@ ask_expire_interval(int object)
 u32
 ask_expiredate()
 {
-    u32 x = ask_expire_interval(0);
+    u32 x = ask_expire_interval(0,NULL);
     return x? make_timestamp() + x : 0;
 }
 
@@ -1574,7 +1684,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;
@@ -1669,6 +1780,17 @@ ask_user_id( int mode )
        }
 
        for(;;) {
+            /* 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.
+               
+                 n = Change name
+                 c = Change comment
+                 e = Change email
+                 o = Okay (ready, continue)
+                 q = Quit
+             */
            const char *ansstr = _("NnCcEeOoQq");
 
            if( strlen(ansstr) != 10 )
@@ -2019,7 +2141,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 ) ) {
@@ -2130,7 +2252,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
@@ -2152,10 +2274,11 @@ read_parameter_file( const char *fname )
        { "Passphrase",     pPASSPHRASE },
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
+        { "Handle",         pHANDLE },
        { NULL, 0 }
     };
     IOBUF fp;
-    unsigned char *line;
+    byte *line;
     unsigned int maxlen, nline;
     char *p;
     int lnr;
@@ -2170,6 +2293,12 @@ read_parameter_file( const char *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;
@@ -2209,7 +2338,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;
            }
@@ -2269,7 +2400,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;
        }
@@ -2297,7 +2430,8 @@ read_parameter_file( const char *fname )
     }
     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 */
@@ -2350,7 +2484,7 @@ generate_keypair (const char *fname, const char *card_serialno,
   if (opt.batch && card_serialno)
     {
       /* We don't yet support unattended key generation. */
-      log_error (_("sorry, can't do this in batch mode\n"));
+      log_error (_("can't do this in batch mode\n"));
       return;
     }
   
@@ -2420,7 +2554,7 @@ generate_keypair (const char *fname, const char *card_serialno,
           sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
           r->next = para;
           para = r;
-          tty_printf(_("DSA keypair will have 1024 bits.\n"));
+          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" );
@@ -2474,7 +2608,7 @@ generate_keypair (const char *fname, const char *card_serialno,
       para = r;
     }
    
-  expire = ask_expire_interval(0);
+  expire = ask_expire_interval(0,NULL);
   r = m_alloc_clear( sizeof *r + 20 );
   r->key = pKEYEXPIRE;
   r->u.expire = expire;
@@ -2600,24 +2734,6 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
 
 
 static void
-print_status_key_created (int letter, PKT_public_key *pk)
-{
-  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);
-}
-
-static void
 do_generate_keypair( struct para_data_s *para,
                     struct output_control_s *outctrl, int card )
 {
@@ -2645,9 +2761,14 @@ do_generate_keypair( struct para_data_s *para,
            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;
            }
@@ -2669,10 +2790,15 @@ do_generate_keypair( struct para_data_s *para,
            outctrl->sec.newfname = NULL;
 
            oldmask = umask (077);
-           outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
+            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;
            }
@@ -2743,7 +2869,25 @@ do_generate_keypair( struct para_data_s *para,
                                get_parameter_uint (para, pKEYUSAGE));
     }
 
-    if( get_parameter( para, pSUBKEYTYPE ) )
+    /* 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,
+                           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 ) )
       {
         if (!card)
           {
@@ -2782,17 +2926,6 @@ do_generate_keypair( struct para_data_s *para,
         did_sub = 1;
       }
 
-    if (card && get_parameter (para, pAUTHKEYTYPE))
-      {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root,
-                           get_parameter_u32 (para, pKEYEXPIRE), para);
-        
-        if (!rc)
-          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 )
@@ -2879,7 +3012,7 @@ do_generate_keypair( struct para_data_s *para,
                tty_printf(_("Note that this key cannot be used for "
                             "encryption.  You may want to use\n"
                             "the command \"--edit-key\" to generate a "
-                            "secondary key for this purpose.\n") );
+                            "subkey for this purpose.\n") );
            }
        }
     }
@@ -2889,11 +3022,13 @@ 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 );
@@ -2923,6 +3058,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 );
@@ -2953,20 +3089,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;
@@ -2974,12 +3121,14 @@ 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 ) {
+    if (ask_pass)
+        dek = do_ask_passphrase (&s2k);
+    else if (passphrase) {
        s2k = m_alloc_secure( sizeof *s2k );
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
@@ -3090,7 +3239,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)
@@ -3288,7 +3437,13 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
 
     fname = make_filename (backup_dir, name_buffer, NULL);
     oldmask = umask (077);
-    fp = iobuf_create (fname);
+    if (is_secured_filename (fname))
+      {
+        fp = NULL;
+        errno = EPERM;
+      }
+    else
+      fp = iobuf_create (fname);
     umask (oldmask);
     if (!fp) 
       {
@@ -3313,9 +3468,25 @@ 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);