gcc-4 defaults forced me to edit many many files to get rid of the
[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 (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
227   /* FIXME: keep PI and TRIES in OPAQUE.  Frankly this is a whole
228      mess because we should call the card's verify function from the
229      pinentry check pin CB. */
230  again:
231   pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
232   if (!pi)
233     return gpg_error_from_errno (errno);
234   pi->max_length = maxbuf-1;
235   pi->min_digits = 0;  /* we want a real passphrase */
236   pi->max_digits = 8;
237   pi->max_tries = 3;
238
239   if (any_flags)
240     {
241       rc = agent_askpin (ctrl, info, prompt, again_text, pi);
242       again_text = NULL;
243       if (!rc && newpin)
244         {
245           struct pin_entry_info_s *pi2;
246           pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10);
247           if (!pi2)
248             {
249               rc = gpg_error_from_errno (errno);
250               xfree (pi);
251               return rc;
252             }
253           pi2->max_length = maxbuf-1;
254           pi2->min_digits = 0;
255           pi2->max_digits = 8;
256           pi2->max_tries = 1;
257           rc = agent_askpin (ctrl, _("Repeat this PIN"), prompt, NULL, pi2);
258           if (!rc && strcmp (pi->pin, pi2->pin))
259             {
260               again_text = N_("PIN not correctly repeated; try again");
261               xfree (pi2);
262               xfree (pi);
263               goto again;
264             }
265           xfree (pi2);
266         }
267     }
268   else
269     {
270       char *desc;
271       if ( asprintf (&desc,
272                      _("Please enter the PIN%s%s%s to unlock the card"), 
273                      info? " (`":"",
274                      info? info:"",
275                      info? "')":"") < 0)
276         desc = NULL;
277       rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi);
278       free (desc);
279     }
280
281   if (!rc)
282     {
283       strncpy (buf, pi->pin, maxbuf-1);
284       buf[maxbuf-1] = 0;
285     }
286   xfree (pi);
287   return rc;
288 }
289
290
291
292
293 int
294 divert_pksign (CTRL ctrl, 
295                const unsigned char *digest, size_t digestlen, int algo,
296                const unsigned char *shadow_info, unsigned char **r_sig)
297 {
298   int rc;
299   char *kid;
300   size_t siglen;
301   unsigned char *sigval;
302   unsigned char *data;
303   size_t ndata;
304
305   rc = ask_for_card (ctrl, shadow_info, &kid);
306   if (rc)
307     return rc;
308
309   rc = encode_md_for_card (digest, digestlen, algo, 
310                            &data, &ndata);
311   if (rc)
312     return rc;
313
314   rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
315                           data, ndata, &sigval, &siglen);
316   if (!rc)
317     *r_sig = sigval;
318   xfree (data);
319   xfree (kid);
320   
321   return rc;
322 }
323
324
325 /* Decrypt the the value given asn an S-expression in CIPHER using the
326    key identified by SHADOW_INFO and return the plaintext in an
327    allocated buffer in R_BUF.  */
328 int  
329 divert_pkdecrypt (CTRL ctrl,
330                   const unsigned char *cipher,
331                   const unsigned char *shadow_info,
332                   char **r_buf, size_t *r_len)
333 {
334   int rc;
335   char *kid;
336   const unsigned char *s;
337   size_t n;
338   const unsigned char *ciphertext;
339   size_t ciphertextlen;
340   char *plaintext;
341   size_t plaintextlen;
342
343   s = cipher;
344   if (*s != '(')
345     return gpg_error (GPG_ERR_INV_SEXP);
346   s++;
347   n = snext (&s);
348   if (!n)
349     return gpg_error (GPG_ERR_INV_SEXP); 
350   if (!smatch (&s, n, "enc-val"))
351     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
352   if (*s != '(')
353     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
354   s++;
355   n = snext (&s);
356   if (!n)
357     return gpg_error (GPG_ERR_INV_SEXP); 
358   if (!smatch (&s, n, "rsa"))
359     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
360   if (*s != '(')
361     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
362   s++;
363   n = snext (&s);
364   if (!n)
365     return gpg_error (GPG_ERR_INV_SEXP); 
366   if (!smatch (&s, n, "a"))
367     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
368   n = snext (&s);
369   if (!n)
370     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
371   ciphertext = s;
372   ciphertextlen = n;
373
374   rc = ask_for_card (ctrl, shadow_info, &kid);
375   if (rc)
376     return rc;
377
378   rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
379                              ciphertext, ciphertextlen,
380                              &plaintext, &plaintextlen);
381   if (!rc)
382     {
383       *r_buf = plaintext;
384       *r_len = plaintextlen;
385     }
386   xfree (kid);
387   return rc;
388 }
389
390
391 int  
392 divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context)
393 {
394   return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
395 }
396
397
398
399
400