gpg: First take on PKT_ENCRYPTED_AEAD.
[gnupg.git] / agent / learncard.c
index 8b2c7ad..abe1dd0 100644 (file)
@@ -1,11 +1,11 @@
 /* learncard.c - Handle the LEARN command
- *     Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2003, 2004, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,9 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -34,7 +32,8 @@
 
 /* Structures used by the callback mechanism to convey information
    pertaining to key pairs.  */
-struct keypair_info_s {
+struct keypair_info_s
+{
   struct keypair_info_s *next;
   int no_cert;
   char *id;          /* points into grip */
@@ -45,24 +44,27 @@ struct keypair_info_s {
 };
 typedef struct keypair_info_s *KEYPAIR_INFO;
 
-struct kpinfo_cb_parm_s {
+struct kpinfo_cb_parm_s
+{
+  ctrl_t ctrl;
   int error;
   KEYPAIR_INFO info;
 };
 
 
-
 /* Structures used by the callback mechanism to convey information
    pertaining to certificates.  */
 struct certinfo_s {
   struct certinfo_s *next;
-  int type;  
+  int type;
   int done;
   char id[1];
 };
 typedef struct certinfo_s *CERTINFO;
 
-struct certinfo_cb_parm_s {
+struct certinfo_cb_parm_s
+{
+  ctrl_t ctrl;
   int error;
   CERTINFO info;
 };
@@ -73,12 +75,12 @@ struct certinfo_cb_parm_s {
 struct sinfo_s {
   struct sinfo_s *next;
   char *data;       /* Points into keyword. */
-  char keyword[1];  
+  char keyword[1];
 };
-typedef struct sinfo_s *SINFO;  
+typedef struct sinfo_s *SINFO;
 
 struct sinfo_cb_parm_s {
-  int error;;
+  int error;
   SINFO info;
 };
 
@@ -131,7 +133,12 @@ kpinfo_cb (void *opaque, const char *line)
   char *p;
 
   if (parm->error)
-    return; /* no need to gather data after an error coccured */
+    return; /* no need to gather data after an error occurred */
+
+  if ((parm->error = agent_write_status (parm->ctrl, "PROGRESS",
+                                         "learncard", "k", "0", "0", NULL)))
+    return;
+
   item = xtrycalloc (1, sizeof *item + strlen (line));
   if (!item)
     {
@@ -165,7 +172,7 @@ kpinfo_cb (void *opaque, const char *line)
       return;
     }
   *p = 0; /* ignore trailing stuff */
-  
+
   /* store it */
   item->next = parm->info;
   parm->info = item;
@@ -183,7 +190,11 @@ certinfo_cb (void *opaque, const char *line)
   char *p, *pend;
 
   if (parm->error)
-    return; /* no need to gather data after an error coccured */
+    return; /* no need to gather data after an error occurred */
+
+  if ((parm->error = agent_write_status (parm->ctrl, "PROGRESS",
+                                         "learncard", "c", "0", "0", NULL)))
+    return;
 
   type = strtol (line, &p, 10);
   while (spacep (p))
@@ -191,7 +202,7 @@ certinfo_cb (void *opaque, const char *line)
   for (pend = p; *pend && !spacep (pend); pend++)
     ;
   if (p == pend || !*p)
-    { 
+    {
       parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
       return;
     }
@@ -221,7 +232,7 @@ sinfo_cb (void *opaque, const char *keyword, size_t keywordlen,
   SINFO item;
 
   if (sparm->error)
-    return; /* no need to gather data after an error coccured */
+    return; /* no need to gather data after an error occurred */
 
   item = xtrycalloc (1, sizeof *item + keywordlen + 1 + strlen (data));
   if (!item)
@@ -247,13 +258,27 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
   int rc;
   char *derbuf;
   size_t derbuflen;
-  
+
   rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen);
   if (rc)
     {
-      log_error ("error reading certificate: %s\n",
-                 gpg_strerror (rc));
-      return rc;
+      const char *action;
+
+      switch (gpg_err_code (rc))
+        {
+        case GPG_ERR_INV_ID:
+        case GPG_ERR_NOT_FOUND:
+          action = " - ignored";
+          break;
+        default:
+          action = "";
+          break;
+        }
+      if (opt.verbose || !*action)
+        log_info ("error reading certificate '%s': %s%s\n",
+                  id? id:"?", gpg_strerror (rc), action);
+
+      return *action? 0 : rc;
     }
 
   rc = assuan_send_data (assuan_context, derbuf, derbuflen);
@@ -271,26 +296,28 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
   return 0;
 }
 
-/* Perform the learn operation.  If ASSUAN_CONTEXT is not NULL all new
-   certificates are send back via Assuan.  */
+/* Perform the learn operation.  If ASSUAN_CONTEXT is not NULL and
+   SEND is true all new certificates are send back via Assuan.  */
 int
-agent_handle_learn (ctrl_t ctrl, void *assuan_context)
+agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
 {
   int rc;
   struct kpinfo_cb_parm_s parm;
   struct certinfo_cb_parm_s cparm;
   struct sinfo_cb_parm_s sparm;
-  char *serialno = NULL;
+  const char *serialno = NULL;
   KEYPAIR_INFO item;
   SINFO sitem;
   unsigned char grip[20];
   char *p;
   int i;
-  static int certtype_list[] = { 
+  static int certtype_list[] = {
+    111, /* Root CA */
     101, /* trusted */
     102, /* useful */
     100, /* regular */
-    /* We don't include 110 here because gpgsm can't handle it. */
+    /* We don't include 110 here because gpgsm can't handle that
+       special root CA format. */
     -1 /* end of list */
   };
 
@@ -298,11 +325,8 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
   memset (&parm, 0, sizeof parm);
   memset (&cparm, 0, sizeof cparm);
   memset (&sparm, 0, sizeof sparm);
-
-  /* Check whether a card is present and get the serial number */
-  rc = agent_card_serialno (ctrl, &serialno);
-  if (rc)
-    goto leave;
+  parm.ctrl = ctrl;
+  cparm.ctrl = ctrl;
 
   /* Now gather all the available info. */
   rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm,
@@ -314,18 +338,24 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
       log_debug ("agent_card_learn failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
-  
-  log_info ("card has S/N: %s\n", serialno);
 
   /* Pass on all the collected status information. */
-  if (assuan_context)
+  for (sitem = sparm.info; sitem; sitem = sitem->next)
     {
-      for (sitem = sparm.info; sitem; sitem = sitem->next)
-        {
-          assuan_write_status (assuan_context, sitem->keyword, sitem->data);
-        }
+      if (!strcmp (sitem->keyword, "SERIALNO"))
+        serialno = sitem->data;
+      if (assuan_context)
+        assuan_write_status (assuan_context, sitem->keyword, sitem->data);
+    }
+
+  if (!serialno)
+    {
+      rc = GPG_ERR_NOT_FOUND;
+      goto leave;
     }
 
+  log_info ("card has S/N: %s\n", serialno);
+
   /* Write out the certificates in a standard order. */
   for (i=0; certtype_list[i] != -1; i++)
     {
@@ -338,8 +368,8 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
           if (opt.verbose)
             log_info ("          id: %s    (type=%d)\n",
                       citem->id, citem->type);
-          
-          if (assuan_context)
+
+          if (assuan_context && send)
             {
               rc = send_cert_back (ctrl, citem->id, assuan_context);
               if (rc)
@@ -348,11 +378,10 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
             }
         }
     }
-  
+
   for (item = parm.info; item; item = item->next)
     {
-      unsigned char *pubkey, *shdkey;
-      size_t n;
+      unsigned char *pubkey;
 
       if (opt.verbose)
         log_info ("          id: %s    (grip=%s)\n", item->id, item->hexgrip);
@@ -360,12 +389,18 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
       if (item->no_cert)
         continue; /* No public key yet available. */
 
+      if (assuan_context)
+        {
+          agent_write_status (ctrl, "KEYPAIRINFO",
+                              item->hexgrip, item->id, NULL);
+        }
+
       for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
         grip[i] = xtoi_2 (p);
-      
-      if (!agent_key_available (grip))
+
+      if (!force && !agent_key_available (grip))
         continue; /* The key is already available. */
-      
+
       /* Unknown key - store it. */
       rc = agent_card_readkey (ctrl, item->id, &pubkey);
       if (rc)
@@ -374,41 +409,18 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
           goto leave;
         }
 
-      {
-        unsigned char *shadow_info = make_shadow_info (serialno, item->id);
-        if (!shadow_info)
-          {
-            rc = gpg_error (GPG_ERR_ENOMEM);
-            xfree (pubkey);
-            goto leave;
-          }
-        rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
-        xfree (shadow_info);
-      }
+      rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force);
       xfree (pubkey);
       if (rc)
-        {
-          log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
-          goto leave;
-        }
-      n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
-      assert (n);
-
-      rc = agent_write_private_key (grip, shdkey, n, 0);
-      xfree (shdkey);
-      if (rc)
-        {
-          log_error ("error writing key: %s\n", gpg_strerror (rc));
-          goto leave;
-        }
+        goto leave;
 
       if (opt.verbose)
-        log_info ("stored\n");
-      
-      if (assuan_context)
+        log_info ("          id: %s - shadow key created\n", item->id);
+
+      if (assuan_context && send)
         {
           CERTINFO citem;
-          
+
           /* only send the certificate if we have not done so before */
           for (citem = cparm.info; citem; citem = citem->next)
             {
@@ -424,13 +436,10 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
         }
     }
 
-  
+
  leave:
-  xfree (serialno);
   release_keypair_info (parm.info);
   release_certinfo (cparm.info);
   release_sinfo (sparm.info);
   return rc;
 }
-
-