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