2006-09-06 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / scd / app-nks.c
blob1213083e9a56e80a2dcab76466cb9eb12c195477
1 /* app-nks.c - The Telesec NKS 2.0 card application.
2 * Copyright (C) 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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.
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <time.h>
30 #include "scdaemon.h"
31 #include "i18n.h"
32 #include "iso7816.h"
33 #include "app-common.h"
34 #include "tlv.h"
36 static struct {
37 int fid; /* File ID. */
38 int certtype; /* Type of certificate or 0 if it is not a certificate. */
39 int iskeypair; /* If true has the FID of the correspoding certificate. */
40 int issignkey; /* True if file is a key usable for signing. */
41 int isenckey; /* True if file is a key usable for decryption. */
42 } filelist[] = {
43 { 0x4531, 0, 0xC000, 1, 0 },
44 { 0xC000, 101 },
45 { 0x4331, 100 },
46 { 0x4332, 100 },
47 { 0xB000, 110 },
48 { 0x45B1, 0, 0xC200, 0, 1 },
49 { 0xC200, 101 },
50 { 0x43B1, 100 },
51 { 0x43B2, 100 },
52 { 0, 0 }
57 /* Read the file with FID, assume it contains a public key and return
58 its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
59 static gpg_error_t
60 keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
62 gpg_error_t err;
63 unsigned char grip[20];
64 unsigned char *buffer[2];
65 size_t buflen[2];
66 gcry_sexp_t sexp;
67 int i;
69 err = iso7816_select_file (slot, fid, 0, NULL, NULL);
70 if (err)
71 return err;
72 err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]);
73 if (err)
74 return err;
75 err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]);
76 if (err)
78 xfree (buffer[0]);
79 return err;
82 for (i=0; i < 2; i++)
84 /* Check that the value appears like an integer encoded as
85 Simple-TLV. We don't check the tag because the tests cards I
86 have use 1 for both, the modulus and the exponent - the
87 example in the documentation gives 2 for the exponent. */
88 if (buflen[i] < 3)
89 err = gpg_error (GPG_ERR_TOO_SHORT);
90 else if (buffer[i][1] != buflen[i]-2 )
91 err = gpg_error (GPG_ERR_INV_OBJ);
94 if (!err)
95 err = gcry_sexp_build (&sexp, NULL,
96 "(public-key (rsa (n %b) (e %b)))",
97 (int)buflen[0]-2, buffer[0]+2,
98 (int)buflen[1]-2, buffer[1]+2);
100 xfree (buffer[0]);
101 xfree (buffer[1]);
102 if (err)
103 return err;
105 if (!gcry_pk_get_keygrip (sexp, grip))
107 err = gpg_error (GPG_ERR_INTERNAL); /* i.e. RSA not supported by
108 libgcrypt. */
110 else
112 for (i=0; i < 20; i++)
113 sprintf (r_gripstr+i*2, "%02X", grip[i]);
115 gcry_sexp_release (sexp);
116 return err;
121 static gpg_error_t
122 do_learn_status (app_t app, ctrl_t ctrl)
124 gpg_error_t err;
125 char ct_buf[100], id_buf[100];
126 int i;
128 /* Output information about all useful objects. */
129 for (i=0; filelist[i].fid; i++)
131 if (filelist[i].certtype)
133 size_t len;
135 len = app_help_read_length_of_cert (app->slot,
136 filelist[i].fid, NULL);
137 if (len)
139 /* FIXME: We should store the length in the application's
140 context so that a following readcert does only need to
141 read that many bytes. */
142 sprintf (ct_buf, "%d", filelist[i].certtype);
143 sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
144 send_status_info (ctrl, "CERTINFO",
145 ct_buf, strlen (ct_buf),
146 id_buf, strlen (id_buf),
147 NULL, (size_t)0);
150 else if (filelist[i].iskeypair)
152 char gripstr[40+1];
154 err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
155 if (err)
156 log_error ("can't get keygrip from FID 0x%04X: %s\n",
157 filelist[i].fid, gpg_strerror (err));
158 else
160 sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
161 send_status_info (ctrl, "KEYPAIRINFO",
162 gripstr, 40,
163 id_buf, strlen (id_buf),
164 NULL, (size_t)0);
169 return 0;
175 /* Read the certificate with id CERTID (as returned by learn_status in
176 the CERTINFO status lines) and return it in the freshly allocated
177 buffer put into CERT and the length of the certificate put into
178 CERTLEN. */
179 static gpg_error_t
180 do_readcert (app_t app, const char *certid,
181 unsigned char **cert, size_t *certlen)
183 int i, fid;
184 gpg_error_t err;
185 unsigned char *buffer;
186 const unsigned char *p;
187 size_t buflen, n;
188 int class, tag, constructed, ndef;
189 size_t totobjlen, objlen, hdrlen;
190 int rootca = 0;
192 *cert = NULL;
193 *certlen = 0;
194 if (strncmp (certid, "NKS-DF01.", 9) )
195 return gpg_error (GPG_ERR_INV_ID);
196 certid += 9;
197 if (!hexdigitp (certid) || !hexdigitp (certid+1)
198 || !hexdigitp (certid+2) || !hexdigitp (certid+3)
199 || certid[4])
200 return gpg_error (GPG_ERR_INV_ID);
201 fid = xtoi_4 (certid);
202 for (i=0; filelist[i].fid; i++)
203 if ((filelist[i].certtype || filelist[i].iskeypair)
204 && filelist[i].fid == fid)
205 break;
206 if (!filelist[i].fid)
207 return gpg_error (GPG_ERR_NOT_FOUND);
209 /* If the requested objects is a plain public key, redirect it to
210 the corresponding certificate. The whole system is a bit messy
211 becuase we sometime use the key directly or let the caller
212 retrieve the key from the certificate. The valid point behind
213 that is to support not-yet stored certificates. */
214 if (filelist[i].iskeypair)
215 fid = filelist[i].iskeypair;
218 /* Read the entire file. fixme: This could be optimized by first
219 reading the header to figure out how long the certificate
220 actually is. */
221 err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
222 if (err)
224 log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
225 return err;
228 err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
229 if (err)
231 log_error ("error reading certificate from FID 0x%04X: %s\n",
232 fid, gpg_strerror (err));
233 return err;
236 if (!buflen || *buffer == 0xff)
238 log_info ("no certificate contained in FID 0x%04X\n", fid);
239 err = gpg_error (GPG_ERR_NOT_FOUND);
240 goto leave;
243 /* Now figure something out about the object. */
244 p = buffer;
245 n = buflen;
246 err = parse_ber_header (&p, &n, &class, &tag, &constructed,
247 &ndef, &objlen, &hdrlen);
248 if (err)
249 goto leave;
250 if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
252 else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
253 rootca = 1;
254 else
255 return gpg_error (GPG_ERR_INV_OBJ);
256 totobjlen = objlen + hdrlen;
257 assert (totobjlen <= buflen);
259 err = parse_ber_header (&p, &n, &class, &tag, &constructed,
260 &ndef, &objlen, &hdrlen);
261 if (err)
262 goto leave;
264 if (rootca)
266 else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
268 const unsigned char *save_p;
270 /* The certificate seems to be contained in a userCertificate
271 container. Skip this and assume the following sequence is
272 the certificate. */
273 if (n < objlen)
275 err = gpg_error (GPG_ERR_INV_OBJ);
276 goto leave;
278 p += objlen;
279 n -= objlen;
280 save_p = p;
281 err = parse_ber_header (&p, &n, &class, &tag, &constructed,
282 &ndef, &objlen, &hdrlen);
283 if (err)
284 goto leave;
285 if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) )
286 return gpg_error (GPG_ERR_INV_OBJ);
287 totobjlen = objlen + hdrlen;
288 assert (save_p + totobjlen <= buffer + buflen);
289 memmove (buffer, save_p, totobjlen);
292 *cert = buffer;
293 buffer = NULL;
294 *certlen = totobjlen;
296 leave:
297 xfree (buffer);
298 return err;
302 /* Verify the PIN if required. */
303 static gpg_error_t
304 verify_pin (app_t app,
305 gpg_error_t (*pincb)(void*, const char *, char **),
306 void *pincb_arg)
308 /* Note that force_chv1 is never set but we do it here anyway so
309 that other applications may reuse this function. For example it
310 makes sense to set force_chv1 for German signature law cards.
311 NKS is very similar to the DINSIG draft standard. */
312 if (!app->did_chv1 || app->force_chv1 )
314 char *pinvalue;
315 int rc;
317 rc = pincb (pincb_arg, "PIN", &pinvalue);
318 if (rc)
320 log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
321 return rc;
324 /* The following limits are due to TCOS but also defined in the
325 NKS specs. */
326 if (strlen (pinvalue) < 6)
328 log_error ("PIN is too short; minimum length is 6\n");
329 xfree (pinvalue);
330 return gpg_error (GPG_ERR_BAD_PIN);
332 else if (strlen (pinvalue) > 16)
334 log_error ("PIN is too large; maximum length is 16\n");
335 xfree (pinvalue);
336 return gpg_error (GPG_ERR_BAD_PIN);
339 /* Also it is possible to use a local PIN, we use the gloabl
340 PIN for this application. */
341 rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
342 if (rc)
344 if ( gpg_error (rc) == GPG_ERR_USE_CONDITIONS )
345 log_error (_("the NullPIN has not yet been changed\n"));
346 else
347 log_error ("verify PIN failed\n");
348 xfree (pinvalue);
349 return rc;
351 app->did_chv1 = 1;
352 xfree (pinvalue);
355 return 0;
360 /* Create the signature and return the allocated result in OUTDATA.
361 If a PIN is required the PINCB will be used to ask for the PIN;
362 that callback should return the PIN in an allocated buffer and
363 store that in the 3rd argument. */
364 static gpg_error_t
365 do_sign (app_t app, const char *keyidstr, int hashalgo,
366 gpg_error_t (*pincb)(void*, const char *, char **),
367 void *pincb_arg,
368 const void *indata, size_t indatalen,
369 unsigned char **outdata, size_t *outdatalen )
371 static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
372 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
373 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
374 static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
375 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
376 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
377 int rc, i;
378 int fid;
379 unsigned char data[35]; /* Must be large enough for a SHA-1 digest
380 + the largest OID _prefix above. */
382 if (!keyidstr || !*keyidstr)
383 return gpg_error (GPG_ERR_INV_VALUE);
384 if (indatalen != 20 && indatalen != 16 && indatalen != 35)
385 return gpg_error (GPG_ERR_INV_VALUE);
387 /* Check that the provided ID is vaid. This is not really needed
388 but we do it to to enforce correct usage by the caller. */
389 if (strncmp (keyidstr, "NKS-DF01.", 9) )
390 return gpg_error (GPG_ERR_INV_ID);
391 keyidstr += 9;
392 if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
393 || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
394 || keyidstr[4])
395 return gpg_error (GPG_ERR_INV_ID);
396 fid = xtoi_4 (keyidstr);
397 for (i=0; filelist[i].fid; i++)
398 if (filelist[i].iskeypair && filelist[i].fid == fid)
399 break;
400 if (!filelist[i].fid)
401 return gpg_error (GPG_ERR_NOT_FOUND);
402 if (!filelist[i].issignkey)
403 return gpg_error (GPG_ERR_INV_ID);
405 /* Prepare the DER object from INDATA. */
406 if (indatalen == 35)
408 /* Alright, the caller was so kind to send us an already
409 prepared DER object. Check that it is waht we want and that
410 it matches the hash algorithm. */
411 if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
413 else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
415 else
416 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
417 memcpy (data, indata, indatalen);
419 else
421 if (hashalgo == GCRY_MD_SHA1)
422 memcpy (data, sha1_prefix, 15);
423 else if (hashalgo == GCRY_MD_RMD160)
424 memcpy (data, rmd160_prefix, 15);
425 else
426 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
427 memcpy (data+15, indata, indatalen);
430 rc = verify_pin (app, pincb, pincb_arg);
431 if (!rc)
432 rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
433 return rc;
439 /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
440 If a PIN is required the PINCB will be used to ask for the PIN; it
441 should return the PIN in an allocated buffer and put it into PIN. */
442 static gpg_error_t
443 do_decipher (app_t app, const char *keyidstr,
444 gpg_error_t (*pincb)(void*, const char *, char **),
445 void *pincb_arg,
446 const void *indata, size_t indatalen,
447 unsigned char **outdata, size_t *outdatalen )
449 static const unsigned char mse_parm[] = {
450 0x80, 1, 0x10, /* Select algorithm RSA. */
451 0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
453 int rc, i;
454 int fid;
456 if (!keyidstr || !*keyidstr || !indatalen)
457 return gpg_error (GPG_ERR_INV_VALUE);
459 /* Check that the provided ID is vaid. This is not really needed
460 but we do it to to enforce correct usage by the caller. */
461 if (strncmp (keyidstr, "NKS-DF01.", 9) )
462 return gpg_error (GPG_ERR_INV_ID);
463 keyidstr += 9;
464 if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
465 || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
466 || keyidstr[4])
467 return gpg_error (GPG_ERR_INV_ID);
468 fid = xtoi_4 (keyidstr);
469 for (i=0; filelist[i].fid; i++)
470 if (filelist[i].iskeypair && filelist[i].fid == fid)
471 break;
472 if (!filelist[i].fid)
473 return gpg_error (GPG_ERR_NOT_FOUND);
474 if (!filelist[i].isenckey)
475 return gpg_error (GPG_ERR_INV_ID);
477 /* Do the TCOS specific MSE. */
478 rc = iso7816_manage_security_env (app->slot,
479 0xC1, 0xB8,
480 mse_parm, sizeof mse_parm);
481 if (!rc)
482 rc = verify_pin (app, pincb, pincb_arg);
483 if (!rc)
484 rc = iso7816_decipher (app->slot, indata, indatalen, 0x81,
485 outdata, outdatalen);
486 return rc;
491 /* Select the NKS 2.0 application on the card in SLOT. */
492 gpg_error_t
493 app_select_nks (app_t app)
495 static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
496 int slot = app->slot;
497 int rc;
499 rc = iso7816_select_application (slot, aid, sizeof aid, 0);
500 if (!rc)
502 app->apptype = "NKS";
504 app->fnc.learn_status = do_learn_status;
505 app->fnc.readcert = do_readcert;
506 app->fnc.getattr = NULL;
507 app->fnc.setattr = NULL;
508 app->fnc.genkey = NULL;
509 app->fnc.sign = do_sign;
510 app->fnc.auth = NULL;
511 app->fnc.decipher = do_decipher;
512 app->fnc.change_pin = NULL;
513 app->fnc.check_pin = NULL;
516 return rc;