* g10.c (main): New commands --card-edit, --card-status and
[gnupg.git] / g10 / cardglue.c
1 /* cardglue.c - mainly dispatcher for card related functions.
2  * Copyright (C) 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 #ifdef ENABLE_CARD_SUPPORT
23 /* 
24    Note, that most card related code has been taken from 1.9.x branch
25    and is maintained over there if at all possible.  Thus, if you make
26    changes here, please check that a similar change has been commited
27    to the 1.9.x branch.
28 */
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <assert.h>
35
36 #include "options.h"
37 #include "packet.h"
38 #include "errors.h"
39 #include "memory.h"
40 #include "util.h"
41 #include "main.h"
42 #include "status.h"
43 #include "i18n.h"
44
45 #include "cardglue.h"
46 #include "apdu.h"
47 #include "app-common.h"
48
49 struct ctrl_ctx_s {
50   int (*status_cb)(void *opaque, const char *line);
51   void *status_cb_arg;
52 };
53
54
55 static char *default_reader_port;
56
57
58
59
60
61 /* Create a serialno/fpr string from the serial number and the secret
62    key.  caller must free the returned string.  There is no error
63    return. [Taken from 1.9's keyid.c]*/
64 char *
65 serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
66                           PKT_secret_key *sk)
67 {
68   unsigned char fpr[MAX_FINGERPRINT_LEN];
69   size_t fprlen;
70   char *buffer, *p;
71   int i;
72   
73   fingerprint_from_sk (sk, fpr, &fprlen);
74   buffer = p = xmalloc (snlen*2 + 1 + fprlen*2 + 1);
75   for (i=0; i < snlen; i++, p+=2)
76     sprintf (p, "%02X", sn[i]);
77   *p++ = '/';
78   for (i=0; i < fprlen; i++, p+=2)
79     sprintf (p, "%02X", fpr[i]);
80   *p = 0;
81   return buffer;
82 }
83
84
85 /* Send a line with status information via assuan and escape all given
86    buffers. The variable elements are pairs of (char *, size_t),
87    terminated with a (NULL, 0). */
88 void
89 send_status_info (CTRL ctrl, const char *keyword, ...)
90 {
91   va_list arg_ptr;
92   const unsigned char *value;
93   size_t valuelen;
94   char buf[950], *p;
95   size_t n;
96   
97   va_start (arg_ptr, keyword);
98
99   p = buf; 
100   n = 0;
101   valuelen = strlen (keyword);
102   for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, keyword++)
103     *p++ = *keyword;
104
105   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
106     {
107       valuelen = va_arg (arg_ptr, size_t);
108       if (!valuelen)
109         continue; /* empty buffer */
110       if (n)
111         {
112           *p++ = ' ';
113           n++;
114         }
115       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
116         {
117           if (*value < ' ' || *value == '+')
118             {
119               sprintf (p, "%%%02X", *value);
120               p += 3;
121             }
122           else if (*value == ' ')
123             *p++ = '+';
124           else
125             *p++ = *value;
126         }
127     }
128   *p = 0;
129   ctrl->status_cb (ctrl->status_cb_arg, buf);
130
131   va_end (arg_ptr);
132 }
133
134
135 void gcry_md_hash_buffer (int algo, void *digest,
136                           const void *buffer, size_t length)
137 {
138   MD_HANDLE h = md_open (algo, 0);
139   if (!h)
140     BUG();
141   md_write (h, (byte *) buffer, length);
142   md_final (h);
143   memcpy (digest, md_read (h, algo), md_digest_length (algo));
144   md_close (h);
145 }
146
147
148 /* This is a limited version of the one in 1.9 but it should be
149    sufficient here. */
150 void
151 log_printf (const char *fmt, ...)
152 {
153   va_list arg_ptr;
154
155   va_start (arg_ptr, fmt);
156   vfprintf (log_stream (), fmt, arg_ptr);
157   va_end (arg_ptr);
158 }
159
160
161
162 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
163    dump, with TEXT just an empty string, print a trailing linefeed,
164    otherwise print an entire debug line. */
165 void
166 log_printhex (const char *text, const void *buffer, size_t length)
167 {
168   if (text && *text)
169     log_debug ("%s ", text);
170   if (length)
171     {
172       const unsigned char *p = buffer;
173       log_printf ("%02X", *p);
174       for (length--, p++; length--; p++)
175         log_printf (" %02X", *p);
176     }
177   if (text)
178     log_printf ("\n");
179 }
180
181
182
183 void
184 app_set_default_reader_port (const char *portstr)
185 {
186   xfree (default_reader_port);
187   default_reader_port = portstr? xstrdup (portstr): NULL;
188 }
189
190
191 /* Retrieve the serial number and the time of the last update of the
192    card.  The serial number is returned as a malloced string (hex
193    encoded) in SERIAL and the time of update is returned in STAMP.  If
194    no update time is available the returned value is 0.  Caller must
195    free SERIAL unless the function returns an error. */
196 int 
197 app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
198 {
199   unsigned char *buf, *p;
200   int i;
201
202   if (!app || !serial || !stamp)
203     return gpg_error (GPG_ERR_INV_VALUE);
204
205   *serial = NULL;
206   *stamp = 0; /* not available */
207
208   buf = xtrymalloc (app->serialnolen * 2 + 1);
209   if (!buf)
210     return gpg_error_from_errno (errno);
211   for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
212     sprintf (p, "%02X", app->serialno[i]);
213   *p = 0;
214   *serial = buf;
215   return 0;
216 }
217
218
219
220
221
222
223 /* Release the card info structure. */
224 void 
225 agent_release_card_info (struct agent_card_info_s *info)
226 {
227   if (!info)
228     return;
229
230   xfree (info->serialno); info->serialno = NULL;
231   xfree (info->disp_name); info->disp_name = NULL;
232   xfree (info->disp_lang); info->disp_lang = NULL;
233   xfree (info->pubkey_url); info->pubkey_url = NULL;
234   xfree (info->login_data); info->login_data = NULL;
235   info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
236 }
237
238
239 /* Open the current card and select the openpgp application.  Return
240    an APP context handle to be used for further procesing or NULL on
241    error or if no OpenPGP application exists.*/
242 static APP
243 open_card (void)
244 {
245   int slot;
246   int rc;
247   APP app;
248
249   slot = apdu_open_reader (default_reader_port);
250   if (slot == -1)
251     {
252       log_error ("card reader not available\n");
253       return NULL;
254     }
255
256   app = xcalloc (1, sizeof *app);
257   app->slot = slot;
258   rc = app_select_openpgp (app, &app->serialno, &app->serialnolen);
259   if (rc)
260     {
261 /*        apdu_close_reader (slot); */
262       log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
263       xfree (app);
264       return NULL;
265     }
266
267   app->initialized = 1;
268   return app;
269 }
270
271
272
273 /* Return a new malloced string by unescaping the string S.  Escaping
274    is percent escaping and '+'/space mapping.  A binary nul will
275    silently be replaced by a 0xFF.  Function returns NULL to indicate
276    an out of memory status. */
277 static char *
278 unescape_status_string (const unsigned char *s)
279 {
280   char *buffer, *d;
281
282   buffer = d = xmalloc (strlen (s)+1);
283   while (*s)
284     {
285       if (*s == '%' && s[1] && s[2])
286         { 
287           s++;
288           *d = xtoi_2 (s);
289           if (!*d)
290             *d = '\xff';
291           d++;
292           s += 2;
293         }
294       else if (*s == '+')
295         {
296           *d++ = ' ';
297           s++;
298         }
299       else
300         *d++ = *s++;
301     }
302   *d = 0; 
303   return buffer;
304 }
305
306 /* Take a 20 byte hexencoded string and put it into the the provided
307    20 byte buffer FPR in binary format. */
308 static int
309 unhexify_fpr (const char *hexstr, unsigned char *fpr)
310 {
311   const char *s;
312   int n;
313
314   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
315     ;
316   if (*s || (n != 40))
317     return 0; /* no fingerprint (invalid or wrong length). */
318   n /= 2;
319   for (s=hexstr, n=0; *s; s += 2, n++)
320     fpr[n] = xtoi_2 (s);
321   return 1; /* okay */
322 }
323
324 /* Take the serial number from LINE and return it verbatim in a newly
325    allocated string.  We make sure that only hex characters are
326    returned. */
327 static char *
328 store_serialno (const char *line)
329 {
330   const char *s;
331   char *p;
332
333   for (s=line; hexdigitp (s); s++)
334     ;
335   p = xmalloc (s + 1 - line);
336   memcpy (p, line, s-line);
337   p[s-line] = 0;
338   return p;
339 }
340
341
342
343 static int
344 learn_status_cb (void *opaque, const char *line)
345 {
346   struct agent_card_info_s *parm = opaque;
347   const char *keyword = line;
348   int keywordlen;
349   int i;
350
351   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
352     ;
353   while (spacep (line))
354     line++;
355
356   if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
357     {
358       parm->serialno = store_serialno (line);
359     }
360   else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
361     {
362       parm->disp_name = unescape_status_string (line);
363     }
364   else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
365     {
366       parm->disp_lang = unescape_status_string (line);
367     }
368   else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
369     {
370       parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
371     }
372   else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
373     {
374       parm->pubkey_url = unescape_status_string (line);
375     }
376   else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
377     {
378       parm->login_data = unescape_status_string (line);
379     }
380   else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
381     {
382       parm->sig_counter = strtoul (line, NULL, 0);
383     }
384   else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
385     {
386       char *p, *buf;
387
388       buf = p = unescape_status_string (line);
389       if (buf)
390         {
391           while (spacep (p))
392             p++;
393           parm->chv1_cached = atoi (p);
394           while (!spacep (p))
395             p++;
396           while (spacep (p))
397             p++;
398           for (i=0; *p && i < 3; i++)
399             {
400               parm->chvmaxlen[i] = atoi (p);
401               while (!spacep (p))
402                 p++;
403               while (spacep (p))
404                 p++;
405             }
406           for (i=0; *p && i < 3; i++)
407             {
408               parm->chvretry[i] = atoi (p);
409               while (!spacep (p))
410                 p++;
411               while (spacep (p))
412                 p++;
413             }
414           xfree (buf);
415         }
416     }
417   else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
418     {
419       int no = atoi (line);
420       while (!spacep (line))
421         line++;
422       while (spacep (line))
423         line++;
424       if (no == 1)
425         parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
426       else if (no == 2)
427         parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
428       else if (no == 3)
429         parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
430     }
431   
432   return 0;
433 }
434
435
436 /* Return card info. */
437 int 
438 agent_learn (struct agent_card_info_s *info)
439 {
440   APP app;
441   int rc;
442   struct ctrl_ctx_s ctrl;
443   time_t stamp;
444   char *serial;
445   
446   app = open_card ();
447   if (!app)
448     return gpg_error (GPG_ERR_CARD);
449
450   memset (&ctrl, 0, sizeof ctrl);
451   ctrl.status_cb = learn_status_cb;
452   ctrl.status_cb_arg = info;
453
454   rc = app_get_serial_and_stamp (app, &serial, &stamp);
455   if (!rc)
456     {
457       send_status_info (&ctrl, "SERIALNO", serial, strlen(serial), NULL, 0);
458       xfree (serial);
459       rc = app->fnc.learn_status (app, &ctrl);
460     }
461
462   return rc;
463 }
464
465 /* Send a SETATTR command to the SCdaemon. */
466 int 
467 agent_scd_setattr (const char *name,
468                    const unsigned char *value, size_t valuelen)
469 {
470
471   return gpg_error (GPG_ERR_CARD);
472 }
473
474 /* Send a GENKEY command to the SCdaemon. */
475 int 
476 agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
477 {
478
479   return gpg_error (GPG_ERR_CARD);
480 }
481
482 /* Send a PKSIGN command to the SCdaemon. */
483 int 
484 agent_scd_pksign (const char *keyid, int hashalgo,
485                   const unsigned char *indata, size_t indatalen,
486                   char **r_buf, size_t *r_buflen)
487 {
488
489   return gpg_error (GPG_ERR_CARD);
490 }
491
492
493 /* Send a PKDECRYPT command to the SCdaemon. */
494 int 
495 agent_scd_pkdecrypt (const char *serialno,
496                      const unsigned char *indata, size_t indatalen,
497                      char **r_buf, size_t *r_buflen)
498 {
499
500   return gpg_error (GPG_ERR_CARD);
501 }
502
503 /* Change the PIN of an OpenPGP card or reset the retry counter. */
504 int 
505 agent_scd_change_pin (int chvno)
506 {
507
508   return gpg_error (GPG_ERR_CARD);
509 }
510
511
512
513
514 #endif /*ENABLE_CARD_SUPPORT*/
515