bug fixes
[gnupg.git] / agent / divert-scd.c
1 /* divert-scd.c - divert operations to the scdaemon 
2  *      Copyright (C) 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., 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 "sexp-parse.h"
34 #include "i18n.h"
35
36
37 static int
38 ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
39 {
40   int rc, i;
41   const unsigned char *s;
42   size_t n;
43   char *serialno;
44   int no_card = 0;
45   char *desc;
46   char *want_sn, *want_kid;
47   int want_sn_displen;
48
49   *r_kid = NULL;
50   s = shadow_info;
51   if (*s != '(')
52     return gpg_error (GPG_ERR_INV_SEXP);
53   s++;
54   n = snext (&s);
55   if (!n)
56     return gpg_error (GPG_ERR_INV_SEXP);
57   want_sn = xtrymalloc (n*2+1);
58   if (!want_sn)
59     return out_of_core ();
60   for (i=0; i < n; i++)
61     sprintf (want_sn+2*i, "%02X", s[i]);
62   s += n;
63   /* We assume that a 20 byte serial number is a standard one which
64      seems to have the property to have a zero in the last nibble.  We
65      don't display this '0' because it may confuse the user */
66   want_sn_displen = strlen (want_sn);
67   if (want_sn_displen == 20 && want_sn[19] == '0')
68     want_sn_displen--;
69
70   n = snext (&s);
71   if (!n)
72     return gpg_error (GPG_ERR_INV_SEXP);
73   want_kid = xtrymalloc (n+1);
74   if (!want_kid)
75     {
76       gpg_error_t tmperr = out_of_core ();
77       xfree (want_sn);
78       return tmperr;
79     }
80   memcpy (want_kid, s, n);
81   want_kid[n] = 0;
82
83   for (;;)
84     {
85       rc = agent_card_serialno (ctrl, &serialno);
86       if (!rc)
87         {
88           log_debug ("detected card with S/N %s\n", serialno);
89           i = strcmp (serialno, want_sn);
90           xfree (serialno);
91           serialno = NULL;
92           if (!i)
93             {
94               xfree (want_sn);
95               *r_kid = want_kid;
96               return 0; /* yes, we have the correct card */
97             }
98         }
99       else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
100         {
101           log_debug ("no card present\n");
102           rc = 0;
103           no_card = 1;
104         }
105       else
106         {
107           log_error ("error accesing card: %s\n", gpg_strerror (rc));
108         }
109
110       if (!rc)
111         {
112           if (asprintf (&desc,
113                     "%s:%%0A%%0A"
114                     "  \"%.*s\"",
115                     no_card? "Please insert the card with serial number" 
116                     : "Please remove the current card and "
117                     "insert the one with serial number",
118                     want_sn_displen, want_sn) < 0)
119             {
120               rc = out_of_core ();
121             }
122           else
123             {
124               rc = agent_get_confirmation (ctrl, desc, NULL, NULL);
125               free (desc);
126             }
127         }
128       if (rc)
129         {
130           xfree (want_sn);
131           xfree (want_kid);
132           return rc;
133         }
134     }
135 }
136
137
138 /* Put the DIGEST into an DER encoded container and return it in R_VAL. */
139 static int
140 encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
141                     unsigned char **r_val, size_t *r_len)
142 {
143   unsigned char *frame;
144   unsigned char asn[100];
145   size_t asnlen;
146
147   *r_val = NULL;
148   *r_len = 0;
149
150   asnlen = DIM(asn);
151   if (!algo || gcry_md_test_algo (algo))
152     return gpg_error (GPG_ERR_DIGEST_ALGO);
153   if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
154     {
155       log_error ("no object identifier for algo %d\n", algo);
156       return gpg_error (GPG_ERR_INTERNAL);
157     }
158
159   frame = xtrymalloc (asnlen + digestlen);
160   if (!frame)
161     return out_of_core ();
162   memcpy (frame, asn, asnlen);
163   memcpy (frame+asnlen, digest, digestlen);
164   if (DBG_CRYPTO)
165     log_printhex ("encoded hash:", frame, asnlen+digestlen);
166       
167   *r_val = frame;
168   *r_len = asnlen+digestlen;
169   return 0;
170 }
171
172
173 /* Callback used to ask for the PIN which should be set into BUF.  The
174    buf has been allocated by the caller and is of size MAXBUF which
175    includes the terminating null.  The function should return an UTF-8
176    string with the passphrase, the buffer may optionally be padded
177    with arbitrary characters.
178
179    INFO gets displayed as part of a generic string.  However if the
180    first character of INFO is a vertical bar all up to the next
181    verical bar are considered flags and only everything after the
182    second vertical bar gets displayed as the full prompt.
183
184    Flags:
185
186       'N' = New PIN, this requests a second prompt to repeat the the
187             PIN.  If the PIN is not correctly repeated it starts from
188             all over.
189       'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike.
190
191    Example:
192
193      "|AN|Please enter the new security officer's PIN"
194      
195    The text "Please ..." will get displayed and the flags 'A' and 'N'
196    are considered.
197  */
198 static int 
199 getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
200 {
201   struct pin_entry_info_s *pi;
202   int rc;
203   ctrl_t ctrl = opaque;
204   const char *ends, *s;
205   int any_flags = 0;
206   int newpin = 0;
207   const char *again_text = NULL;
208   const char *prompt = "PIN";
209
210   if (buf && maxbuf < 2)
211     return gpg_error (GPG_ERR_INV_VALUE);
212
213   /* Parse the flags. */
214   if (info && *info =='|' && (ends=strchr (info+1, '|')))
215     {
216       for (s=info+1; s < ends; s++)
217         {
218           if (*s == 'A')
219             prompt = _("Admin PIN");
220           else if (*s == 'N')
221             newpin = 1;
222         }
223       info = ends+1;
224       any_flags = 1;
225     }
226   else if (info && *info == '|')
227     log_debug ("pin_cb called without proper PIN info hack\n");
228
229   /* If BUF has been passed as NULL, we are in keypad mode: The
230      callback opens the popup and immediatley returns. */
231   if (!buf)
232     {
233       if (maxbuf == 0) /* Close the pinentry. */
234         {
235           agent_popup_message_stop (ctrl);
236           rc = 0;
237         }
238       else if (maxbuf == 1)  /* Open the pinentry. */
239         {
240           rc = agent_popup_message_start (ctrl, info, NULL, NULL);
241         }
242       else
243         rc = gpg_error (GPG_ERR_INV_VALUE);
244       return rc;
245     }
246
247   /* FIXME: keep PI and TRIES in OPAQUE.  Frankly this is a whole
248      mess because we should call the card's verify function from the
249      pinentry check pin CB. */
250  again:
251   pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
252   if (!pi)
253     return gpg_error_from_syserror ();
254   pi->max_length = maxbuf-1;
255   pi->min_digits = 0;  /* we want a real passphrase */
256   pi->max_digits = 8;
257   pi->max_tries = 3;
258
259   if (any_flags)
260     {
261       rc = agent_askpin (ctrl, info, prompt, again_text, pi);
262       again_text = NULL;
263       if (!rc && newpin)
264         {
265           struct pin_entry_info_s *pi2;
266           pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
267           if (!pi2)
268             {
269               rc = gpg_error_from_syserror ();
270               xfree (pi);
271               return rc;
272             }
273           pi2->max_length = maxbuf-1;
274           pi2->min_digits = 0;
275           pi2->max_digits = 8;
276           pi2->max_tries = 1;
277           rc = agent_askpin (ctrl, _("Repeat this PIN"), prompt, NULL, pi2);
278           if (!rc && strcmp (pi->pin, pi2->pin))
279             {
280               again_text = N_("PIN not correctly repeated; try again");
281               xfree (pi2);
282               xfree (pi);
283               goto again;
284             }
285           xfree (pi2);
286         }
287     }
288   else
289     {
290       char *desc;
291       if ( asprintf (&desc,
292                      _("Please enter the PIN%s%s%s to unlock the card"), 
293                      info? " (`":"",
294                      info? info:"",
295                      info? "')":"") < 0)
296         desc = NULL;
297       rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi);
298       free (desc);
299     }
300
301   if (!rc)
302     {
303       strncpy (buf, pi->pin, maxbuf-1);
304       buf[maxbuf-1] = 0;
305     }
306   xfree (pi);
307   return rc;
308 }
309
310
311
312
313 int
314 divert_pksign (ctrl_t ctrl, 
315                const unsigned char *digest, size_t digestlen, int algo,
316                const unsigned char *shadow_info, unsigned char **r_sig)
317 {
318   int rc;
319   char *kid;
320   size_t siglen;
321   unsigned char *sigval;
322   unsigned char *data;
323   size_t ndata;
324
325   rc = ask_for_card (ctrl, shadow_info, &kid);
326   if (rc)
327     return rc;
328
329   rc = encode_md_for_card (digest, digestlen, algo, 
330                            &data, &ndata);
331   if (rc)
332     return rc;
333
334   rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
335                           data, ndata, &sigval, &siglen);
336   if (!rc)
337     *r_sig = sigval;
338   xfree (data);
339   xfree (kid);
340   
341   return rc;
342 }
343
344
345 /* Decrypt the the value given asn an S-expression in CIPHER using the
346    key identified by SHADOW_INFO and return the plaintext in an
347    allocated buffer in R_BUF.  */
348 int  
349 divert_pkdecrypt (ctrl_t ctrl,
350                   const unsigned char *cipher,
351                   const unsigned char *shadow_info,
352                   char **r_buf, size_t *r_len)
353 {
354   int rc;
355   char *kid;
356   const unsigned char *s;
357   size_t n;
358   const unsigned char *ciphertext;
359   size_t ciphertextlen;
360   char *plaintext;
361   size_t plaintextlen;
362
363   s = cipher;
364   if (*s != '(')
365     return gpg_error (GPG_ERR_INV_SEXP);
366   s++;
367   n = snext (&s);
368   if (!n)
369     return gpg_error (GPG_ERR_INV_SEXP); 
370   if (!smatch (&s, n, "enc-val"))
371     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
372   if (*s != '(')
373     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
374   s++;
375   n = snext (&s);
376   if (!n)
377     return gpg_error (GPG_ERR_INV_SEXP); 
378   if (!smatch (&s, n, "rsa"))
379     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
380   if (*s != '(')
381     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
382   s++;
383   n = snext (&s);
384   if (!n)
385     return gpg_error (GPG_ERR_INV_SEXP); 
386   if (!smatch (&s, n, "a"))
387     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
388   n = snext (&s);
389   if (!n)
390     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
391   ciphertext = s;
392   ciphertextlen = n;
393
394   rc = ask_for_card (ctrl, shadow_info, &kid);
395   if (rc)
396     return rc;
397
398   rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
399                              ciphertext, ciphertextlen,
400                              &plaintext, &plaintextlen);
401   if (!rc)
402     {
403       *r_buf = plaintext;
404       *r_len = plaintextlen;
405     }
406   xfree (kid);
407   return rc;
408 }
409
410
411 int  
412 divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context)
413 {
414   return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
415 }
416
417
418
419
420