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