LCOV - code coverage report
Current view: top level - agent - learncard.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 189 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /* learncard.c - Handle the LEARN command
       2             :  * Copyright (C) 2002, 2003, 2004, 2009 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : #include <errno.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <ctype.h>
      26             : #include <assert.h>
      27             : #include <unistd.h>
      28             : #include <sys/stat.h>
      29             : 
      30             : #include "agent.h"
      31             : #include <assuan.h>
      32             : 
      33             : /* Structures used by the callback mechanism to convey information
      34             :    pertaining to key pairs.  */
      35             : struct keypair_info_s
      36             : {
      37             :   struct keypair_info_s *next;
      38             :   int no_cert;
      39             :   char *id;          /* points into grip */
      40             :   char hexgrip[1];   /* The keygrip (i.e. a hash over the public key
      41             :                         parameters) formatted as a hex string.
      42             :                         Allocated somewhat large to also act as
      43             :                         memeory for the above ID field. */
      44             : };
      45             : typedef struct keypair_info_s *KEYPAIR_INFO;
      46             : 
      47             : struct kpinfo_cb_parm_s
      48             : {
      49             :   ctrl_t ctrl;
      50             :   int error;
      51             :   KEYPAIR_INFO info;
      52             : };
      53             : 
      54             : 
      55             : /* Structures used by the callback mechanism to convey information
      56             :    pertaining to certificates.  */
      57             : struct certinfo_s {
      58             :   struct certinfo_s *next;
      59             :   int type;
      60             :   int done;
      61             :   char id[1];
      62             : };
      63             : typedef struct certinfo_s *CERTINFO;
      64             : 
      65             : struct certinfo_cb_parm_s
      66             : {
      67             :   ctrl_t ctrl;
      68             :   int error;
      69             :   CERTINFO info;
      70             : };
      71             : 
      72             : 
      73             : /* Structures used by the callback mechanism to convey assuan status
      74             :    lines.  */
      75             : struct sinfo_s {
      76             :   struct sinfo_s *next;
      77             :   char *data;       /* Points into keyword. */
      78             :   char keyword[1];
      79             : };
      80             : typedef struct sinfo_s *SINFO;
      81             : 
      82             : struct sinfo_cb_parm_s {
      83             :   int error;
      84             :   SINFO info;
      85             : };
      86             : 
      87             : 
      88             : /* Destructor for key information objects. */
      89             : static void
      90           0 : release_keypair_info (KEYPAIR_INFO info)
      91             : {
      92           0 :   while (info)
      93             :     {
      94           0 :       KEYPAIR_INFO tmp = info->next;
      95           0 :       xfree (info);
      96           0 :       info = tmp;
      97             :     }
      98           0 : }
      99             : 
     100             : /* Destructor for certificate information objects. */
     101             : static void
     102           0 : release_certinfo (CERTINFO info)
     103             : {
     104           0 :   while (info)
     105             :     {
     106           0 :       CERTINFO tmp = info->next;
     107           0 :       xfree (info);
     108           0 :       info = tmp;
     109             :     }
     110           0 : }
     111             : 
     112             : /* Destructor for status information objects. */
     113             : static void
     114           0 : release_sinfo (SINFO info)
     115             : {
     116           0 :   while (info)
     117             :     {
     118           0 :       SINFO tmp = info->next;
     119           0 :       xfree (info);
     120           0 :       info = tmp;
     121             :     }
     122           0 : }
     123             : 
     124             : 
     125             : 
     126             : /* This callback is used by agent_card_learn and passed the content of
     127             :    all KEYPAIRINFO lines.  It merely stores this data away */
     128             : static void
     129           0 : kpinfo_cb (void *opaque, const char *line)
     130             : {
     131           0 :   struct kpinfo_cb_parm_s *parm = opaque;
     132             :   KEYPAIR_INFO item;
     133             :   char *p;
     134             : 
     135           0 :   if (parm->error)
     136           0 :     return; /* no need to gather data after an error coccured */
     137             : 
     138           0 :   if ((parm->error = agent_write_status (parm->ctrl, "PROGRESS",
     139             :                                          "learncard", "k", "0", "0", NULL)))
     140           0 :     return;
     141             : 
     142           0 :   item = xtrycalloc (1, sizeof *item + strlen (line));
     143           0 :   if (!item)
     144             :     {
     145           0 :       parm->error = out_of_core ();
     146           0 :       return;
     147             :     }
     148           0 :   strcpy (item->hexgrip, line);
     149           0 :   for (p = item->hexgrip; hexdigitp (p); p++)
     150             :     ;
     151           0 :   if (p == item->hexgrip && *p == 'X' && spacep (p+1))
     152             :     {
     153           0 :       item->no_cert = 1;
     154           0 :       p++;
     155             :     }
     156           0 :   else if ((p - item->hexgrip) != 40 || !spacep (p))
     157             :     { /* not a 20 byte hex keygrip or not followed by a space */
     158           0 :       parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
     159           0 :       xfree (item);
     160           0 :       return;
     161             :     }
     162           0 :   *p++ = 0;
     163           0 :   while (spacep (p))
     164           0 :     p++;
     165           0 :   item->id = p;
     166           0 :   while (*p && !spacep (p))
     167           0 :     p++;
     168           0 :   if (p == item->id)
     169             :     { /* invalid ID string */
     170           0 :       parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
     171           0 :       xfree (item);
     172           0 :       return;
     173             :     }
     174           0 :   *p = 0; /* ignore trailing stuff */
     175             : 
     176             :   /* store it */
     177           0 :   item->next = parm->info;
     178           0 :   parm->info = item;
     179             : }
     180             : 
     181             : 
     182             : /* This callback is used by agent_card_learn and passed the content of
     183             :    all CERTINFO lines.  It merely stores this data away */
     184             : static void
     185           0 : certinfo_cb (void *opaque, const char *line)
     186             : {
     187           0 :   struct certinfo_cb_parm_s *parm = opaque;
     188             :   CERTINFO item;
     189             :   int type;
     190             :   char *p, *pend;
     191             : 
     192           0 :   if (parm->error)
     193           0 :     return; /* no need to gather data after an error coccured */
     194             : 
     195           0 :   if ((parm->error = agent_write_status (parm->ctrl, "PROGRESS",
     196             :                                          "learncard", "c", "0", "0", NULL)))
     197           0 :     return;
     198             : 
     199           0 :   type = strtol (line, &p, 10);
     200           0 :   while (spacep (p))
     201           0 :     p++;
     202           0 :   for (pend = p; *pend && !spacep (pend); pend++)
     203             :     ;
     204           0 :   if (p == pend || !*p)
     205             :     {
     206           0 :       parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
     207           0 :       return;
     208             :     }
     209           0 :   *pend = 0; /* ignore trailing stuff */
     210             : 
     211           0 :   item = xtrycalloc (1, sizeof *item + strlen (p));
     212           0 :   if (!item)
     213             :     {
     214           0 :       parm->error = out_of_core ();
     215           0 :       return;
     216             :     }
     217           0 :   item->type = type;
     218           0 :   strcpy (item->id, p);
     219             :   /* store it */
     220           0 :   item->next = parm->info;
     221           0 :   parm->info = item;
     222             : }
     223             : 
     224             : 
     225             : /* This callback is used by agent_card_learn and passed the content of
     226             :    all SINFO lines.  It merely stores this data away */
     227             : static void
     228           0 : sinfo_cb (void *opaque, const char *keyword, size_t keywordlen,
     229             :           const char *data)
     230             : {
     231           0 :   struct sinfo_cb_parm_s *sparm = opaque;
     232             :   SINFO item;
     233             : 
     234           0 :   if (sparm->error)
     235           0 :     return; /* no need to gather data after an error coccured */
     236             : 
     237           0 :   item = xtrycalloc (1, sizeof *item + keywordlen + 1 + strlen (data));
     238           0 :   if (!item)
     239             :     {
     240           0 :       sparm->error = out_of_core ();
     241           0 :       return;
     242             :     }
     243           0 :   memcpy (item->keyword, keyword, keywordlen);
     244           0 :   item->data = item->keyword + keywordlen;
     245           0 :   *item->data = 0;
     246           0 :   item->data++;
     247           0 :   strcpy (item->data, data);
     248             :   /* store it */
     249           0 :   item->next = sparm->info;
     250           0 :   sparm->info = item;
     251             : }
     252             : 
     253             : 
     254             : 
     255             : static int
     256           0 : send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
     257             : {
     258             :   int rc;
     259             :   char *derbuf;
     260             :   size_t derbuflen;
     261             : 
     262           0 :   rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen);
     263           0 :   if (rc)
     264             :     {
     265             :       const char *action;
     266             : 
     267           0 :       switch (gpg_err_code (rc))
     268             :         {
     269             :         case GPG_ERR_INV_ID:
     270             :         case GPG_ERR_NOT_FOUND:
     271           0 :           action = " - ignored";
     272           0 :           break;
     273             :         default:
     274           0 :           action = "";
     275           0 :           break;
     276             :         }
     277           0 :       if (opt.verbose || !*action)
     278           0 :         log_info ("error reading certificate '%s': %s%s\n",
     279             :                   id? id:"?", gpg_strerror (rc), action);
     280             : 
     281           0 :       return *action? 0 : rc;
     282             :     }
     283             : 
     284           0 :   rc = assuan_send_data (assuan_context, derbuf, derbuflen);
     285           0 :   xfree (derbuf);
     286           0 :   if (!rc)
     287           0 :     rc = assuan_send_data (assuan_context, NULL, 0);
     288           0 :   if (!rc)
     289           0 :     rc = assuan_write_line (assuan_context, "END");
     290           0 :   if (rc)
     291             :     {
     292           0 :       log_error ("sending certificate failed: %s\n",
     293             :                  gpg_strerror (rc));
     294           0 :       return rc;
     295             :     }
     296           0 :   return 0;
     297             : }
     298             : 
     299             : /* Perform the learn operation.  If ASSUAN_CONTEXT is not NULL and
     300             :    SEND is true all new certificates are send back via Assuan.  */
     301             : int
     302           0 : agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
     303             : {
     304             :   int rc;
     305             : 
     306             :   struct kpinfo_cb_parm_s parm;
     307             :   struct certinfo_cb_parm_s cparm;
     308             :   struct sinfo_cb_parm_s sparm;
     309           0 :   char *serialno = NULL;
     310             :   KEYPAIR_INFO item;
     311             :   SINFO sitem;
     312             :   unsigned char grip[20];
     313             :   char *p;
     314             :   int i;
     315             :   static int certtype_list[] = {
     316             :     111, /* Root CA */
     317             :     101, /* trusted */
     318             :     102, /* useful */
     319             :     100, /* regular */
     320             :     /* We don't include 110 here because gpgsm can't handle that
     321             :        special root CA format. */
     322             :     -1 /* end of list */
     323             :   };
     324             : 
     325             : 
     326           0 :   memset (&parm, 0, sizeof parm);
     327           0 :   memset (&cparm, 0, sizeof cparm);
     328           0 :   memset (&sparm, 0, sizeof sparm);
     329           0 :   parm.ctrl = ctrl;
     330           0 :   cparm.ctrl = ctrl;
     331             : 
     332             :   /* Check whether a card is present and get the serial number */
     333           0 :   rc = agent_card_serialno (ctrl, &serialno);
     334           0 :   if (rc)
     335           0 :     goto leave;
     336             : 
     337             :   /* Now gather all the available info. */
     338           0 :   rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm,
     339             :                          sinfo_cb, &sparm);
     340           0 :   if (!rc && (parm.error || cparm.error || sparm.error))
     341           0 :     rc = parm.error? parm.error : cparm.error? cparm.error : sparm.error;
     342           0 :   if (rc)
     343             :     {
     344           0 :       log_debug ("agent_card_learn failed: %s\n", gpg_strerror (rc));
     345           0 :       goto leave;
     346             :     }
     347             : 
     348           0 :   log_info ("card has S/N: %s\n", serialno);
     349             : 
     350             :   /* Pass on all the collected status information. */
     351           0 :   if (assuan_context)
     352             :     {
     353           0 :       for (sitem = sparm.info; sitem; sitem = sitem->next)
     354             :         {
     355           0 :           assuan_write_status (assuan_context, sitem->keyword, sitem->data);
     356             :         }
     357             :     }
     358             : 
     359             :   /* Write out the certificates in a standard order. */
     360           0 :   for (i=0; certtype_list[i] != -1; i++)
     361             :     {
     362             :       CERTINFO citem;
     363           0 :       for (citem = cparm.info; citem; citem = citem->next)
     364             :         {
     365           0 :           if (certtype_list[i] != citem->type)
     366           0 :             continue;
     367             : 
     368           0 :           if (opt.verbose)
     369           0 :             log_info ("          id: %s    (type=%d)\n",
     370           0 :                       citem->id, citem->type);
     371             : 
     372           0 :           if (assuan_context && send)
     373             :             {
     374           0 :               rc = send_cert_back (ctrl, citem->id, assuan_context);
     375           0 :               if (rc)
     376           0 :                 goto leave;
     377           0 :               citem->done = 1;
     378             :             }
     379             :         }
     380             :     }
     381             : 
     382           0 :   for (item = parm.info; item; item = item->next)
     383             :     {
     384             :       unsigned char *pubkey, *shdkey;
     385             :       size_t n;
     386             : 
     387           0 :       if (opt.verbose)
     388           0 :         log_info ("          id: %s    (grip=%s)\n", item->id, item->hexgrip);
     389             : 
     390           0 :       if (item->no_cert)
     391           0 :         continue; /* No public key yet available. */
     392             : 
     393           0 :       if (assuan_context)
     394             :         {
     395           0 :           agent_write_status (ctrl, "KEYPAIRINFO",
     396           0 :                               item->hexgrip, item->id, NULL);
     397             :         }
     398             : 
     399           0 :       for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
     400           0 :         grip[i] = xtoi_2 (p);
     401             : 
     402           0 :       if (!force && !agent_key_available (grip))
     403           0 :         continue; /* The key is already available. */
     404             : 
     405             :       /* Unknown key - store it. */
     406           0 :       rc = agent_card_readkey (ctrl, item->id, &pubkey);
     407           0 :       if (rc)
     408             :         {
     409           0 :           log_debug ("agent_card_readkey failed: %s\n", gpg_strerror (rc));
     410           0 :           goto leave;
     411             :         }
     412             : 
     413             :       {
     414           0 :         unsigned char *shadow_info = make_shadow_info (serialno, item->id);
     415           0 :         if (!shadow_info)
     416             :           {
     417           0 :             rc = gpg_error (GPG_ERR_ENOMEM);
     418           0 :             xfree (pubkey);
     419           0 :             goto leave;
     420             :           }
     421           0 :         rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
     422           0 :         xfree (shadow_info);
     423             :       }
     424           0 :       xfree (pubkey);
     425           0 :       if (rc)
     426             :         {
     427           0 :           log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
     428           0 :           goto leave;
     429             :         }
     430           0 :       n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
     431           0 :       assert (n);
     432             : 
     433           0 :       rc = agent_write_private_key (grip, shdkey, n, force);
     434           0 :       xfree (shdkey);
     435           0 :       if (rc)
     436             :         {
     437           0 :           log_error ("error writing key: %s\n", gpg_strerror (rc));
     438           0 :           goto leave;
     439             :         }
     440             : 
     441           0 :       if (opt.verbose)
     442           0 :         log_info ("          id: %s - shadow key created\n", item->id);
     443             : 
     444           0 :       if (assuan_context && send)
     445             :         {
     446             :           CERTINFO citem;
     447             : 
     448             :           /* only send the certificate if we have not done so before */
     449           0 :           for (citem = cparm.info; citem; citem = citem->next)
     450             :             {
     451           0 :               if (!strcmp (citem->id, item->id))
     452           0 :                 break;
     453             :             }
     454           0 :           if (!citem)
     455             :             {
     456           0 :               rc = send_cert_back (ctrl, item->id, assuan_context);
     457           0 :               if (rc)
     458           0 :                 goto leave;
     459             :             }
     460             :         }
     461             :     }
     462             : 
     463             : 
     464             :  leave:
     465           0 :   xfree (serialno);
     466           0 :   release_keypair_info (parm.info);
     467           0 :   release_certinfo (cparm.info);
     468           0 :   release_sinfo (sparm.info);
     469           0 :   return rc;
     470             : }

Generated by: LCOV version 1.11