* keygen.c (keygen_set_std_prefs): Add SHA256 and BZip2 to default
[gnupg.git] / g10 / keygen.c
index d1c6e60..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 )
 {
@@ -185,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)
@@ -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)));
 
@@ -1196,6 +1270,100 @@ 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.
  *          and only if key flags are to be written the desired usage.
@@ -1211,21 +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 );
-    if (opt.expert)
-      tty_printf(    _("   (%d) RSA (sign and encrypt)\n"), 6 );
-    if (opt.expert && addmode)
-      tty_printf(    _("   (%d) RSA (auth only)\n"), 7 );
+        tty_printf(_("   (%d) RSA (encrypt only)\n"), 6 );
     if (opt.expert)
-      tty_printf(    _("   (%d) RSA (sign and auth)\n"), 8 );
-    if (opt.expert && addmode)
-      tty_printf(    _("   (%d) RSA (encrypt and auth)\n"), 9 );
-    if (opt.expert)
-      tty_printf(    _("  (%d) RSA (sign, encrypt and auth)\n"), 10 );
+      tty_printf(  _("   (%d) RSA (set your own capabilities)\n"), 7 );
 
     for(;;) {
        answer = cpr_get("keygen.algo",_("Your selection? "));
@@ -1236,46 +1398,31 @@ ask_algo (int addmode, unsigned int *r_usage)
            algo = 0;   /* create both keys */
            break;
        }
-       else if( algo == 10 && opt.expert ) {
-           algo = PUBKEY_ALGO_RSA;
-           *r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
-           break;
-       }
-       else if( algo == 9 && opt.expert && addmode) {
-           algo = PUBKEY_ALGO_RSA;
-           *r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH;
-           break;
-       }
-       else if( algo == 8 && opt.expert ) {
-           algo = PUBKEY_ALGO_RSA;
-           *r_usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
-           break;
-       }
-       else if( algo == 7 && opt.expert && addmode) {
-           algo = PUBKEY_ALGO_RSA;
-           *r_usage = PUBKEY_USAGE_AUTH;
-           break;
-       }
-       else if( algo == 6 && opt.expert ) {
+       else if( algo == 7 && 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 ) {
+       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;
@@ -1284,6 +1431,7 @@ ask_algo (int addmode, unsigned int *r_usage)
        else
            tty_printf(_("Invalid selection.\n"));
     }
+
     return algo;
 }
 
@@ -1291,68 +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? ")) ) {
-               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 );
+    }
+  else if( (nbits % 32) )
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      tty_printf(_("rounded up to %u bits\n"), nbits );
     }
-    return nbits;
+
+  return nbits;
 }
 
 
@@ -1360,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;
@@ -1392,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;
@@ -1401,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"
@@ -1410,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"
@@ -1427,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;
 }
@@ -1472,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;
 }
 
@@ -1506,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;
@@ -1601,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 )
@@ -1951,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 ) ) {
@@ -2062,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
@@ -2084,10 +2274,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;
@@ -2096,26 +2289,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;
        }
@@ -2139,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;
            }
@@ -2199,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;
        }
@@ -2222,12 +2425,13 @@ 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 */
@@ -2247,8 +2451,7 @@ read_parameter_file( const char *fname )
     }
 
     release_parameter_list( para );
-    if( strcmp( fname, "-" ) )
-       fclose(fp);
+    iobuf_close (fp);
 }
 
 
@@ -2281,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;
     }
   
@@ -2351,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" );
@@ -2385,11 +2588,12 @@ generate_keypair (const char *fname, const char *card_serialno,
            
           if (use)
             {
-              r = m_alloc_clear( sizeof *r + 20 );
+              r = m_alloc_clear( sizeof *r + 25 );
               r->key = pKEYUSAGE;
-              sprintf( r->u.value, "%s%s",
+              sprintf( r->u.value, "%s%s%s",
                        (use & PUBKEY_USAGE_SIG)? "sign ":"",
-                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
+                       (use & PUBKEY_USAGE_AUTH)? "auth":"" );
               r->next = para;
               para = r;
             }
@@ -2404,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;
@@ -2530,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 )
 {
@@ -2575,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;
            }
@@ -2599,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;
            }
@@ -2673,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)
           {
@@ -2712,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 )
@@ -2809,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") );
            }
        }
     }
@@ -2819,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 );
@@ -2853,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 );
@@ -2883,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;
@@ -2904,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? ") ) )
+                                                 _("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;
@@ -3020,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)
@@ -3028,7 +3247,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
   else
     use = PUBKEY_USAGE_AUTH;
   if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay",
-                                               _("Really create? ") ) )
+                                               _("Really create? (y/N) ")))
     goto leave;
 
   if (passphrase)
@@ -3218,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) 
       {
@@ -3243,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);