* Makefile.am (pkglib_PROGRAMS): Put protect-tool there.
[gnupg.git] / agent / divert-scd.c
1 /* divert-scd.c - divert operations to the scdaemon 
2  *      Copyright (C) 2002 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
34
35
36 static int
37 ask_for_card (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 GNUPG_Invalid_Sexp;
52   s++;
53   n = snext (&s);
54   if (!n)
55     return GNUPG_Invalid_Sexp;
56   want_sn = xtrymalloc (n*2+1);
57   if (!want_sn)
58     return GNUPG_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 GNUPG_Invalid_Sexp;
72   want_kid = xtrymalloc (n+1);
73   if (!want_kid)
74     {
75       xfree (want_sn);
76       return GNUPG_Out_Of_Core;
77     }
78   memcpy (want_kid, s, n);
79   want_kid[n] = 0;
80
81   for (;;)
82     {
83       rc = agent_card_serialno (&serialno);
84       if (!rc)
85         {
86           log_debug ("detected card with S/N %s\n", serialno);
87           i = strcmp (serialno, want_sn);
88           xfree (serialno);
89           serialno = NULL;
90           if (!i)
91             {
92               xfree (want_sn);
93               *r_kid = want_kid;
94               return 0; /* yes, we have the correct card */
95             }
96         }
97       else if (rc == GNUPG_Card_Not_Present)
98         {
99           log_debug ("no card present\n");
100           rc = 0;
101           no_card = 1;
102         }
103       else
104         {
105           log_error ("error accesing card: %s\n", gnupg_strerror (rc));
106         }
107
108       if (!rc)
109         {
110           if (asprintf (&desc,
111                     "%s:%%0A%%0A"
112                     "  \"%.*s\"",
113                     no_card? "Please insert the card with serial number" 
114                     : "Please remove the current card and "
115                     "insert the one with serial number",
116                     want_sn_displen, want_sn) < 0)
117             {
118               rc = GNUPG_Out_Of_Core;
119             }
120           else
121             {
122               rc = agent_get_confirmation (desc, NULL, NULL);
123               free (desc);
124             }
125         }
126       if (rc)
127         {
128           xfree (want_sn);
129           xfree (want_kid);
130           return rc;
131         }
132     }
133 }
134
135
136 /* Put the DIGEST into an DER encoded comtainer and return it in R_VAL. */
137 static int
138 encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
139                     unsigned char **r_val, size_t *r_len)
140 {
141   byte *frame;
142   byte asn[100];
143   size_t asnlen;
144
145   asnlen = DIM(asn);
146   if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
147     {
148       log_error ("no object identifier for algo %d\n", algo);
149       return GNUPG_Internal_Error;
150     }
151
152   frame = xtrymalloc (asnlen + digestlen);
153   if (!frame)
154     return GNUPG_Out_Of_Core;
155   memcpy (frame, asn, asnlen);
156   memcpy (frame+asnlen, digest, digestlen);
157   if (DBG_CRYPTO)
158     log_printhex ("encoded hash:", frame, asnlen+digestlen);
159       
160   *r_val = frame;
161   *r_len = asnlen+digestlen;
162   return 0;
163 }
164
165
166 /* Callback used to ask for the PIN which should be set into BUF.  The
167    buf has been allocated by the caller and is of size MAXBUF which
168    includes the terminating null.  The function should return an UTF-8
169    string with the passphrase, the buffer may optionally be padded
170    with arbitrary characters */
171 static int 
172 getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
173 {
174   struct pin_entry_info_s *pi;
175   int rc;
176
177   assert (!opaque);
178
179   if (maxbuf < 2)
180     return GNUPG_Invalid_Value;
181
182   /* FIXME: keep PI and TRIES in OPAQUE.  Actually this is a whole
183      mess becuase we should call the card's verify function from the
184      pinentry check pin CB. */
185   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
186   pi->max_length = maxbuf-1;
187   pi->min_digits = 0;  /* we want a real passphrase */
188   pi->max_digits = 8;
189   pi->max_tries = 3;
190
191   rc = agent_askpin (info, pi);
192   if (!rc)
193     {
194       strncpy (buf, pi->pin, maxbuf-1);
195       buf[maxbuf-1] = 0;
196     }
197   xfree (pi);
198   return rc;
199 }
200
201
202
203
204 int
205 divert_pksign (const unsigned char *digest, size_t digestlen, int algo,
206                const unsigned char *shadow_info, unsigned char **r_sig)
207 {
208   int rc;
209   char *kid;
210   size_t siglen;
211   char *sigval;
212   unsigned char *data;
213   size_t ndata;
214
215   rc = ask_for_card (shadow_info, &kid);
216   if (rc)
217     return rc;
218
219   rc = encode_md_for_card (digest, digestlen, algo, 
220                            &data, &ndata);
221   if (rc)
222     return rc;
223
224   rc = agent_card_pksign (kid, getpin_cb, NULL,
225                           data, ndata, &sigval, &siglen);
226   if (!rc)
227     *r_sig = sigval;
228   xfree (data);
229   xfree (kid);
230   
231   return rc;
232 }
233
234
235 /* Decrypt the the value given asn an S-expression in CIPHER using the
236    key identified by SHADOW_INFO and return the plaintext in an
237    allocated buffer in R_BUF.  */
238 int  
239 divert_pkdecrypt (const unsigned char *cipher,
240                   const unsigned char *shadow_info,
241                   char **r_buf, size_t *r_len)
242 {
243   int rc;
244   char *kid;
245   const unsigned char *s;
246   size_t n;
247   const unsigned char *ciphertext;
248   size_t ciphertextlen;
249   char *plaintext;
250   size_t plaintextlen;
251
252   s = cipher;
253   if (*s != '(')
254     return GNUPG_Invalid_Sexp;
255   s++;
256   n = snext (&s);
257   if (!n)
258     return GNUPG_Invalid_Sexp; 
259   if (!smatch (&s, n, "enc-val"))
260     return GNUPG_Unknown_Sexp; 
261   if (*s != '(')
262     return GNUPG_Unknown_Sexp;
263   s++;
264   n = snext (&s);
265   if (!n)
266     return GNUPG_Invalid_Sexp; 
267   if (!smatch (&s, n, "rsa"))
268     return GNUPG_Unsupported_Algorithm; 
269   if (*s != '(')
270     return GNUPG_Unknown_Sexp;
271   s++;
272   n = snext (&s);
273   if (!n)
274     return GNUPG_Invalid_Sexp; 
275   if (!smatch (&s, n, "a"))
276     return GNUPG_Unknown_Sexp;
277   n = snext (&s);
278   if (!n)
279     return GNUPG_Unknown_Sexp; 
280   ciphertext = s;
281   ciphertextlen = n;
282
283   rc = ask_for_card (shadow_info, &kid);
284   if (rc)
285     return rc;
286
287   rc = agent_card_pkdecrypt (kid, getpin_cb, NULL,
288                              ciphertext, ciphertextlen,
289                              &plaintext, &plaintextlen);
290   if (!rc)
291     {
292       *r_buf = plaintext;
293       *r_len = plaintextlen;
294     }
295   xfree (kid);
296   return rc;
297 }