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