agent: Allow gpg-protect-tool to handle openpgp-native protection.
[gnupg.git] / agent / genkey.c
index ecf676e..12c3e34 100644 (file)
@@ -1,5 +1,6 @@
 /* genkey.c - Generate a keypair
  * Copyright (C) 2002, 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH.
  *
  * This file is part of GnuPG.
  *
@@ -57,7 +58,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
     {
       unsigned char *p;
 
-      rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
+      rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
       if (rc)
         {
           xfree (buf);
@@ -154,13 +155,13 @@ take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn)
 
   if (opt.enforce_passphrase_constraints)
     {
-      err = agent_show_message (ctrl, desc, _("Enter new passphrase"));
+      err = agent_show_message (ctrl, desc, L_("Enter new passphrase"));
       if (!err)
         err = gpg_error (GPG_ERR_CANCELED);
     }
   else
     err = agent_get_confirmation (ctrl, desc,
-                                  anyway_btn, _("Enter new passphrase"), 0);
+                                  anyway_btn, L_("Enter new passphrase"), 0);
   return err;
 }
 
@@ -168,16 +169,18 @@ take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn)
 static int
 take_this_one_anyway (ctrl_t ctrl, const char *desc)
 {
-  return take_this_one_anyway2 (ctrl, desc, _("Take this one anyway"));
+  return take_this_one_anyway2 (ctrl, desc, L_("Take this one anyway"));
 }
 
 
 /* Check whether the passphrase PW is suitable. Returns 0 if the
    passphrase is suitable and true if it is not and the user should be
-   asked to provide a different one.  If SILENT is set, no message are
-   displayed.  */
+   asked to provide a different one.  If FAILED_CONSTRAINT is set, a
+   message describing the problem is returned in
+   *FAILED_CONSTRAINT.  */
 int
-check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
+check_passphrase_constraints (ctrl_t ctrl, const char *pw,
+                             char **failed_constraint)
 {
   gpg_error_t err = 0;
   unsigned int minlen = opt.min_passphrase_len;
@@ -186,6 +189,9 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
   char *msg2 = NULL;
   char *msg3 = NULL;
 
+  if (ctrl && ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
+    return 0;
+
   if (!pw)
     pw = "";
 
@@ -193,26 +199,31 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
   if (!*pw)
     {
       const char *desc = (opt.enforce_passphrase_constraints?
-                          _("You have not entered a passphrase!%0A"
-                            "An empty passphrase is not allowed.") :
-                          _("You have not entered a passphrase - "
-                            "this is in general a bad idea!%0A"
-                            "Please confirm that you do not want to "
-                            "have any protection on your key."));
-
-      if (silent)
-        return gpg_error (GPG_ERR_INV_PASSPHRASE);
-
-      err = take_this_one_anyway2 (ctrl, desc,
-                                   _("Yes, protection is not needed"));
+                          L_("You have not entered a passphrase!%0A"
+                             "An empty passphrase is not allowed.") :
+                          L_("You have not entered a passphrase - "
+                             "this is in general a bad idea!%0A"
+                             "Please confirm that you do not want to "
+                             "have any protection on your key."));
+
+      err = 1;
+      if (failed_constraint)
+       {
+         if (opt.enforce_passphrase_constraints)
+           *failed_constraint = xstrdup (desc);
+         else
+           err = take_this_one_anyway2 (ctrl, desc,
+                                        L_("Yes, protection is not needed"));
+       }
+
       goto leave;
     }
 
   /* Now check the constraints and collect the error messages unless
      in in silent mode which returns immediately.  */
-  if (utf8_charcount (pw) < minlen )
+  if (utf8_charcount (pw, -1) < minlen )
     {
-      if (silent)
+      if (!failed_constraint)
         {
           err = gpg_error (GPG_ERR_INV_PASSPHRASE);
           goto leave;
@@ -231,7 +242,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
 
   if (nonalpha_count (pw) < minnonalpha )
     {
-      if (silent)
+      if (!failed_constraint)
         {
           err = gpg_error (GPG_ERR_INV_PASSPHRASE);
           goto leave;
@@ -257,15 +268,15 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
   if (*pw && opt.check_passphrase_pattern &&
       check_passphrase_pattern (ctrl, pw))
     {
-      if (silent)
+      if (!failed_constraint)
         {
           err = gpg_error (GPG_ERR_INV_PASSPHRASE);
           goto leave;
         }
 
       msg3 = xtryasprintf
-        (_("A passphrase may not be a known term or match%%0A"
-           "certain pattern."));
+        (L_("A passphrase may not be a known term or match%%0A"
+            "certain pattern."));
       if (!msg3)
         {
           err = gpg_error_from_syserror ();
@@ -273,13 +284,13 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
         }
     }
 
-  if (msg1 || msg2 || msg3)
+  if (failed_constraint && (msg1 || msg2 || msg3))
     {
       char *msg;
       size_t n;
 
       msg = strconcat
-        (_("Warning: You have entered an insecure passphrase."),
+        (L_("Warning: You have entered an insecure passphrase."),
          "%0A%0A",
          msg1? msg1 : "", msg1? "%0A" : "",
          msg2? msg2 : "", msg2? "%0A" : "",
@@ -295,9 +306,14 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
       if (n > 3 && !strcmp (msg + n - 3, "%0A"))
         msg[n-3] = 0;
 
-      /* Show error messages.  */
-      err = take_this_one_anyway (ctrl, msg);
-      xfree (msg);
+      err = 1;
+      if (opt.enforce_passphrase_constraints)
+       *failed_constraint = msg;
+      else
+       {
+         err = take_this_one_anyway (ctrl, msg);
+         xfree (msg);
+       }
     }
 
  leave:
@@ -310,14 +326,14 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
 
 /* Callback function to compare the first entered PIN with the one
    currently being entered. */
-static int
+static gpg_error_t
 reenter_compare_cb (struct pin_entry_info_s *pi)
 {
   const char *pin1 = pi->check_cb_arg;
 
   if (!strcmp (pin1, pi->pin))
     return 0; /* okay */
-  return -1;
+  return gpg_error (GPG_ERR_BAD_PASSPHRASE);
 }
 
 
@@ -332,8 +348,8 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
 {
   gpg_error_t err;
   const char *text1 = prompt;
-  const char *text2 = _("Please re-enter this passphrase");
-  const char *initial_errtext = NULL;
+  const char *text2 = L_("Please re-enter this passphrase");
+  char *initial_errtext = NULL;
   struct pin_entry_info_s *pi, *pi2;
 
   *r_passphrase = NULL;
@@ -358,23 +374,32 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
        return err;
     }
 
-  pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
-  pi2 = pi + (sizeof *pi + 100);
-  pi->max_length = 100;
+  pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
+  if (!pi)
+    return gpg_error_from_syserror ();
+  pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1);
+  if (!pi2)
+    {
+      err = gpg_error_from_syserror ();
+      xfree (pi2);
+      return err;
+    }
+  pi->max_length = MAX_PASSPHRASE_LEN + 1;
   pi->max_tries = 3;
   pi->with_qualitybar = 1;
   pi->with_repeat = 1;
-  pi2->max_length = 100;
+  pi2->max_length = MAX_PASSPHRASE_LEN + 1;
   pi2->max_tries = 3;
   pi2->check_cb = reenter_compare_cb;
   pi2->check_cb_arg = pi->pin;
 
  next_try:
-  err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
+  err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, NULL, 0);
+  xfree (initial_errtext);
   initial_errtext = NULL;
   if (!err)
     {
-      if (check_passphrase_constraints (ctrl, pi->pin, 0))
+      if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext))
         {
           pi->failed_tries = 0;
           pi2->failed_tries = 0;
@@ -384,12 +409,14 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
          it already did the repetition check, ask to confirm it.  */
       if (*pi->pin && !pi->repeat_okay)
         {
-          err = agent_askpin (ctrl, text2, NULL, NULL, pi2);
-          if (err == -1)
+          err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL, 0);
+          if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
             { /* The re-entered one did not match and the user did not
                  hit cancel. */
-              initial_errtext = _("does not match - try again");
-              goto next_try;
+              initial_errtext = xtrystrdup (L_("does not match - try again"));
+              if (initial_errtext)
+                goto next_try;
+              err = gpg_error_from_syserror ();
             }
         }
     }
@@ -401,6 +428,9 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
       if (!*r_passphrase)
         err = gpg_error_from_syserror ();
     }
+
+  xfree (initial_errtext);
+  xfree (pi2);
   xfree (pi);
   return err;
 }
@@ -447,8 +477,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
   else
     {
       rc = agent_ask_new_passphrase (ctrl,
-                                     _("Please enter the passphrase to%0A"
-                                       "protect your new key"),
+                                     L_("Please enter the passphrase to%0A"
+                                        "protect your new key"),
                                      &passphrase_buffer);
       if (rc)
         return rc;
@@ -573,7 +603,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
           *passphrase_addr = NULL;
         }
       err = agent_ask_new_passphrase (ctrl,
-                                      _("Please enter the new passphrase"),
+                                      L_("Please enter the new passphrase"),
                                       &pass);
       if (!err)
         err = store_key (s_skey, pass, 1, ctrl->s2k_count);