* certcheck.c (gpgsm_check_cert_sig): Add cert hash debugging.
[gnupg.git] / agent / learncard.c
1 /* learncard.c - Handle the LEARN command
2  *      Copyright (C) 2002 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30
31 #include "agent.h"
32 #include "../assuan/assuan.h"
33
34 struct keypair_info_s {
35   struct keypair_info_s *next;
36   int no_cert;
37   char *id;  /* points into grip */
38   char hexgrip[1];
39 };
40 typedef struct keypair_info_s *KEYPAIR_INFO;
41
42 struct kpinfo_cb_parm_s {
43   int error;
44   KEYPAIR_INFO info;
45 };
46
47
48 struct certinfo_s {
49   struct certinfo_s *next;
50   int type;  
51   int done;
52   char id[1];
53 };
54 typedef struct certinfo_s *CERTINFO;
55
56 struct certinfo_cb_parm_s {
57   int error;
58   CERTINFO info;
59 };
60
61
62 static void
63 release_keypair_info (KEYPAIR_INFO info)
64 {
65   while (info)
66     {
67       KEYPAIR_INFO tmp = info->next;
68       xfree (info);
69       info = tmp;
70     }
71 }
72
73 static void
74 release_certinfo (CERTINFO info)
75 {
76   while (info)
77     {
78       CERTINFO tmp = info->next;
79       xfree (info);
80       info = tmp;
81     }
82 }
83
84
85
86 /* This callback is used by agent_card_leanr and passed the content of
87    all KEYPAIRINFO lines.  It merely stores this data away */
88 static void
89 kpinfo_cb (void *opaque, const char *line)
90 {
91   struct kpinfo_cb_parm_s *parm = opaque;
92   KEYPAIR_INFO item;
93   char *p;
94
95   if (parm->error)
96     return; /* no need to gather data after an error coccured */
97   item = xtrycalloc (1, sizeof *item + strlen (line));
98   if (!item)
99     {
100       parm->error = GNUPG_Out_Of_Core;
101       return;
102     }
103   strcpy (item->hexgrip, line);
104   for (p = item->hexgrip; hexdigitp (p); p++)
105     ;
106   if (p == item->hexgrip && *p == 'X' && spacep (p+1))
107     {
108       item->no_cert = 1;
109       p++;
110     }
111   else if ((p - item->hexgrip) != 40 || !spacep (p))
112     { /* not a 20 byte hex keygrip or not followed by a space */
113       parm->error = GNUPG_Invalid_Response;
114       xfree (item);
115       return;
116     }
117   *p++ = 0;
118   while (spacep (p))
119     p++;
120   item->id = p;
121   while (*p && !spacep (p))
122     p++;
123   if (p == item->id)
124     { /* invalid ID string */
125       parm->error = GNUPG_Invalid_Response;
126       xfree (item);
127       return;
128     }
129   *p = 0; /* ignore trailing stuff */
130   
131   /* store it */
132   item->next = parm->info;
133   parm->info = item;
134 }
135
136
137 /* This callback is used by agent_card_leanr and passed the content of
138    all CERTINFO lines.  It merely stores this data away */
139 static void
140 certinfo_cb (void *opaque, const char *line)
141 {
142   struct certinfo_cb_parm_s *parm = opaque;
143   CERTINFO item;
144   int type;
145   char *p, *pend;
146
147   if (parm->error)
148     return; /* no need to gather data after an error coccured */
149
150   type = strtol (line, &p, 10);
151   while (spacep (p))
152     p++;
153   for (pend = p; *pend && !spacep (pend); pend++)
154     ;
155   if (p == pend || !*p)
156     { 
157       parm->error = GNUPG_Invalid_Response;
158       return;
159     }
160   *pend = 0; /* ignore trailing stuff */
161
162   item = xtrycalloc (1, sizeof *item + strlen (p));
163   if (!item)
164     {
165       parm->error = GNUPG_Out_Of_Core;
166       return;
167     }
168   item->type = type;
169   strcpy (item->id, p);
170   /* store it */
171   item->next = parm->info;
172   parm->info = item;
173 }
174
175
176 /* Create an S-expression with the shadow info.  */
177 static unsigned char *
178 make_shadow_info (const char *serialno, const char *idstring)
179 {
180   const char *s;
181   unsigned char *info, *p;
182   char numbuf[21];
183   int n;
184
185   for (s=serialno, n=0; *s && s[1]; s += 2)
186     n++;
187
188   info = p = xtrymalloc (1 + 21 + n
189                            + 21 + strlen (idstring) + 1 + 1);
190   *p++ = '(';
191   sprintf (numbuf, "%d:", n);
192   p = stpcpy (p, numbuf);
193   for (s=serialno; *s && s[1]; s += 2)
194     *p++ = xtoi_2 (s);
195   sprintf (numbuf, "%d:", strlen (idstring));
196   p = stpcpy (p, numbuf);
197   p = stpcpy (p, idstring);
198   *p++ = ')';
199   *p = 0;
200   return info;
201 }
202
203 static int
204 send_cert_back (const char *id, void *assuan_context)
205 {
206   int rc;
207   char *derbuf;
208   size_t derbuflen;
209   
210   rc = agent_card_readcert (id, &derbuf, &derbuflen);
211   if (rc)
212     {
213       log_error ("error reading certificate: %s\n",
214                  gnupg_strerror (rc));
215       return rc;
216     }
217
218   rc = assuan_send_data (assuan_context, derbuf, derbuflen);
219   xfree (derbuf);
220   if (!rc)
221     rc = assuan_send_data (assuan_context, NULL, 0);
222   if (!rc)
223     rc = assuan_write_line (assuan_context, "END");
224   if (rc)
225     {
226       log_error ("sending certificate failed: %s\n",
227                  assuan_strerror (rc));
228       return map_assuan_err (rc);
229     }
230   return 0;
231 }
232
233 /* Perform the learn operation.  If ASSUAN_CONTEXT is not NULL all new
234    certificates are send via Assuan */
235 int
236 agent_handle_learn (void *assuan_context)
237 {
238   int rc;
239   struct kpinfo_cb_parm_s parm;
240   struct certinfo_cb_parm_s cparm;
241   char *serialno = NULL;
242   KEYPAIR_INFO item;
243   unsigned char grip[20];
244   char *p;
245   int i;
246   static int certtype_list[] = { 
247     101, /* trusted */
248     102, /* useful */
249     100, /* regular */
250     -1 /* end of list */
251   };
252
253
254   memset (&parm, 0, sizeof parm);
255   memset (&cparm, 0, sizeof cparm);
256
257   /* Check whether a card is present and get the serial number */
258   rc = agent_card_serialno (&serialno);
259   if (rc)
260     goto leave;
261
262   /* now gather all the availabe info */
263   rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm);
264   if (!rc && (parm.error || cparm.error))
265     rc = parm.error? parm.error : cparm.error;
266   if (rc)
267     {
268       log_debug ("agent_card_learn failed: %s\n", gnupg_strerror (rc));
269       goto leave;
270     }
271   
272   log_info ("card has S/N: %s\n", serialno);
273
274   /* Write out the certificates in a standard order. */
275   for (i=0; certtype_list[i] != -1; i++)
276     {
277       CERTINFO citem;
278       for (citem = cparm.info; citem; citem = citem->next)
279         {
280           if (certtype_list[i] != citem->type)
281             continue;
282
283           if (opt.verbose)
284             log_info ("          id: %s    (type=%d)\n",
285                       citem->id, citem->type);
286           
287           if (assuan_context)
288             {
289               rc = send_cert_back (citem->id, assuan_context);
290               if (rc)
291                 goto leave;
292               citem->done = 1;
293             }
294         }
295     }
296   
297   for (item = parm.info; item; item = item->next)
298     {
299       unsigned char *pubkey, *shdkey;
300       size_t n;
301
302       if (opt.verbose)
303         log_info ("          id: %s    (grip=%s)\n", item->id, item->hexgrip);
304
305       if (item->no_cert)
306         continue; /* no public key yet available */
307
308       for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
309         grip[i] = xtoi_2 (p);
310       
311       if (!agent_key_available (grip))
312         continue;
313       
314       /* unknown - store it */
315       rc = agent_card_readkey (item->id, &pubkey);
316       if (rc)
317         {
318           log_debug ("agent_card_readkey failed: %s\n", gnupg_strerror (rc));
319           goto leave;
320         }
321
322       {
323         unsigned char *shadow_info = make_shadow_info (serialno, item->id);
324         if (!shadow_info)
325           {
326             rc = GNUPG_Out_Of_Core;
327             xfree (pubkey);
328             goto leave;
329           }
330         rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
331         xfree (shadow_info);
332       }
333       xfree (pubkey);
334       if (rc)
335         {
336           log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
337           goto leave;
338         }
339       n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
340       assert (n);
341
342       rc = agent_write_private_key (grip, shdkey, n, 0);
343       xfree (shdkey);
344       if (rc)
345         {
346           log_error ("error writing key: %s\n", gnupg_strerror (rc));
347           goto leave;
348         }
349
350       if (opt.verbose)
351         log_info ("stored\n");
352       
353       if (assuan_context)
354         {
355           CERTINFO citem;
356           
357           /* only send the certificate if we have not done so before */
358           for (citem = cparm.info; citem; citem = citem->next)
359             {
360               if (!strcmp (citem->id, item->id))
361                 break;
362             }
363           if (!citem)
364             {
365               rc = send_cert_back (item->id, assuan_context);
366               if (rc)
367                 goto leave;
368             }
369         }
370     }
371
372   
373  leave:
374   xfree (serialno);
375   release_keypair_info (parm.info);
376   release_certinfo (cparm.info);
377   return rc;
378 }
379
380