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