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