Made card key generate with backup key work for 2048 bit.
authorWerner Koch <wk@gnupg.org>
Fri, 15 May 2009 19:26:46 +0000 (19:26 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 15 May 2009 19:26:46 +0000 (19:26 +0000)
Improved card key generation prompts.

doc/gpg-agent.texi
g10/ChangeLog
g10/call-agent.c
g10/call-agent.h
g10/card-util.c
g10/keydb.h
g10/keygen.c
g10/passphrase.c
scd/app-openpgp.c

index dad0501..16dd521 100644 (file)
@@ -579,8 +579,10 @@ manually.  Comment lines, indicated by a leading hash mark, as well as
 empty lines are ignored.  An entry starts with optional whitespace,
 followed by the keygrip of the key given as 40 hex digits, optionally
 followed by the caching TTL in seconds and another optional field for
-arbitrary flags.  The keygrip may be prefixed with a @code{!} to
-disable this entry.
+arbitrary flags.  A non-zero TTL overrides the global default as
+set by @option{--default-cache-ttl-ssh}.
+
+The keygrip may be prefixed with a @code{!} to disable an entry entry.
     
 The following example lists exactly one key.  Note that keys available
 through a OpenPGP smartcard in the active smartcard reader are
@@ -1054,7 +1056,7 @@ special handling of passphrases.  This command uses a syntax which helps
 clients to use the agent with minimum effort.
 
 @example
-  GET_PASSPHRASE [--data] [--check] [--no-ask] @var{cache_id} [@var{error_message} @var{prompt} @var{description}]
+  GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]] [--qualitybar] @var{cache_id} [@var{error_message} @var{prompt} @var{description}]
 @end example
 
 @var{cache_id} is expected to be a string used to identify a cached
@@ -1089,6 +1091,9 @@ If the option @option{--no-ask} is used and the passphrase is not in the
 cache the user will not be asked to enter a passphrase but the error
 code @code{GPG_ERR_NO_DATA} is returned.  
 
+If the option @option{--qualitybar} is used and a minimum passphrase
+length has been configured, a visual indication of the entered
+passphrase quality is shown.
 
 @example
   CLEAR_PASSPHRASE @var{cache_id}
index bd54d19..1f97512 100644 (file)
@@ -1,8 +1,29 @@
+2009-05-15  Werner Koch  <wk@g10code.com>
+
+       * keygen.c (gen_card_key_with_backup): Get the size of the key
+       from the card.
+       * call-agent.h (struct agent_card_info_s): Add field KEY_ATTR.
+       * call-agent.c (learn_status_cb): Support KEY-ATTR.
+       * card-util.c (card_status): Print key attributes.
+
 2009-05-15  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpg.c (gpgconf_list): Remove dead entry "allow-pka-lookup" (a
        verify option for a couple of years now).
 
+2009-05-14  Werner Koch  <wk@g10code.com>
+
+       * call-agent.c (agent_get_passphrase): Add arg CHECK.
+       * passphrase.c (passphrase_get): Pass new arg.
+
+       * keygen.c (gen_card_key_with_backup): Print a status error.
+       (do_generate_keypair): Ditto.
+       (do_ask_passphrase): Add arg MODE.
+       (generate_raw_key): Call with mode 1.
+       * passphrase.c (ask_passphrase): Remove becuase it is not used.
+       (passphrase_to_dek): Factor code out to ...
+       (passphrase_to_dek_ext): .. New.  Add args CUSTDESC and CUSTPROMPT.
+
 2009-05-13  Werner Koch  <wk@g10code.com>
 
        * keygen.c (parse_expire_string): Base ISO date string at noon.
index 444048a..c8a2013 100644 (file)
@@ -325,7 +325,19 @@ learn_status_cb (void *opaque, const char *line)
       else if (no == 3)
         parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
     }
-  
+  else if (keywordlen == 8 && !memcmp (keyword, "KEY-ATTR", keywordlen))
+    {
+      int keyno, algo, nbits;
+
+      sscanf (line, "%d %d %d", &keyno, &algo, &nbits);
+      keyno--;
+      if (keyno >= 0 && keyno < DIM (parm->key_attr))
+        {
+          parm->key_attr[keyno].algo = algo;
+          parm->key_attr[keyno].nbits = nbits;
+        }
+    }
+
   return 0;
 }
 
@@ -343,6 +355,9 @@ agent_learn (struct agent_card_info_s *info)
   rc = assuan_transact (agent_ctx, "LEARN --send",
                         dummy_data_cb, NULL, default_inq_cb, NULL,
                         learn_status_cb, info);
+  /* Also try to get the key attributes.  */
+  if (!rc)
+    agent_scd_getattr ("KEY-ATTR", info);
   
   return rc;
 }
@@ -535,7 +550,6 @@ scd_genkey_cb (void *opaque, const char *line)
   int keywordlen;
   gpg_error_t rc;
 
-  log_debug ("got status line `%s'\n", line);
   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
     ;
   while (spacep (line))
@@ -827,6 +841,7 @@ agent_get_passphrase (const char *cache_id,
                       const char *prompt,
                       const char *desc_msg,
                       int repeat,
+                      int check,
                       char **r_passphrase)
 {
   int rc;
@@ -863,8 +878,9 @@ agent_get_passphrase (const char *cache_id,
       goto no_mem;
 
   snprintf (line, DIM(line)-1, 
-            "GET_PASSPHRASE --data --repeat=%d -- %s %s %s %s", 
+            "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s", 
             repeat, 
+            check? " --check --qualitybar":"",
             arg1? arg1:"X",
             arg2? arg2:"X",
             arg3? arg3:"X",
index ebe37b1..577926e 100644 (file)
@@ -53,6 +53,10 @@ struct agent_card_info_s
   int is_v2;         /* True if this is a v2 card.  */
   int chvmaxlen[3];  /* Maximum allowed length of a CHV. */
   int chvretry[3];   /* Allowed retries for the CHV; 0 = blocked. */
+  struct {           /* Array with key attributes.  */
+    int algo;              /* Algorithm identifier.  */
+    unsigned int nbits;    /* Supported keysize.  */
+  } key_attr[3];      
 };
 
 struct agent_card_genkey_s {
@@ -116,6 +120,7 @@ gpg_error_t agent_get_passphrase (const char *cache_id,
                                   const char *prompt,
                                   const char *desc_msg,
                                   int repeat,
+                                  int check,
                                   char **r_passphrase);
 
 /* Send the CLEAR_PASSPHRASE command to the agent.  */
index 1d26366..7d36ebf 100644 (file)
@@ -443,6 +443,10 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
       fputs (":\n", fp);
 
       fprintf (fp, "forcepin:%d:::\n", !info.chv1_cached);
+      for (i=0; i < DIM (info.key_attr); i++)
+        if (info.key_attr[0].algo)
+          fprintf (fp, "keyattr:%d:%d:%u:\n", i+1,
+                   info.key_attr[i].algo, info.key_attr[i].nbits);
       fprintf (fp, "maxpinlen:%d:%d:%d:\n",
                    info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]);
       fprintf (fp, "pinretry:%d:%d:%d:\n",
@@ -518,6 +522,16 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
         }
       tty_fprintf (fp,    "Signature PIN ....: %s\n",
                    info.chv1_cached? _("not forced"): _("forced"));
+      if (info.key_attr[0].algo)
+        {
+          tty_fprintf (fp,    "Key attributes ...:");
+          for (i=0; i < DIM (info.key_attr); i++)
+            tty_fprintf (fp, " %u%c",
+                         info.key_attr[i].nbits,
+                         info.key_attr[i].algo == 1? 'R':
+                         info.key_attr[i].algo == 17? 'D': '?');
+          tty_fprintf (fp, "\n");
+        }
       tty_fprintf (fp,    "Max. PIN lengths .: %d %d %d\n",
                    info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]);
       tty_fprintf (fp,    "PIN retry counter : %d %d %d\n",
@@ -1077,7 +1091,7 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1)
 
   *forced_chv1 = !info->chv1_cached;
   if (*forced_chv1)
-    { /* Switch of the forced mode so that during key generation we
+    { /* Switch off the forced mode so that during key generation we
          don't get bothered with PIN queries for each
          self-signature. */
       rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1, info->serialno);
index 4e82458..ca3ca77 100644 (file)
@@ -202,11 +202,11 @@ int  have_static_passphrase(void);
 void set_passphrase_from_string(const char *pass);
 void read_passphrase_from_fd( int fd );
 void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo );
-char *ask_passphrase (const char *description,
-                      const char *tryagain_text,
-                      const char *promptid,
-                      const char *prompt, 
-                      const char *cacheid, int *canceled);
+DEK *passphrase_to_dek_ext(u32 *keyid, int pubkey_algo,
+                           int cipher_algo, STRING2KEY *s2k, int mode,
+                           const char *tryagain_text,
+                           const char *custdesc, const char *custprompt,
+                           int *canceled);
 DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
                        int cipher_algo, STRING2KEY *s2k, int mode,
                         const char *tryagain_text, int *canceled);
index 8afa74e..96c6833 100644 (file)
@@ -2153,21 +2153,28 @@ ask_user_id( int mode )
 }
 
 
+/*  MODE  0 - standard
+          1 - Ask for passphrase of the card backup key.  */
 static DEK *
-do_ask_passphrase ( STRING2KEY **ret_s2k, int *r_canceled )
+do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
 {
     DEK *dek = NULL;
     STRING2KEY *s2k;
     const char *errtext = NULL;
+    const char *custdesc = NULL;
 
     tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
 
+    if (mode == 1)
+      custdesc = _("Please enter a passphrase to protect the off-card "
+                   "backup of the new encryption key.");
+
     s2k = xmalloc_secure( sizeof *s2k );
     for(;;) {
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
-       dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,
-                                 errtext, r_canceled);
+       dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
+                                     errtext, custdesc, NULL, r_canceled);
         if (!dek && *r_canceled) {
            xfree(dek); dek = NULL;
            xfree(s2k); s2k = NULL;
@@ -2587,7 +2594,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       STRING2KEY *s2k;
       DEK *dek;
 
-      dek = do_ask_passphrase ( &s2k, &canceled );
+      dek = do_ask_passphrase (&s2k, 0, &canceled);
       if (dek)
         {
           r = xmalloc_clear( sizeof *r );
@@ -3085,7 +3092,7 @@ generate_keypair (const char *fname, const char *card_serialno,
   para = r;
     
   canceled = 0;
-  dek = card_serialno? NULL : do_ask_passphrase ( &s2k, &canceled );
+  dek = card_serialno? NULL : do_ask_passphrase (&s2k, 0, &canceled);
   if( dek )
     {
       r = xmalloc_clear( sizeof *r );
@@ -3143,7 +3150,7 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
       log_info(_("keysize rounded up to %u bits\n"), nbits );
     }
 
-  dek = do_ask_passphrase (&s2k, &canceled);
+  dek = do_ask_passphrase (&s2k, 1, &canceled);
   if (canceled)
     {
       rc = gpg_error (GPG_ERR_CANCELED);
@@ -3547,6 +3554,7 @@ 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) );
+      write_status_error (card? "card_key_generate":"key_generate", rc);
       print_status_key_not_created ( get_parameter_value (para, pHANDLE) );
     }
   else
@@ -3660,7 +3668,7 @@ generate_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock)
   
   canceled = 0;
   if (ask_pass)
-    dek = do_ask_passphrase (&s2k, &canceled);
+    dek = do_ask_passphrase (&s2k, 0, &canceled);
   else if (passphrase)
     {
       s2k = xmalloc_secure ( sizeof *s2k );
@@ -3951,19 +3959,35 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
   PKT_public_key *pk;
   size_t n;
   int i;
+  unsigned int nbits;
+    
+  /* Get the size of the key directly from the card.  */
+  {
+    struct agent_card_info_s info;
+    
+    memset (&info, 0, sizeof info);
+    if (!agent_scd_getattr ("KEY-ATTR", &info)
+        && info.key_attr[1].algo)
+      nbits = info.key_attr[1].nbits;
+    else
+      nbits = 1024; /* All pre-v2.0 cards.  */
+    agent_release_card_info (&info);
+  }
 
-  rc = generate_raw_key (algo, 1024, timestamp,
+  /* Create a key of this size in memory.  */
+  rc = generate_raw_key (algo, nbits, timestamp,
                          &sk_unprotected, &sk_protected);
   if (rc)
     return rc;
 
-  /* First, store the key to the card. */
+  /* Store the key to the card. */
   rc = save_unprotected_key_to_card (sk_unprotected, keyno);
   if (rc)
     {
       log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
       free_secret_key (sk_unprotected);
       free_secret_key (sk_protected);
+      write_status_error ("save_key_to_card", rc);
       return rc;
     }
 
index 8b952f7..f5d3013 100644 (file)
@@ -236,7 +236,8 @@ read_passphrase_from_fd( int fd )
 /*
  * Ask the GPG Agent for the passphrase.
  * Mode 0:  Allow cached passphrase
- *      1:  No cached passphrase FIXME: Not really implemented
+ *      1:  No cached passphrase; that is we are asking for a new passphrase
+ *          FIXME: Only partially implemented
  *
  * Note that TRYAGAIN_TEXT must not be translated.  If CANCELED is not
  * NULL, the function does set it to 1 if the user canceled the
@@ -260,6 +261,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
   char *my_prompt;
   char hexfprbuf[20*2+1];
   const char *my_cacheid;
+  int check = (mode == 1);
 
   if (canceled)
     *canceled = 0;
@@ -347,7 +349,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
   my_prompt = custom_prompt ? native_to_utf8 (custom_prompt): NULL;
 
   rc = agent_get_passphrase (my_cacheid, tryagain_text, my_prompt, atext,
-                             repeat, &pw);
+                             repeat, check, &pw);
   
   xfree (my_prompt);
   xfree (atext); atext = NULL;
@@ -432,54 +434,6 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
 }
 
 
-/****************
- * Ask for a passphrase and return that string.
- */
-char *
-ask_passphrase (const char *description,
-                const char *tryagain_text,
-                const char *promptid,
-                const char *prompt,
-                const char *cacheid, int *canceled)
-{
-  char *pw = NULL;
-
-  (void)promptid;
-  
-  if (canceled)
-    *canceled = 0;
-
-  if (!opt.batch && description)
-    {
-      if (strchr (description, '%'))
-        {
-          char *tmp = percent_plus_unescape (description, 0xff);
-          if (!tmp)
-            log_fatal(_("out of core\n"));
-          tty_printf ("\n%s\n", tmp);
-          xfree (tmp);
-        }
-      else
-        tty_printf ("\n%s\n",description);
-    }
-               
-  if (have_static_passphrase ()) 
-    {
-      pw = xmalloc_secure (strlen(fd_passwd)+1);
-      strcpy (pw, fd_passwd);
-    }
-  else
-    pw = passphrase_get (NULL, 0, cacheid, 0,
-                         tryagain_text, description, prompt,
-                         canceled );
-
-  if (!pw || !*pw)
-    write_status( STATUS_MISSING_PASSPHRASE );
-
-  return pw;
-}
-
-
 /* Return a new DEK object Using the string-to-key sepcifier S2K.  Use
    KEYID and PUBKEY_ALGO to prompt the user.  Returns NULL is the user
    selected to cancel the passphrase entry and if CANCELED is not
@@ -490,9 +444,11 @@ ask_passphrase (const char *description,
         2:  Ditto, but change the text to "repeat entry"
 */
 DEK *
-passphrase_to_dek (u32 *keyid, int pubkey_algo,
-                  int cipher_algo, STRING2KEY *s2k, int mode,
-                   const char *tryagain_text, int *canceled)
+passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
+                       int cipher_algo, STRING2KEY *s2k, int mode,
+                       const char *tryagain_text, 
+                       const char *custdesc, const char *custprompt,
+                       int *canceled)
 {
   char *pw = NULL;
   DEK *dek;
@@ -612,7 +568,7 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
       /* Divert to the gpg-agent. */
       pw = passphrase_get ( keyid, mode == 2, NULL,
                             mode == 2? opt.passwd_repeat: 0,
-                            tryagain_text, NULL, NULL, canceled );
+                            tryagain_text, custdesc, custprompt, canceled);
       if (*canceled)
         {
           xfree (pw);
@@ -637,3 +593,14 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
   last_pw = pw;
   return dek;
 }
+
+
+DEK *
+passphrase_to_dek (u32 *keyid, int pubkey_algo,
+                  int cipher_algo, STRING2KEY *s2k, int mode,
+                   const char *tryagain_text, int *canceled)
+{
+  return passphrase_to_dek_ext (keyid, pubkey_algo, cipher_algo,
+                                s2k, mode, tryagain_text, NULL, NULL,
+                                canceled);
+}
index a633fea..02c1d33 100644 (file)
@@ -2368,6 +2368,9 @@ do_writekey (app_t app, ctrl_t ctrl,
 
   maxbits = app->app_local->keyattr[keyno].n_bits;
   nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0;
+  if (opt.verbose)
+    log_info ("RSA modulus size is %u bits (%u bytes)\n", 
+              nbits, (unsigned int)rsa_n_len);
   if (nbits != maxbits)
     {
       log_error (_("RSA modulus missing or not of size %d bits\n"),