Mainly changes to adjust for the changed KSBA API.
[gnupg.git] / agent / genkey.c
index 1aca33b..1417abb 100644 (file)
@@ -1,5 +1,5 @@
 /* pksign.c - Generate a keypair
- *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *     Copyright (C) 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <ctype.h>
 #include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
 
 #include "agent.h"
-
+#include "i18n.h"
 
 static int
-store_key (GCRY_SEXP private, const char *passphrase)
+store_key (gcry_sexp_t private, const char *passphrase, int force)
 {
-  int i;
-  char *fname;
-  FILE *fp;
+  int rc;
   char *buf;
   size_t len;
   unsigned char grip[20];
-  char hexgrip[40+4+1];
   
   if ( !gcry_pk_get_keygrip (private, grip) )
     {
       log_error ("can't calculate keygrip\n");
-      return seterr (General_Error);
-    }
-  for (i=0; i < 20; i++)
-    sprintf (hexgrip+2*i, "%02X", grip[i]);
-  strcpy (hexgrip+40, ".key");
-
-  fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
-  if (!access (fname, F_OK))
-    {
-      log_error ("secret key file `%s' already exists - very strange\n",
-                 fname);
-      xfree (fname);
-      return seterr (General_Error);
-    }
-  fp = fopen (fname, "wbx");  /* FIXME: the x is a GNU extension - let
-                                 configure check whether this actually
-                                 works */
-  if (!fp) 
-    { 
-      log_error ("can't create `%s': %s\n", fname, strerror (errno));
-      xfree (fname);
-      return seterr (File_Create_Error);
+      return gpg_error (GPG_ERR_GENERAL);
     }
 
   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
   assert (len);
   buf = gcry_malloc_secure (len);
   if (!buf)
-    {
-      fclose (fp);
-      remove (fname);
-      xfree (fname);
-      return seterr (Out_Of_Core);
-    }
+      return out_of_core ();
   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
   assert (len);
 
   if (passphrase)
     {
       unsigned char *p;
-      int rc;
 
       rc = agent_protect (buf, passphrase, &p, &len);
       if (rc)
         {
-          fclose (fp);
-          remove (fname);
-          xfree (fname);
           xfree (buf);
           return rc;
         }
@@ -100,27 +65,22 @@ store_key (GCRY_SEXP private, const char *passphrase)
       buf = p;
     }
 
-  if (fwrite (buf, len, 1, fp) != 1)
-    {
-      log_error ("error writing `%s': %s\n", fname, strerror (errno));
-      fclose (fp);
-      remove (fname);
-      xfree (fname);
-      xfree (buf);
-      return seterr (File_Create_Error);
-    }
-  if ( fclose (fp) )
-    {
-      log_error ("error closing `%s': %s\n", fname, strerror (errno));
-      remove (fname);
-      xfree (fname);
-      xfree (buf);
-      return seterr (File_Create_Error);
-    }
-
-  xfree (fname);
+  rc = agent_write_private_key (grip, buf, len, force);
   xfree (buf);
-  return 0;
+  return rc;
+}
+
+/* Callback function to compare the first entered PIN with the one
+   currently being entered. */
+static int
+reenter_compare_cb (struct pin_entry_info_s *pi)
+{
+  const char *pin1 = pi->check_cb_arg;
+
+  if (!strcmp (pin1, pi->pin))
+    return 0; /* okay */
+  pi->cb_errtext = _("does not match - try again");
+  return -1;
 }
 
 
@@ -131,7 +91,7 @@ int
 agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
               FILE *outfp) 
 {
-  GCRY_SEXP s_keyparam, s_key, s_private, s_public;
+  gcry_sexp_t s_keyparam, s_key, s_private, s_public;
   struct pin_entry_info_s *pi, *pi2;
   int rc;
   size_t len;
@@ -140,43 +100,34 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
   rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
   if (rc)
     {
-      log_error ("failed to convert keyparam: %s\n", gcry_strerror (rc));
-      return seterr (Invalid_Data);
+      log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
+      return gpg_error (GPG_ERR_INV_DATA);
     }
 
-  /* Get the passphrase now, cause key generation may take a while */
+  /* Get the passphrase now, cause key generation may take a while. */
   {
-    const char *text1 = trans ("Please enter the passphrase to%0A"
+    const char *text1 = _("Please enter the passphrase to%0A"
                                "to protect your new key");
-    const char *text2 = trans ("Please re-enter this passphrase");
-    const char *nomatch = trans ("does not match - try again");
-    int tries = 0;
+    const char *text2 = _("Please re-enter this passphrase");
 
     pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
-    pi2 = pi + sizeof *pi;
+    pi2 = pi + (sizeof *pi + 100);
     pi->max_length = 100;
     pi->max_tries = 3;
     pi2->max_length = 100;
     pi2->max_tries = 3;
+    pi2->check_cb = reenter_compare_cb;
+    pi2->check_cb_arg = pi->pin;
 
-    rc = agent_askpin (text1, NULL, pi);
+    rc = agent_askpin (ctrl, text1, pi);
     if (!rc)
-      {
-        do 
-          {
-            rc = agent_askpin (text2, tries? nomatch:NULL, pi2);
-            tries++;
-          }
-        while (!rc && tries < 3 && strcmp (pi->pin, pi2->pin));
-        if (!rc && strcmp (pi->pin, pi2->pin))
-          rc = GNUPG_Canceled;
-      }
+      rc = agent_askpin (ctrl, text2, pi2);
     if (rc)
       return rc;
     if (!*pi->pin)
       {
         xfree (pi);
-        pi = NULL; /* use does not want a passphrase */
+        pi = NULL; /* User does not want a passphrase. */
       }
   }
 
@@ -184,9 +135,9 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
   gcry_sexp_release (s_keyparam);
   if (rc)
     {
-      log_error ("key generation failed: %s\n", gcry_strerror (rc));
+      log_error ("key generation failed: %s\n", gpg_strerror (rc));
       xfree (pi);
-      return map_gcry_err (rc);
+      return rc;
     }
 
   /* break out the parts */
@@ -196,7 +147,7 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
       log_error ("key generation failed: invalid return value\n");
       gcry_sexp_release (s_key);
       xfree (pi);
-      return seterr (Invalid_Data);
+      return gpg_error (GPG_ERR_INV_DATA);
     }
   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
   if (!s_public)
@@ -205,13 +156,13 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
       gcry_sexp_release (s_private);
       gcry_sexp_release (s_key);
       xfree (pi);
-      return seterr (Invalid_Data);
+      return gpg_error (GPG_ERR_INV_DATA);
     }
   gcry_sexp_release (s_key); s_key = NULL;
   
   /* store the secret key */
   log_debug ("storing private key\n");
-  rc = store_key (s_private, pi->pin);
+  rc = store_key (s_private, pi? pi->pin:NULL, 0);
   xfree (pi); pi = NULL;
   gcry_sexp_release (s_private);
   if (rc)
@@ -224,22 +175,24 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
   log_debug ("returning public key\n");
   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
   assert (len);
-  buf = xmalloc (len);
+  buf = xtrymalloc (len);
   if (!buf)
     {
+      gpg_error_t tmperr = out_of_core ();
       gcry_sexp_release (s_private);
       gcry_sexp_release (s_public);
-      return seterr (Out_Of_Core);
+      return tmperr;
     }
   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
   assert (len);
   if (fwrite (buf, len, 1, outfp) != 1)
     {
+      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
       log_error ("error writing public key: %s\n", strerror (errno));
       gcry_sexp_release (s_private);
       gcry_sexp_release (s_public);
       xfree (buf);
-      return seterr (File_Create_Error);
+      return tmperr;
     }
   gcry_sexp_release (s_public);
   xfree (buf);
@@ -247,3 +200,41 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
   return 0;
 }
 
+
+\f
+/* Apply a new passpahrse to the key S_SKEY and store it. */
+int
+agent_protect_and_store (CTRL ctrl, gcry_sexp_t s_skey) 
+{
+  struct pin_entry_info_s *pi, *pi2;
+  int rc;
+
+  {
+    const char *text1 = _("Please enter the new passphrase");
+    const char *text2 = _("Please re-enter this passphrase");
+
+    pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
+    pi2 = pi + (sizeof *pi + 100);
+    pi->max_length = 100;
+    pi->max_tries = 3;
+    pi2->max_length = 100;
+    pi2->max_tries = 3;
+    pi2->check_cb = reenter_compare_cb;
+    pi2->check_cb_arg = pi->pin;
+
+    rc = agent_askpin (ctrl, text1, pi);
+    if (!rc)
+      rc = agent_askpin (ctrl, text2, pi2);
+    if (rc)
+      return rc;
+    if (!*pi->pin)
+      {
+        xfree (pi);
+        pi = NULL; /* User does not want a passphrase. */
+      }
+  }
+
+  rc = store_key (s_skey, pi? pi->pin:NULL, 1);
+  xfree (pi);
+  return 0;
+}