Moved 1.9 branch to trunk
[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 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 (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
152     {
153       log_error ("no object identifier for algo %d\n", algo);
154       return gpg_error (GPG_ERR_INTERNAL);
155     }
156
157   frame = xtrymalloc (asnlen + digestlen);
158   if (!frame)
159     return out_of_core ();
160   memcpy (frame, asn, asnlen);
161   memcpy (frame+asnlen, digest, digestlen);
162   if (DBG_CRYPTO)
163     log_printhex ("encoded hash:", frame, asnlen+digestlen);
164       
165   *r_val = frame;
166   *r_len = asnlen+digestlen;
167   return 0;
168 }
169
170
171 /* Callback used to ask for the PIN which should be set into BUF.  The
172    buf has been allocated by the caller and is of size MAXBUF which
173    includes the terminating null.  The function should return an UTF-8
174    string with the passphrase, the buffer may optionally be padded
175    with arbitrary characters.
176
177    INFO gets displayed as part of a generic string.  However if the
178    first character of INFO is a vertical bar all up to the next
179    verical bar are considered flags and only everything after the
180    second vertical bar gets displayed as the full prompt.
181
182    Flags:
183
184       'N' = New PIN, this requests a second prompt to repeat the the
185             PIN.  If the PIN is not correctly repeated it starts from
186             all over.
187       'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike.
188
189    Example:
190
191      "|AN|Please enter the new security officer's PIN"
192      
193    The text "Please ..." will get displayed and the flags 'A' and 'N'
194    are considered.
195  */
196 static int 
197 getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
198 {
199   struct pin_entry_info_s *pi;
200   int rc;
201   ctrl_t ctrl = opaque;
202   const char *ends, *s;
203   int any_flags = 0;
204   int newpin = 0;
205   const char *again_text = NULL;
206   const char *prompt = "PIN";
207
208   if (buf && maxbuf < 2)
209     return gpg_error (GPG_ERR_INV_VALUE);
210
211   /* Parse the flags. */
212   if (info && *info =='|' && (ends=strchr (info+1, '|')))
213     {
214       for (s=info+1; s < ends; s++)
215         {
216           if (*s == 'A')
217             prompt = _("Admin PIN");
218           else if (*s == 'N')
219             newpin = 1;
220         }
221       info = ends+1;
222       any_flags = 1;
223     }
224   else if (info && *info == '|')
225     log_debug ("pin_cb called without proper PIN info hack\n");
226
227   /* If BUF has been passed as NULL, we are in keypad mode: The
228      callback opens the popup and immediatley returns. */
229   if (!buf)
230     {
231       if (maxbuf == 0) /* Close the pinentry. */
232         {
233           agent_popup_message_stop (ctrl);
234           rc = 0;
235         }
236       else if (maxbuf == 1)  /* Open the pinentry. */
237         {
238           rc = agent_popup_message_start (ctrl, info, NULL, NULL);
239         }
240       else
241         rc = gpg_error (GPG_ERR_INV_VALUE);
242       return rc;
243     }
244
245   /* FIXME: keep PI and TRIES in OPAQUE.  Frankly this is a whole
246      mess because we should call the card's verify function from the
247      pinentry check pin CB. */
248  again:
249   pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
250   if (!pi)
251     return gpg_error_from_errno (errno);
252   pi->max_length = maxbuf-1;
253   pi->min_digits = 0;  /* we want a real passphrase */
254   pi->max_digits = 8;
255   pi->max_tries = 3;
256
257   if (any_flags)
258     {
259       rc = agent_askpin (ctrl, info, prompt, again_text, pi);
260       again_text = NULL;
261       if (!rc && newpin)
262         {
263           struct pin_entry_info_s *pi2;
264           pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
265           if (!pi2)
266             {
267               rc = gpg_error_from_errno (errno);
268               xfree (pi);
269               return rc;
270             }
271           pi2->max_length = maxbuf-1;
272           pi2->min_digits = 0;
273           pi2->max_digits = 8;
274           pi2->max_tries = 1;
275           rc = agent_askpin (ctrl, _("Repeat this PIN"), prompt, NULL, pi2);
276           if (!rc && strcmp (pi->pin, pi2->pin))
277             {
278               again_text = N_("PIN not correctly repeated; try again");
279               xfree (pi2);
280               xfree (pi);
281               goto again;
282             }
283           xfree (pi2);
284         }
285     }
286   else
287     {
288       char *desc;
289       if ( asprintf (&desc,
290                      _("Please enter the PIN%s%s%s to unlock the card"), 
291                      info? " (`":"",
292                      info? info:"",
293                      info? "')":"") < 0)
294         desc = NULL;
295       rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi);
296       free (desc);
297     }
298
299   if (!rc)
300     {
301       strncpy (buf, pi->pin, maxbuf-1);
302       buf[maxbuf-1] = 0;
303     }
304   xfree (pi);
305   return rc;
306 }
307
308
309
310
311 int
312 divert_pksign (CTRL ctrl, 
313                const unsigned char *digest, size_t digestlen, int algo,
314                const unsigned char *shadow_info, unsigned char **r_sig)
315 {
316   int rc;
317   char *kid;
318   size_t siglen;
319   unsigned char *sigval;
320   unsigned char *data;
321   size_t ndata;
322
323   rc = ask_for_card (ctrl, shadow_info, &kid);
324   if (rc)
325     return rc;
326
327   rc = encode_md_for_card (digest, digestlen, algo, 
328                            &data, &ndata);
329   if (rc)
330     return rc;
331
332   rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
333                           data, ndata, &sigval, &siglen);
334   if (!rc)
335     *r_sig = sigval;
336   xfree (data);
337   xfree (kid);
338   
339   return rc;
340 }
341
342
343 /* Decrypt the the value given asn an S-expression in CIPHER using the
344    key identified by SHADOW_INFO and return the plaintext in an
345    allocated buffer in R_BUF.  */
346 int  
347 divert_pkdecrypt (CTRL ctrl,
348                   const unsigned char *cipher,
349                   const unsigned char *shadow_info,
350                   char **r_buf, size_t *r_len)
351 {
352   int rc;
353   char *kid;
354   const unsigned char *s;
355   size_t n;
356   const unsigned char *ciphertext;
357   size_t ciphertextlen;
358   char *plaintext;
359   size_t plaintextlen;
360
361   s = cipher;
362   if (*s != '(')
363     return gpg_error (GPG_ERR_INV_SEXP);
364   s++;
365   n = snext (&s);
366   if (!n)
367     return gpg_error (GPG_ERR_INV_SEXP); 
368   if (!smatch (&s, n, "enc-val"))
369     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
370   if (*s != '(')
371     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
372   s++;
373   n = snext (&s);
374   if (!n)
375     return gpg_error (GPG_ERR_INV_SEXP); 
376   if (!smatch (&s, n, "rsa"))
377     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
378   if (*s != '(')
379     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
380   s++;
381   n = snext (&s);
382   if (!n)
383     return gpg_error (GPG_ERR_INV_SEXP); 
384   if (!smatch (&s, n, "a"))
385     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
386   n = snext (&s);
387   if (!n)
388     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
389   ciphertext = s;
390   ciphertextlen = n;
391
392   rc = ask_for_card (ctrl, shadow_info, &kid);
393   if (rc)
394     return rc;
395
396   rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
397                              ciphertext, ciphertextlen,
398                              &plaintext, &plaintextlen);
399   if (!rc)
400     {
401       *r_buf = plaintext;
402       *r_len = plaintextlen;
403     }
404   xfree (kid);
405   return rc;
406 }
407
408
409 int  
410 divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context)
411 {
412   return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
413 }
414
415
416
417
418