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