agent: Fix use of imported but unprotected openpgp keys.
authorWerner Koch <wk@gnupg.org>
Thu, 29 Jan 2015 15:26:07 +0000 (16:26 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 29 Jan 2015 15:26:07 +0000 (16:26 +0100)
* agent/agent.h (PRIVATE_KEY_OPENPGP_NONE): New.
* agent/command.c (do_one_keyinfo): Implement it.
* agent/findkey.c (agent_key_from_file): Ditto.
(agent_key_info_from_file): Ditto.
(agent_delete_key): Ditto.
* agent/protect.c (agent_private_key_type): Add detection for openpgp
"none" method.

Signed-off-by: Werner Koch <wk@gnupg.org>
agent/agent.h
agent/command.c
agent/cvt-openpgp.c
agent/findkey.c
agent/protect.c

index 4536242..f60061e 100644 (file)
@@ -248,7 +248,8 @@ enum
     PRIVATE_KEY_PROTECTED = 2,    /* The key is protected.  */
     PRIVATE_KEY_SHADOWED = 3,     /* The key is a stub for a smartcard
                                      based key.  */
-    PROTECTED_SHARED_SECRET = 4   /* RFU.  */
+    PROTECTED_SHARED_SECRET = 4,  /* RFU.  */
+    PRIVATE_KEY_OPENPGP_NONE = 5  /* openpgp-native with protection "none". */
   };
 
 
index d5644cb..ca28e9b 100644 (file)
@@ -1163,7 +1163,9 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
     {
       switch (keytype)
         {
-        case PRIVATE_KEY_CLEAR: protectionstr = "C"; keytypestr = "D";
+        case PRIVATE_KEY_CLEAR:
+        case PRIVATE_KEY_OPENPGP_NONE:
+          protectionstr = "C"; keytypestr = "D";
           break;
         case PRIVATE_KEY_PROTECTED: protectionstr = "P"; keytypestr = "D";
           break;
@@ -1801,12 +1803,12 @@ cmd_passwd (assuan_context_t ctx, char *line)
             }
         }
       if (!err && opt_preset)
-      {
+        {
          char hexgrip[40+1];
          bin2hex(grip, 20, hexgrip);
          err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass,
                                  ctrl->cache_ttl_opt_preset);
-      }
+        }
       xfree (newpass);
     }
   ctrl->in_passwd--;
index 8cf0023..5f94493 100644 (file)
@@ -1051,13 +1051,25 @@ convert_from_openpgp_native (ctrl_t ctrl,
   /* On success try to re-write the key.  */
   if (!err)
     {
-      unsigned char *protectedkey = NULL;
-      size_t protectedkeylen;
-
-      if (!agent_protect (*r_key, passphrase, &protectedkey, &protectedkeylen,
-                          ctrl->s2k_count))
-        agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
-      xfree (protectedkey);
+      if (*passphrase)
+        {
+          unsigned char *protectedkey = NULL;
+          size_t protectedkeylen;
+
+          if (!agent_protect (*r_key, passphrase,
+                              &protectedkey, &protectedkeylen,
+                              ctrl->s2k_count))
+            agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
+          xfree (protectedkey);
+        }
+      else
+        {
+          /* Empty passphrase: write key without protection.  */
+          agent_write_private_key (grip,
+                                   *r_key,
+                                   gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
+                                   1);
+        }
     }
 
   return err;
index 156102b..6f01789 100644 (file)
@@ -664,6 +664,22 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
     {
     case PRIVATE_KEY_CLEAR:
       break; /* no unprotection needed */
+    case PRIVATE_KEY_OPENPGP_NONE:
+      {
+        unsigned char *buf_new;
+        size_t buf_newlen;
+
+        rc = agent_unprotect (ctrl, buf, "", NULL, &buf_new, &buf_newlen);
+        if (rc)
+          log_error ("failed to convert unprotected openpgp key: %s\n",
+                     gpg_strerror (rc));
+        else
+          {
+            xfree (buf);
+            buf = buf_new;
+          }
+      }
+      break;
     case PRIVATE_KEY_PROTECTED:
       {
        char *desc_text_final;
@@ -1159,6 +1175,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
   switch (keytype)
     {
     case PRIVATE_KEY_CLEAR:
+    case PRIVATE_KEY_OPENPGP_NONE:
       break;
     case PRIVATE_KEY_PROTECTED:
       /* If we ever require it we could retrieve the comment fields
@@ -1230,6 +1247,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
   switch (agent_private_key_type (buf))
     {
     case PRIVATE_KEY_CLEAR:
+    case PRIVATE_KEY_OPENPGP_NONE:
     case PRIVATE_KEY_PROTECTED:
       {
         bin2hex (grip, 20, hexgrip);
index 01e72c2..cdb39fd 100644 (file)
@@ -1,6 +1,6 @@
 /* protect.c - Un/Protect a secret key
  * Copyright (C) 1998-2003, 2007, 2009, 2011 Free Software Foundation, Inc.
- * Copyright (C) 1998-2003, 2007, 2009, 2011, 2013 Werner Koch
+ * Copyright (C) 1998-2003, 2007, 2009, 2011, 2013-2015 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -1101,13 +1101,16 @@ agent_unprotect (ctrl_t ctrl,
    PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
    value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
    PRIVATE_KEY_PROTECTED for an protected private key or
-   PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
-   elsewhere. */
+   PRIVATE_KEY_SHADOWED for a sub key where the secret parts are
+   stored elsewhere.  Finally PRIVATE_KEY_OPENPGP_NONE may be returned
+   is the key is still in the openpgp-native format but without
+   protection.  */
 int
 agent_private_key_type (const unsigned char *privatekey)
 {
   const unsigned char *s;
   size_t n;
+  int i;
 
   s = privatekey;
   if (*s != '(')
@@ -1117,7 +1120,75 @@ agent_private_key_type (const unsigned char *privatekey)
   if (!n)
     return PRIVATE_KEY_UNKNOWN;
   if (smatch (&s, n, "protected-private-key"))
-    return PRIVATE_KEY_PROTECTED;
+    {
+      /* We need to check whether this is openpgp-native protected
+         with the protection method "none".  In that case we return a
+         different key type so that the caller knows that there is no
+         need to ask for a passphrase. */
+      if (*s != '(')
+        return PRIVATE_KEY_PROTECTED; /* Unknown sexp - assume protected. */
+      s++;
+      n = snext (&s);
+      if (!n)
+        return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+      s += n; /* Skip over the algo */
+
+      /* Find the (protected ...) list.  */
+      for (;;)
+        {
+          if (*s != '(')
+            return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+          s++;
+          n = snext (&s);
+          if (!n)
+            return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+          if (smatch (&s, n, "protected"))
+            break;
+          s += n;
+          i = 1;
+          if (sskip (&s, &i))
+            return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+        }
+      /* Found - Is this openpgp-native? */
+      n = snext (&s);
+      if (!n)
+        return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+      if (smatch (&s, n, "openpgp-native")) /* Yes.  */
+        {
+          if (*s != '(')
+            return PRIVATE_KEY_UNKNOWN; /* Unknown sexp. */
+          s++;
+          n = snext (&s);
+          if (!n)
+            return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+          s += n; /* Skip over "openpgp-private-key".  */
+          /* Find the (protection ...) list.  */
+          for (;;)
+            {
+              if (*s != '(')
+                return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+              s++;
+              n = snext (&s);
+              if (!n)
+                return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+              if (smatch (&s, n, "protection"))
+                break;
+              s += n;
+              i = 1;
+              if (sskip (&s, &i))
+                return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+            }
+          /* Found - Is the mode "none"? */
+          n = snext (&s);
+          if (!n)
+            return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
+          log_debug ("openpgp-native protection '%.*s'\n", (int)n, s);
+          if (smatch (&s, n, "none"))
+            return PRIVATE_KEY_OPENPGP_NONE;  /* Yes.  */
+        }
+
+      return PRIVATE_KEY_PROTECTED;
+    }
   if (smatch (&s, n, "shadowed-private-key"))
     return PRIVATE_KEY_SHADOWED;
   if (smatch (&s, n, "private-key"))