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