New PIN Callback attributes in gpg-agent.
[gnupg.git] / agent / divert-scd.c
1 /* divert-scd.c - divert operations to the scdaemon 
2  *      Copyright (C) 2002, 2003, 2009 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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30 #include "agent.h"
31 #include "sexp-parse.h"
32 #include "i18n.h"
33
34
35 static int
36 ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
37 {
38   int rc, i;
39   const unsigned char *s;
40   size_t n;
41   char *serialno;
42   int no_card = 0;
43   char *desc;
44   char *want_sn, *want_kid;
45   int want_sn_displen;
46
47   *r_kid = NULL;
48   s = shadow_info;
49   if (*s != '(')
50     return gpg_error (GPG_ERR_INV_SEXP);
51   s++;
52   n = snext (&s);
53   if (!n)
54     return gpg_error (GPG_ERR_INV_SEXP);
55   want_sn = xtrymalloc (n*2+1);
56   if (!want_sn)
57     return out_of_core ();
58   for (i=0; i < n; i++)
59     sprintf (want_sn+2*i, "%02X", s[i]);
60   s += n;
61   /* We assume that a 20 byte serial number is a standard one which
62      seems to have the property to have a zero in the last nibble.  We
63      don't display this '0' because it may confuse the user */
64   want_sn_displen = strlen (want_sn);
65   if (want_sn_displen == 20 && want_sn[19] == '0')
66     want_sn_displen--;
67
68   n = snext (&s);
69   if (!n)
70     return gpg_error (GPG_ERR_INV_SEXP);
71   want_kid = xtrymalloc (n+1);
72   if (!want_kid)
73     {
74       gpg_error_t tmperr = out_of_core ();
75       xfree (want_sn);
76       return tmperr;
77     }
78   memcpy (want_kid, s, n);
79   want_kid[n] = 0;
80
81   for (;;)
82     {
83       rc = agent_card_serialno (ctrl, &serialno);
84       if (!rc)
85         {
86           log_debug ("detected card with S/N %s\n", serialno);
87           i = strcmp (serialno, want_sn);
88           xfree (serialno);
89           serialno = NULL;
90           if (!i)
91             {
92               xfree (want_sn);
93               *r_kid = want_kid;
94               return 0; /* yes, we have the correct card */
95             }
96         }
97       else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
98         {
99           log_debug ("no card present\n");
100           rc = 0;
101           no_card = 1;
102         }
103       else
104         {
105           log_error ("error accesing card: %s\n", gpg_strerror (rc));
106         }
107
108       if (!rc)
109         {
110           if (asprintf (&desc,
111                     "%s:%%0A%%0A"
112                     "  \"%.*s\"",
113                     no_card? "Please insert the card with serial number" 
114                     : "Please remove the current card and "
115                     "insert the one with serial number",
116                     want_sn_displen, want_sn) < 0)
117             {
118               rc = out_of_core ();
119             }
120           else
121             {
122               rc = agent_get_confirmation (ctrl, desc, NULL, NULL);
123               xfree (desc);
124             }
125         }
126       if (rc)
127         {
128           xfree (want_sn);
129           xfree (want_kid);
130           return rc;
131         }
132     }
133 }
134
135
136 /* Put the DIGEST into an DER encoded container and return it in R_VAL. */
137 static int
138 encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
139                     unsigned char **r_val, size_t *r_len)
140 {
141   unsigned char *frame;
142   unsigned char asn[100];
143   size_t asnlen;
144
145   *r_val = NULL;
146   *r_len = 0;
147
148   asnlen = DIM(asn);
149   if (!algo || gcry_md_test_algo (algo))
150     return gpg_error (GPG_ERR_DIGEST_ALGO);
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
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 or alike.
188       'P' = The PIN is a PUK (Personal Unblocking Key).
189       'R' = The PIN is a Reset Code.
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   int resetcode = 0;
208   int is_puk = 0;
209   const char *again_text = NULL;
210   const char *prompt = "PIN";
211
212   if (buf && maxbuf < 2)
213     return gpg_error (GPG_ERR_INV_VALUE);
214
215   /* Parse the flags. */
216   if (info && *info =='|' && (ends=strchr (info+1, '|')))
217     {
218       for (s=info+1; s < ends; s++)
219         {
220           if (*s == 'A')
221             prompt = _("Admin PIN");
222           else if (*s == 'P')
223             {
224               /* TRANSLATORS: A PUK is the Personal Unblocking Code
225                  used to unblock a PIN. */
226               prompt = _("PUK");
227               is_puk = 1;
228             }
229           else if (*s == 'N')
230             newpin = 1;
231           else if (*s == 'R')
232             {
233               prompt = _("Reset Code");
234               resetcode = 1;
235             }
236         }
237       info = ends+1;
238       any_flags = 1;
239     }
240   else if (info && *info == '|')
241     log_debug ("pin_cb called without proper PIN info hack\n");
242
243   /* If BUF has been passed as NULL, we are in keypad mode: The
244      callback opens the popup and immediatley returns. */
245   if (!buf)
246     {
247       if (maxbuf == 0) /* Close the pinentry. */
248         {
249           agent_popup_message_stop (ctrl);
250           rc = 0;
251         }
252       else if (maxbuf == 1)  /* Open the pinentry. */
253         {
254           if (info)
255             {
256               char *desc;
257
258               if ( asprintf (&desc,
259                              _("%s%%0A%%0AUse the reader's keypad for input."),
260                              info) < 0 )
261                 rc = gpg_error_from_syserror ();
262               else
263                 {
264                   rc = agent_popup_message_start (ctrl, desc, NULL);
265                   xfree (desc);
266                 }
267             }
268           else
269             rc = agent_popup_message_start (ctrl, NULL, NULL);
270         }
271       else
272         rc = gpg_error (GPG_ERR_INV_VALUE);
273       return rc;
274     }
275
276   /* FIXME: keep PI and TRIES in OPAQUE.  Frankly this is a whole
277      mess because we should call the card's verify function from the
278      pinentry check pin CB. */
279  again:
280   pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
281   if (!pi)
282     return gpg_error_from_syserror ();
283   pi->max_length = maxbuf-1;
284   pi->min_digits = 0;  /* we want a real passphrase */
285   pi->max_digits = 16;
286   pi->max_tries = 3;
287
288   if (any_flags)
289     {
290       rc = agent_askpin (ctrl, info, prompt, again_text, pi);
291       again_text = NULL;
292       if (!rc && newpin)
293         {
294           struct pin_entry_info_s *pi2;
295           pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
296           if (!pi2)
297             {
298               rc = gpg_error_from_syserror ();
299               xfree (pi);
300               return rc;
301             }
302           pi2->max_length = maxbuf-1;
303           pi2->min_digits = 0;
304           pi2->max_digits = 16;
305           pi2->max_tries = 1;
306           rc = agent_askpin (ctrl,
307                              (resetcode?
308                               _("Repeat this Reset Code"):
309                               is_puk?
310                               _("Repeat this PUK"):
311                               _("Repeat this PIN")),
312                              prompt, NULL, pi2);
313           if (!rc && strcmp (pi->pin, pi2->pin))
314             {
315               again_text = (resetcode? 
316                             N_("Reset Code not correctly repeated; try again"):
317                             is_puk?
318                             N_("PUK not correctly repeated; try again"):
319                             N_("PIN not correctly repeated; try again"));
320               xfree (pi2);
321               xfree (pi);
322               goto again;
323             }
324           xfree (pi2);
325         }
326     }
327   else
328     {
329       char *desc;
330       if ( asprintf (&desc,
331                      _("Please enter the PIN%s%s%s to unlock the card"), 
332                      info? " (`":"",
333                      info? info:"",
334                      info? "')":"") < 0)
335         desc = NULL;
336       rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi);
337       xfree (desc);
338     }
339
340   if (!rc)
341     {
342       strncpy (buf, pi->pin, maxbuf-1);
343       buf[maxbuf-1] = 0;
344     }
345   xfree (pi);
346   return rc;
347 }
348
349
350
351
352 int
353 divert_pksign (ctrl_t ctrl, 
354                const unsigned char *digest, size_t digestlen, int algo,
355                const unsigned char *shadow_info, unsigned char **r_sig)
356 {
357   int rc;
358   char *kid;
359   size_t siglen;
360   unsigned char *sigval = NULL;
361
362   rc = ask_for_card (ctrl, shadow_info, &kid);
363   if (rc)
364     return rc;
365
366   if (algo == MD_USER_TLS_MD5SHA1)
367     {
368       int save = ctrl->use_auth_call;
369       ctrl->use_auth_call = 1;
370       rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
371                               digest, digestlen, &sigval, &siglen);
372       ctrl->use_auth_call = save;
373     }
374   else
375     {
376       unsigned char *data;
377       size_t ndata;
378
379       rc = encode_md_for_card (digest, digestlen, algo, &data, &ndata);
380       if (!rc)
381         {
382           rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
383                                   data, ndata, &sigval, &siglen);
384           xfree (data);
385         }
386     }
387
388   if (!rc)
389     *r_sig = sigval;
390
391   xfree (kid);
392
393   return rc;
394 }
395
396
397 /* Decrypt the the value given asn an S-expression in CIPHER using the
398    key identified by SHADOW_INFO and return the plaintext in an
399    allocated buffer in R_BUF.  */
400 int  
401 divert_pkdecrypt (ctrl_t ctrl,
402                   const unsigned char *cipher,
403                   const unsigned char *shadow_info,
404                   char **r_buf, size_t *r_len)
405 {
406   int rc;
407   char *kid;
408   const unsigned char *s;
409   size_t n;
410   const unsigned char *ciphertext;
411   size_t ciphertextlen;
412   char *plaintext;
413   size_t plaintextlen;
414
415   s = cipher;
416   if (*s != '(')
417     return gpg_error (GPG_ERR_INV_SEXP);
418   s++;
419   n = snext (&s);
420   if (!n)
421     return gpg_error (GPG_ERR_INV_SEXP); 
422   if (!smatch (&s, n, "enc-val"))
423     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
424   if (*s != '(')
425     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
426   s++;
427   n = snext (&s);
428   if (!n)
429     return gpg_error (GPG_ERR_INV_SEXP); 
430   if (!smatch (&s, n, "rsa"))
431     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
432   if (*s != '(')
433     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
434   s++;
435   n = snext (&s);
436   if (!n)
437     return gpg_error (GPG_ERR_INV_SEXP); 
438   if (!smatch (&s, n, "a"))
439     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
440   n = snext (&s);
441   if (!n)
442     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
443   ciphertext = s;
444   ciphertextlen = n;
445
446   rc = ask_for_card (ctrl, shadow_info, &kid);
447   if (rc)
448     return rc;
449
450   rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
451                              ciphertext, ciphertextlen,
452                              &plaintext, &plaintextlen);
453   if (!rc)
454     {
455       *r_buf = plaintext;
456       *r_len = plaintextlen;
457     }
458   xfree (kid);
459   return rc;
460 }
461
462
463 int  
464 divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context)
465 {
466   return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
467 }
468
469
470
471
472