* agent.h (server_control_s): Add connection_fd field.
[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           /* We better reset the SCD now.  This is kludge requred
112              because the scdaemon is currently not always able to
113              detect the presence of a card.  With a fully working
114              scdaemon this would not be required; i.e. the pkcs#15
115              support does not require it becuase OpenSC correclty
116              detects a present card. */
117           agent_reset_scd (ctrl);
118           if (asprintf (&desc,
119                     "%s:%%0A%%0A"
120                     "  \"%.*s\"",
121                     no_card? "Please insert the card with serial number" 
122                     : "Please remove the current card and "
123                     "insert the one with serial number",
124                     want_sn_displen, want_sn) < 0)
125             {
126               rc = out_of_core ();
127             }
128           else
129             {
130               rc = agent_get_confirmation (ctrl, desc, NULL, NULL);
131               free (desc);
132             }
133         }
134       if (rc)
135         {
136           xfree (want_sn);
137           xfree (want_kid);
138           return rc;
139         }
140     }
141 }
142
143
144 /* Put the DIGEST into an DER encoded container and return it in R_VAL. */
145 static int
146 encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
147                     unsigned char **r_val, size_t *r_len)
148 {
149   byte *frame;
150   byte asn[100];
151   size_t asnlen;
152
153   asnlen = DIM(asn);
154   if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
155     {
156       log_error ("no object identifier for algo %d\n", algo);
157       return gpg_error (GPG_ERR_INTERNAL);
158     }
159
160   frame = xtrymalloc (asnlen + digestlen);
161   if (!frame)
162     return out_of_core ();
163   memcpy (frame, asn, asnlen);
164   memcpy (frame+asnlen, digest, digestlen);
165   if (DBG_CRYPTO)
166     log_printhex ("encoded hash:", frame, asnlen+digestlen);
167       
168   *r_val = frame;
169   *r_len = asnlen+digestlen;
170   return 0;
171 }
172
173
174 /* Callback used to ask for the PIN which should be set into BUF.  The
175    buf has been allocated by the caller and is of size MAXBUF which
176    includes the terminating null.  The function should return an UTF-8
177    string with the passphrase, the buffer may optionally be padded
178    with arbitrary characters */
179 static int 
180 getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
181 {
182   struct pin_entry_info_s *pi;
183   int rc;
184   char *desc;
185   CTRL ctrl = opaque;
186
187   if (maxbuf < 2)
188     return gpg_error (GPG_ERR_INV_VALUE);
189
190
191   /* FIXME: keep PI and TRIES in OPAQUE.  Frankly this is a whole
192      mess because we should call the card's verify function from the
193      pinentry check pin CB. */
194   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
195   pi->max_length = maxbuf-1;
196   pi->min_digits = 0;  /* we want a real passphrase */
197   pi->max_digits = 8;
198   pi->max_tries = 3;
199
200   if ( asprintf (&desc, _("Please enter the PIN%s%s%s to unlock the card"), 
201                  info? " (`":"",
202                  info? info:"",
203                  info? "')":"") < 0)
204     desc = NULL;
205   rc = agent_askpin (ctrl, desc?desc:info, pi);
206   free (desc);
207   if (!rc)
208     {
209       strncpy (buf, pi->pin, maxbuf-1);
210       buf[maxbuf-1] = 0;
211     }
212   xfree (pi);
213   return rc;
214 }
215
216
217
218
219 int
220 divert_pksign (CTRL ctrl, 
221                const unsigned char *digest, size_t digestlen, int algo,
222                const unsigned char *shadow_info, unsigned char **r_sig)
223 {
224   int rc;
225   char *kid;
226   size_t siglen;
227   char *sigval;
228   unsigned char *data;
229   size_t ndata;
230
231   rc = ask_for_card (ctrl, shadow_info, &kid);
232   if (rc)
233     return rc;
234
235   rc = encode_md_for_card (digest, digestlen, algo, 
236                            &data, &ndata);
237   if (rc)
238     return rc;
239
240   rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
241                           data, ndata, &sigval, &siglen);
242   if (!rc)
243     *r_sig = sigval;
244   xfree (data);
245   xfree (kid);
246   
247   return rc;
248 }
249
250
251 /* Decrypt the the value given asn an S-expression in CIPHER using the
252    key identified by SHADOW_INFO and return the plaintext in an
253    allocated buffer in R_BUF.  */
254 int  
255 divert_pkdecrypt (CTRL ctrl,
256                   const unsigned char *cipher,
257                   const unsigned char *shadow_info,
258                   char **r_buf, size_t *r_len)
259 {
260   int rc;
261   char *kid;
262   const unsigned char *s;
263   size_t n;
264   const unsigned char *ciphertext;
265   size_t ciphertextlen;
266   char *plaintext;
267   size_t plaintextlen;
268
269   s = cipher;
270   if (*s != '(')
271     return gpg_error (GPG_ERR_INV_SEXP);
272   s++;
273   n = snext (&s);
274   if (!n)
275     return gpg_error (GPG_ERR_INV_SEXP); 
276   if (!smatch (&s, n, "enc-val"))
277     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
278   if (*s != '(')
279     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
280   s++;
281   n = snext (&s);
282   if (!n)
283     return gpg_error (GPG_ERR_INV_SEXP); 
284   if (!smatch (&s, n, "rsa"))
285     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
286   if (*s != '(')
287     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
288   s++;
289   n = snext (&s);
290   if (!n)
291     return gpg_error (GPG_ERR_INV_SEXP); 
292   if (!smatch (&s, n, "a"))
293     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
294   n = snext (&s);
295   if (!n)
296     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
297   ciphertext = s;
298   ciphertextlen = n;
299
300   rc = ask_for_card (ctrl, shadow_info, &kid);
301   if (rc)
302     return rc;
303
304   rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
305                              ciphertext, ciphertextlen,
306                              &plaintext, &plaintextlen);
307   if (!rc)
308     {
309       *r_buf = plaintext;
310       *r_len = plaintextlen;
311     }
312   xfree (kid);
313   return rc;
314 }
315
316
317 int  
318 divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context)
319 {
320   return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
321 }
322
323
324
325
326