Make use of libgpg-error
[gnupg.git] / scd / command.c
1 /* command.c - SCdaemon command handler
2  *      Copyright (C) 2001, 2002, 2003 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 <unistd.h>
28 #include <ksba.h>
29
30 #include <assuan.h>
31
32 #include "scdaemon.h"
33
34 /* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */
35 #define MAXLEN_PIN 100
36
37 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
38
39 /* Data used to associate an Assuan context with local server data */
40 struct server_local_s {
41   ASSUAN_CONTEXT assuan_ctx;
42 };
43
44
45 /* Check whether the option NAME appears in LINE */
46 static int
47 has_option (const char *line, const char *name)
48 {
49   const char *s;
50   int n = strlen (name);
51
52   s = strstr (line, name);
53   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
54 }
55
56
57
58 \f
59 /* Note, that this reset_notify is also used for cleanup purposes. */
60 static void
61 reset_notify (ASSUAN_CONTEXT ctx)
62 {
63   CTRL ctrl = assuan_get_pointer (ctx); 
64
65   if (ctrl->card_ctx)
66     {
67       card_close (ctrl->card_ctx);
68       ctrl->card_ctx = NULL;
69       xfree (ctrl->in_data.value);
70       ctrl->in_data.value = NULL;
71     }
72 }
73
74
75 static int
76 option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
77 {
78   return 0;
79 }
80
81
82 /* If the card has not yet been opened, do it.  Note that this
83    function returns an Assuan error, so don't map the error a second
84    time */
85 static AssuanError
86 open_card (CTRL ctrl)
87 {
88   if (!ctrl->card_ctx)
89     {
90       int rc = card_open (&ctrl->card_ctx);
91       if (rc)
92         return map_to_assuan_status (rc);
93     }
94   return 0;
95 }
96
97
98 /* SERIALNO 
99
100    Return the serial number of the card using a status reponse.  This
101    functon should be used to check for the presence of a card.
102
103    This function is special in that it can be used to reset the card.
104    Most other functions will return an error when a card change has
105    been detected and the use of this function is therefore required.
106
107    Background: We want to keep the client clear of handling card
108    changes between operations; i.e. the client can assume that all
109    operations are doneon the same card unless he call this function.
110  */
111 static int
112 cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
113 {
114   CTRL ctrl = assuan_get_pointer (ctx);
115   int rc = 0;
116   char *serial_and_stamp;
117   char *serial;
118   time_t stamp;
119
120   if ((rc = open_card (ctrl)))
121     return rc;
122
123   rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
124   if (rc)
125     return map_to_assuan_status (rc);
126   rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
127   xfree (serial);
128   if (rc < 0)
129     return ASSUAN_Out_Of_Core;
130   rc = 0;
131   assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
132   free (serial_and_stamp);
133   return 0;
134 }
135
136
137
138
139 /* LEARN [--force]
140
141    Learn all useful information of the currently inserted card.  When
142    used without the force options, the command might do an INQUIRE
143    like this:
144
145       INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
146
147    The client should just send an "END" if the processing should go on
148    or a "CANCEL" to force the function to terminate with a Cancel
149    error message.  The response of this command is a list of status
150    lines formatted as this:
151
152      S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
153
154    If there is no certificate yet stored on the card a single "X" is
155    returned as the keygrip.  In addition to the keypair info, information
156    about all certificates stored on the card is also returned:
157
158      S CERTINFO <certtype> <hexstring_with_id>
159
160    Where CERTINFO is a number indicating the type of certificate:
161       0   := Unknown
162       100 := Regular X.509 cert
163       101 := Trusted X.509 cert
164       102 := Useful X.509 cert
165
166
167 */
168 static int
169 cmd_learn (ASSUAN_CONTEXT ctx, char *line)
170 {
171   CTRL ctrl = assuan_get_pointer (ctx);
172   int rc = 0;
173   int idx;
174
175   if ((rc = open_card (ctrl)))
176     return rc;
177
178   /* Unless the force option is used we try a shortcut by identifying
179      the card using a serial number and inquiring the client with
180      that. The client may choose to cancel the operation if he already
181      knows about this card */
182   {
183     char *serial_and_stamp;
184     char *serial;
185     time_t stamp;
186    
187     rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
188     if (rc)
189       return map_to_assuan_status (rc);
190     rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
191     xfree (serial);
192     if (rc < 0)
193       return ASSUAN_Out_Of_Core;
194     rc = 0;
195     assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
196
197     if (!has_option (line, "--force"))
198       {
199         char *command;
200
201         rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
202         if (rc < 0)
203           {
204             free (serial_and_stamp);
205             return ASSUAN_Out_Of_Core;
206           }
207         rc = 0;
208         rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
209         free (command);  /* (must use standard free here) */
210         if (rc)
211           {
212             if (rc != ASSUAN_Canceled)
213               log_error ("inquire KNOWNCARDP failed: %s\n",
214                          assuan_strerror (rc));
215             free (serial_and_stamp);
216             return rc; 
217           }
218         /* not canceled, so we have to proceeed */
219       }
220     free (serial_and_stamp);
221   }
222
223   /* Return information about the certificates. */
224   for (idx=0; !rc; idx++)
225     {
226       char *certid;
227       int certtype;
228
229       rc = card_enum_certs (ctrl->card_ctx, idx, &certid, &certtype);
230       if (!rc)
231         {
232           char *buf;
233
234           buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
235           if (!buf)
236             rc = out_of_core ();
237           else
238             {
239               sprintf (buf, "%d %s", certtype, certid);
240               assuan_write_status (ctx, "CERTINFO", buf);
241               xfree (buf);
242             }
243         }
244       xfree (certid);
245     }
246   if (rc == -1)
247     rc = 0;
248
249
250   /* Return information about the keys. */
251   for (idx=0; !rc; idx++)
252     {
253       unsigned char keygrip[20];
254       char *keyid;
255       int no_cert = 0;
256
257       rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid);
258       if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT && keyid)
259         {
260           /* this does happen with an incomplete personalized
261              card; i.e. during the time we have stored the key on the
262              card but not stored the certificate; probably becuase it
263              has not yet been received back from the CA.  Note that we
264              must release KEYID in this case. */
265           rc = 0; 
266           no_cert = 1;
267         }
268       if (!rc)
269         {
270           char *buf, *p;
271
272           buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
273           if (!buf)
274             rc = out_of_core ();
275           else
276             {
277               int i;
278               
279               if (no_cert)
280                 *p++ = 'X';
281               else
282                 {
283                   for (i=0; i < 20; i++, p += 2)
284                     sprintf (p, "%02X", keygrip[i]);
285                 }
286               *p++ = ' ';
287               strcpy (p, keyid);
288               assuan_write_status (ctx, "KEYPAIRINFO", buf);
289               xfree (buf);
290             }
291         }
292       xfree (keyid);
293     }
294   if (rc == -1)
295     rc = 0;
296
297
298   return map_to_assuan_status (rc);
299 }
300
301
302 \f
303 /* READCERT <hexified_certid>
304
305  */
306 static int
307 cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
308 {
309   CTRL ctrl = assuan_get_pointer (ctx);
310   int rc;
311   unsigned char *cert;
312   size_t ncert;
313
314   if ((rc = open_card (ctrl)))
315     return rc;
316
317   rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
318   if (rc)
319     {
320       log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
321     }
322   if (!rc)
323     {
324       rc = assuan_send_data (ctx, cert, ncert);
325       xfree (cert);
326       if (rc)
327         return rc;
328     }
329
330   return map_to_assuan_status (rc);
331 }
332
333
334 /* READKEY <hexified_certid>
335
336    Return the public key for the given cert or key ID as an standard
337    S-Expression.  */
338 static int
339 cmd_readkey (ASSUAN_CONTEXT ctx, char *line)
340 {
341   CTRL ctrl = assuan_get_pointer (ctx);
342   int rc;
343   unsigned char *cert = NULL;
344   size_t ncert, n;
345   KsbaCert kc = NULL;
346   KsbaSexp p;
347
348   if ((rc = open_card (ctrl)))
349     return rc;
350
351   rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
352   if (rc)
353     {
354       log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
355       goto leave;
356     }
357       
358   kc = ksba_cert_new ();
359   if (!kc)
360     {
361       rc = out_of_core ();
362       xfree (cert);
363       goto leave;
364     }
365   rc = ksba_cert_init_from_mem (kc, cert, ncert);
366   if (rc)
367     {
368       log_error ("failed to parse the certificate: %s\n", ksba_strerror (rc));
369       rc = map_ksba_err (rc);
370       goto leave;
371     }
372
373   p = ksba_cert_get_public_key (kc);
374   if (!p)
375     {
376       rc = gpg_error (GPG_ERR_NO_PUBKEY);
377       goto leave;
378     }
379
380   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
381   rc = assuan_send_data (ctx, p, n);
382   rc = map_assuan_err (rc);
383   xfree (p);
384
385
386  leave:
387   ksba_cert_release (kc);
388   xfree (cert);
389   return map_to_assuan_status (rc);
390 }
391
392
393 \f
394
395 /* SETDATA <hexstring> 
396
397    The client should use this command to tell us the data he want to
398    sign.  */
399 static int
400 cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
401 {
402   CTRL ctrl = assuan_get_pointer (ctx);
403   int n;
404   char *p;
405   unsigned char *buf;
406
407   /* parse the hexstring */
408   for (p=line,n=0; hexdigitp (p); p++, n++)
409     ;
410   if (*p)
411     return set_error (Parameter_Error, "invalid hexstring");
412   if ((n&1))
413     return set_error (Parameter_Error, "odd number of digits");
414   n /= 2;
415   buf = xtrymalloc (n);
416   if (!buf)
417     return ASSUAN_Out_Of_Core;
418
419   ctrl->in_data.value = buf;
420   ctrl->in_data.valuelen = n;
421   for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
422     buf[n] = xtoi_2 (p);
423   return 0;
424 }
425
426
427
428 static int 
429 pin_cb (void *opaque, const char *info, char **retstr)
430 {
431   ASSUAN_CONTEXT ctx = opaque;
432   char *command;
433   int rc;
434   char *value;
435   size_t valuelen;
436
437   *retstr = NULL;
438   log_debug ("asking for PIN '%s'\n", info);
439
440   rc = asprintf (&command, "NEEDPIN %s", info);
441   if (rc < 0)
442     return out_of_core ();
443
444   /* FIXME: Write an inquire function which returns the result in
445      secure memory */
446   rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
447   free (command);  
448   if (rc)
449     return map_assuan_err (rc);
450
451   if (!valuelen || value[valuelen-1])
452     {
453       /* We require that the returned value is an UTF-8 string */
454       xfree (value);
455       return gpg_error (GPG_ERR_INVALID_RESPONSE);
456     }
457   *retstr = value;
458   return 0;
459 }
460
461
462 /* PKSIGN <hexified_id>
463
464  */
465 static int
466 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
467 {
468   CTRL ctrl = assuan_get_pointer (ctx);
469   int rc;
470   void *outdata;
471   size_t outdatalen;
472   char *keyidstr;
473
474   if ((rc = open_card (ctrl)))
475     return rc;
476
477   /* We have to use a copy of the key ID because the function may use
478      the pin_cb which in turn uses the assuan line buffer and thus
479      overwriting the original line with the keyid */
480   keyidstr = strdup (line);
481   if (!keyidstr)
482     return ASSUAN_Out_Of_Core;
483   rc = card_sign (ctrl->card_ctx,
484                   keyidstr, GCRY_MD_SHA1,
485                   pin_cb, ctx,
486                   ctrl->in_data.value, ctrl->in_data.valuelen,
487                   &outdata, &outdatalen);
488   free (keyidstr);
489   if (rc)
490     {
491       log_error ("card_sign failed: %s\n", gnupg_strerror (rc));
492     }
493   else
494     {
495       rc = assuan_send_data (ctx, outdata, outdatalen);
496       xfree (outdata);
497       if (rc)
498         return rc; /* that is already an assuan error code */
499     }
500
501   return map_to_assuan_status (rc);
502 }
503
504 /* PKDECRYPT <hexified_id>
505
506  */
507 static int
508 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
509 {
510   CTRL ctrl = assuan_get_pointer (ctx);
511   int rc;
512   void *outdata;
513   size_t outdatalen;
514   char *keyidstr;
515
516   if ((rc = open_card (ctrl)))
517     return rc;
518
519   keyidstr = strdup (line);
520   if (!keyidstr)
521     return ASSUAN_Out_Of_Core;
522   rc = card_decipher (ctrl->card_ctx,
523                       keyidstr, 
524                       pin_cb, ctx,
525                       ctrl->in_data.value, ctrl->in_data.valuelen,
526                       &outdata, &outdatalen);
527   free (keyidstr);
528   if (rc)
529     {
530       log_error ("card_create_signature failed: %s\n", gnupg_strerror (rc));
531     }
532   else
533     {
534       rc = assuan_send_data (ctx, outdata, outdatalen);
535       xfree (outdata);
536       if (rc)
537         return rc; /* that is already an assuan error code */
538     }
539
540   return map_to_assuan_status (rc);
541 }
542
543
544
545 \f
546 /* Tell the assuan library about our commands */
547 static int
548 register_commands (ASSUAN_CONTEXT ctx)
549 {
550   static struct {
551     const char *name;
552     int (*handler)(ASSUAN_CONTEXT, char *line);
553   } table[] = {
554     { "SERIALNO",     cmd_serialno },
555     { "LEARN",        cmd_learn },
556     { "READCERT",     cmd_readcert },
557     { "READKEY",      cmd_readkey },
558     { "SETDATA",      cmd_setdata },
559     { "PKSIGN",       cmd_pksign },
560     { "PKDECRYPT",    cmd_pkdecrypt },
561     { "INPUT",        NULL }, 
562     { "OUTPUT",       NULL }, 
563     { NULL }
564   };
565   int i, rc;
566
567   for (i=0; table[i].name; i++)
568     {
569       rc = assuan_register_command (ctx, table[i].name, table[i].handler);
570       if (rc)
571         return rc;
572     } 
573   assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
574
575   assuan_register_reset_notify (ctx, reset_notify);
576   assuan_register_option_handler (ctx, option_handler);
577   return 0;
578 }
579
580
581 /* Startup the server.  If LISTEN_FD is given as -1, this is simple
582    piper server, otherwise it is a regular server */
583 void
584 scd_command_handler (int listen_fd)
585 {
586   int rc;
587   ASSUAN_CONTEXT ctx;
588   struct server_control_s ctrl;
589
590   memset (&ctrl, 0, sizeof ctrl);
591   scd_init_default_ctrl (&ctrl);
592   
593   if (listen_fd == -1)
594     {
595       int filedes[2];
596
597       filedes[0] = 0;
598       filedes[1] = 1;
599       rc = assuan_init_pipe_server (&ctx, filedes);
600     }
601   else
602     {
603       rc = assuan_init_socket_server (&ctx, listen_fd);
604     }
605   if (rc)
606     {
607       log_error ("failed to initialize the server: %s\n",
608                  assuan_strerror(rc));
609       scd_exit (2);
610     }
611   rc = register_commands (ctx);
612   if (rc)
613     {
614       log_error ("failed to register commands with Assuan: %s\n",
615                  assuan_strerror(rc));
616       scd_exit (2);
617     }
618   assuan_set_pointer (ctx, &ctrl);
619   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
620   ctrl.server_local->assuan_ctx = ctx;
621
622   if (DBG_ASSUAN)
623     assuan_set_log_stream (ctx, log_get_stream ());
624
625   for (;;)
626     {
627       rc = assuan_accept (ctx);
628       if (rc == -1)
629         {
630           break;
631         }
632       else if (rc)
633         {
634           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
635           break;
636         }
637       
638       rc = assuan_process (ctx);
639       if (rc)
640         {
641           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
642           continue;
643         }
644     }
645   reset_notify (ctx); /* used for cleanup */
646
647   assuan_deinit_server (ctx);
648 }