1 /* app-nks.c - The Telesec NKS 2.0 card application.
2 * Copyright (C) 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>.
31 #include "app-common.h"
36 int fid
; /* File ID. */
37 int certtype
; /* Type of certificate or 0 if it is not a certificate. */
38 int iskeypair
; /* If true has the FID of the correspoding certificate. */
39 int issignkey
; /* True if file is a key usable for signing. */
40 int isenckey
; /* True if file is a key usable for decryption. */
42 { 0x4531, 0, 0xC000, 1, 0 },
47 { 0x45B1, 0, 0xC200, 0, 1 },
56 /* Read the file with FID, assume it contains a public key and return
57 its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
59 keygripstr_from_pk_file (int slot
, int fid
, char *r_gripstr
)
62 unsigned char grip
[20];
63 unsigned char *buffer
[2];
68 err
= iso7816_select_file (slot
, fid
, 0, NULL
, NULL
);
71 err
= iso7816_read_record (slot
, 1, 1, 0, &buffer
[0], &buflen
[0]);
74 err
= iso7816_read_record (slot
, 2, 1, 0, &buffer
[1], &buflen
[1]);
83 /* Check that the value appears like an integer encoded as
84 Simple-TLV. We don't check the tag because the tests cards I
85 have use 1 for both, the modulus and the exponent - the
86 example in the documentation gives 2 for the exponent. */
88 err
= gpg_error (GPG_ERR_TOO_SHORT
);
89 else if (buffer
[i
][1] != buflen
[i
]-2 )
90 err
= gpg_error (GPG_ERR_INV_OBJ
);
94 err
= gcry_sexp_build (&sexp
, NULL
,
95 "(public-key (rsa (n %b) (e %b)))",
96 (int)buflen
[0]-2, buffer
[0]+2,
97 (int)buflen
[1]-2, buffer
[1]+2);
104 if (!gcry_pk_get_keygrip (sexp
, grip
))
106 err
= gpg_error (GPG_ERR_INTERNAL
); /* i.e. RSA not supported by
111 bin2hex (grip
, 20, r_gripstr
);
113 gcry_sexp_release (sexp
);
120 do_learn_status (app_t app
, ctrl_t ctrl
)
123 char ct_buf
[100], id_buf
[100];
126 /* Output information about all useful objects. */
127 for (i
=0; filelist
[i
].fid
; i
++)
129 if (filelist
[i
].certtype
)
133 len
= app_help_read_length_of_cert (app
->slot
,
134 filelist
[i
].fid
, NULL
);
137 /* FIXME: We should store the length in the application's
138 context so that a following readcert does only need to
139 read that many bytes. */
140 sprintf (ct_buf
, "%d", filelist
[i
].certtype
);
141 sprintf (id_buf
, "NKS-DF01.%04X", filelist
[i
].fid
);
142 send_status_info (ctrl
, "CERTINFO",
143 ct_buf
, strlen (ct_buf
),
144 id_buf
, strlen (id_buf
),
148 else if (filelist
[i
].iskeypair
)
152 err
= keygripstr_from_pk_file (app
->slot
, filelist
[i
].fid
, gripstr
);
154 log_error ("can't get keygrip from FID 0x%04X: %s\n",
155 filelist
[i
].fid
, gpg_strerror (err
));
158 sprintf (id_buf
, "NKS-DF01.%04X", filelist
[i
].fid
);
159 send_status_info (ctrl
, "KEYPAIRINFO",
161 id_buf
, strlen (id_buf
),
173 /* Read the certificate with id CERTID (as returned by learn_status in
174 the CERTINFO status lines) and return it in the freshly allocated
175 buffer put into CERT and the length of the certificate put into
178 do_readcert (app_t app
, const char *certid
,
179 unsigned char **cert
, size_t *certlen
)
183 unsigned char *buffer
;
184 const unsigned char *p
;
186 int class, tag
, constructed
, ndef
;
187 size_t totobjlen
, objlen
, hdrlen
;
192 if (strncmp (certid
, "NKS-DF01.", 9) )
193 return gpg_error (GPG_ERR_INV_ID
);
195 if (!hexdigitp (certid
) || !hexdigitp (certid
+1)
196 || !hexdigitp (certid
+2) || !hexdigitp (certid
+3)
198 return gpg_error (GPG_ERR_INV_ID
);
199 fid
= xtoi_4 (certid
);
200 for (i
=0; filelist
[i
].fid
; i
++)
201 if ((filelist
[i
].certtype
|| filelist
[i
].iskeypair
)
202 && filelist
[i
].fid
== fid
)
204 if (!filelist
[i
].fid
)
205 return gpg_error (GPG_ERR_NOT_FOUND
);
207 /* If the requested objects is a plain public key, redirect it to
208 the corresponding certificate. The whole system is a bit messy
209 because we sometime use the key directly or let the caller
210 retrieve the key from the certificate. The rationale for
211 that is to support not-yet stored certificates. */
212 if (filelist
[i
].iskeypair
)
213 fid
= filelist
[i
].iskeypair
;
216 /* Read the entire file. fixme: This could be optimized by first
217 reading the header to figure out how long the certificate
219 err
= iso7816_select_file (app
->slot
, fid
, 0, NULL
, NULL
);
222 log_error ("error selecting FID 0x%04X: %s\n", fid
, gpg_strerror (err
));
226 err
= iso7816_read_binary (app
->slot
, 0, 0, &buffer
, &buflen
);
229 log_error ("error reading certificate from FID 0x%04X: %s\n",
230 fid
, gpg_strerror (err
));
234 if (!buflen
|| *buffer
== 0xff)
236 log_info ("no certificate contained in FID 0x%04X\n", fid
);
237 err
= gpg_error (GPG_ERR_NOT_FOUND
);
241 /* Now figure something out about the object. */
244 err
= parse_ber_header (&p
, &n
, &class, &tag
, &constructed
,
245 &ndef
, &objlen
, &hdrlen
);
248 if ( class == CLASS_UNIVERSAL
&& tag
== TAG_SEQUENCE
&& constructed
)
250 else if ( class == CLASS_UNIVERSAL
&& tag
== TAG_SET
&& constructed
)
253 return gpg_error (GPG_ERR_INV_OBJ
);
254 totobjlen
= objlen
+ hdrlen
;
255 assert (totobjlen
<= buflen
);
257 err
= parse_ber_header (&p
, &n
, &class, &tag
, &constructed
,
258 &ndef
, &objlen
, &hdrlen
);
264 else if (class == CLASS_UNIVERSAL
&& tag
== TAG_OBJECT_ID
&& !constructed
)
266 const unsigned char *save_p
;
268 /* The certificate seems to be contained in a userCertificate
269 container. Skip this and assume the following sequence is
273 err
= gpg_error (GPG_ERR_INV_OBJ
);
279 err
= parse_ber_header (&p
, &n
, &class, &tag
, &constructed
,
280 &ndef
, &objlen
, &hdrlen
);
283 if ( !(class == CLASS_UNIVERSAL
&& tag
== TAG_SEQUENCE
&& constructed
) )
284 return gpg_error (GPG_ERR_INV_OBJ
);
285 totobjlen
= objlen
+ hdrlen
;
286 assert (save_p
+ totobjlen
<= buffer
+ buflen
);
287 memmove (buffer
, save_p
, totobjlen
);
292 *certlen
= totobjlen
;
300 /* Verify the PIN if required. */
302 verify_pin (app_t app
,
303 gpg_error_t (*pincb
)(void*, const char *, char **),
306 iso7816_pininfo_t pininfo
;
309 /* Note that force_chv1 is never set but we do it here anyway so
310 that other applications may reuse this function. For example it
311 makes sense to set force_chv1 for German signature law cards.
312 NKS is very similar to the DINSIG draft standard. */
313 if ( app
->did_chv1
&& !app
->force_chv1
)
314 return 0; /* No need to verify it again. */
316 memset (&pininfo
, 0, sizeof pininfo
);
321 if (!opt
.disable_keypad
322 && !iso7816_check_keypad (app
->slot
, ISO7816_VERIFY
, &pininfo
) )
324 rc
= pincb (pincb_arg
,
325 _("||Please enter your PIN at the reader's keypad"),
329 log_info (_("PIN callback returned error: %s\n"),
334 /* Although it is possible to use a local PIN, we use the global
335 PIN for this application. */
336 rc
= iso7816_verify_kp (app
->slot
, 0, "", 0, &pininfo
);
337 /* Dismiss the prompt. */
338 pincb (pincb_arg
, NULL
, NULL
);
344 rc
= pincb (pincb_arg
, "PIN", &pinvalue
);
347 log_info ("PIN callback returned error: %s\n", gpg_strerror (rc
));
351 /* The following limits are due to TCOS but also defined in the
353 if (strlen (pinvalue
) < pininfo
.minlen
)
355 log_error ("PIN is too short; minimum length is %d\n",
358 return gpg_error (GPG_ERR_BAD_PIN
);
360 else if (strlen (pinvalue
) > pininfo
.maxlen
)
362 log_error ("PIN is too large; maximum length is %d\n",
365 return gpg_error (GPG_ERR_BAD_PIN
);
368 /* Although it is possible to use a local PIN, we use the global
369 PIN for this application. */
370 rc
= iso7816_verify (app
->slot
, 0, pinvalue
, strlen (pinvalue
));
376 if ( gpg_err_code (rc
) == GPG_ERR_USE_CONDITIONS
)
377 log_error (_("the NullPIN has not yet been changed\n"));
379 log_error ("verify PIN failed\n");
389 /* Create the signature and return the allocated result in OUTDATA.
390 If a PIN is required the PINCB will be used to ask for the PIN;
391 that callback should return the PIN in an allocated buffer and
392 store that in the 3rd argument. */
394 do_sign (app_t app
, const char *keyidstr
, int hashalgo
,
395 gpg_error_t (*pincb
)(void*, const char *, char **),
397 const void *indata
, size_t indatalen
,
398 unsigned char **outdata
, size_t *outdatalen
)
400 static unsigned char sha1_prefix
[15] = /* Object ID is 1.3.14.3.2.26 */
401 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
402 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
403 static unsigned char rmd160_prefix
[15] = /* Object ID is 1.3.36.3.2.1 */
404 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
405 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
408 unsigned char data
[35]; /* Must be large enough for a SHA-1 digest
409 + the largest OID _prefix above. */
411 if (!keyidstr
|| !*keyidstr
)
412 return gpg_error (GPG_ERR_INV_VALUE
);
413 if (indatalen
!= 20 && indatalen
!= 16 && indatalen
!= 35)
414 return gpg_error (GPG_ERR_INV_VALUE
);
416 /* Check that the provided ID is valid. This is not really needed
417 but we do it to enforce correct usage by the caller. */
418 if (strncmp (keyidstr
, "NKS-DF01.", 9) )
419 return gpg_error (GPG_ERR_INV_ID
);
421 if (!hexdigitp (keyidstr
) || !hexdigitp (keyidstr
+1)
422 || !hexdigitp (keyidstr
+2) || !hexdigitp (keyidstr
+3)
424 return gpg_error (GPG_ERR_INV_ID
);
425 fid
= xtoi_4 (keyidstr
);
426 for (i
=0; filelist
[i
].fid
; i
++)
427 if (filelist
[i
].iskeypair
&& filelist
[i
].fid
== fid
)
429 if (!filelist
[i
].fid
)
430 return gpg_error (GPG_ERR_NOT_FOUND
);
431 if (!filelist
[i
].issignkey
)
432 return gpg_error (GPG_ERR_INV_ID
);
434 /* Prepare the DER object from INDATA. */
437 /* Alright, the caller was so kind to send us an already
438 prepared DER object. Check that it is waht we want and that
439 it matches the hash algorithm. */
440 if (hashalgo
== GCRY_MD_SHA1
&& !memcmp (indata
, sha1_prefix
, 15))
442 else if (hashalgo
== GCRY_MD_RMD160
&& !memcmp (indata
, rmd160_prefix
,15))
445 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
446 memcpy (data
, indata
, indatalen
);
450 if (hashalgo
== GCRY_MD_SHA1
)
451 memcpy (data
, sha1_prefix
, 15);
452 else if (hashalgo
== GCRY_MD_RMD160
)
453 memcpy (data
, rmd160_prefix
, 15);
455 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
456 memcpy (data
+15, indata
, indatalen
);
459 rc
= verify_pin (app
, pincb
, pincb_arg
);
461 rc
= iso7816_compute_ds (app
->slot
, data
, 35, outdata
, outdatalen
);
468 /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
469 If a PIN is required the PINCB will be used to ask for the PIN; it
470 should return the PIN in an allocated buffer and put it into PIN. */
472 do_decipher (app_t app
, const char *keyidstr
,
473 gpg_error_t (*pincb
)(void*, const char *, char **),
475 const void *indata
, size_t indatalen
,
476 unsigned char **outdata
, size_t *outdatalen
)
478 static const unsigned char mse_parm
[] = {
479 0x80, 1, 0x10, /* Select algorithm RSA. */
480 0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
485 if (!keyidstr
|| !*keyidstr
|| !indatalen
)
486 return gpg_error (GPG_ERR_INV_VALUE
);
488 /* Check that the provided ID is valid. This is not really needed
489 but we do it to to enforce correct usage by the caller. */
490 if (strncmp (keyidstr
, "NKS-DF01.", 9) )
491 return gpg_error (GPG_ERR_INV_ID
);
493 if (!hexdigitp (keyidstr
) || !hexdigitp (keyidstr
+1)
494 || !hexdigitp (keyidstr
+2) || !hexdigitp (keyidstr
+3)
496 return gpg_error (GPG_ERR_INV_ID
);
497 fid
= xtoi_4 (keyidstr
);
498 for (i
=0; filelist
[i
].fid
; i
++)
499 if (filelist
[i
].iskeypair
&& filelist
[i
].fid
== fid
)
501 if (!filelist
[i
].fid
)
502 return gpg_error (GPG_ERR_NOT_FOUND
);
503 if (!filelist
[i
].isenckey
)
504 return gpg_error (GPG_ERR_INV_ID
);
506 /* Do the TCOS specific MSE. */
507 rc
= iso7816_manage_security_env (app
->slot
,
509 mse_parm
, sizeof mse_parm
);
511 rc
= verify_pin (app
, pincb
, pincb_arg
);
513 rc
= iso7816_decipher (app
->slot
, indata
, indatalen
, 0x81,
514 outdata
, outdatalen
);
519 /* Handle the PASSWD command. CHVNOSTR is currently ignored; we
520 always use VHV0. RESET_MODE is not yet implemented. */
522 do_change_pin (app_t app
, ctrl_t ctrl
, const char *chvnostr
,
524 gpg_error_t (*pincb
)(void*, const char *, char **),
535 if ((flags
& APP_CHANGE_FLAG_RESET
))
536 return gpg_error (GPG_ERR_NOT_IMPLEMENTED
);
538 if ((flags
& APP_CHANGE_FLAG_NULLPIN
))
540 /* With the nullpin flag, we do not verify the PIN - it would fail
541 if the Nullpin is still set. */
542 oldpin
= "\0\0\0\0\0";
547 err
= verify_pin (app
, pincb
, pincb_arg
);
554 /* TRANSLATORS: Do not translate the "|*|" prefixes but
555 keep it at the start of the string. We need this elsewhere
556 to get some infos on the string. */
557 err
= pincb (pincb_arg
, _("|N|New PIN"), &pinvalue
);
560 log_error (_("error getting new PIN: %s\n"), gpg_strerror (err
));
564 err
= iso7816_change_reference_data (app
->slot
, 0x00,
566 pinvalue
, strlen (pinvalue
));
572 /* Perform a simple verify operation. KEYIDSTR should be NULL or empty. */
574 do_check_pin (app_t app
, const char *keyidstr
,
575 gpg_error_t (*pincb
)(void*, const char *, char **),
579 return verify_pin (app
, pincb
, pincb_arg
);
583 /* Select the NKS 2.0 application. */
585 app_select_nks (app_t app
)
587 static char const aid
[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
588 int slot
= app
->slot
;
591 rc
= iso7816_select_application (slot
, aid
, sizeof aid
, 0);
594 app
->apptype
= "NKS";
596 app
->fnc
.learn_status
= do_learn_status
;
597 app
->fnc
.readcert
= do_readcert
;
598 app
->fnc
.getattr
= NULL
;
599 app
->fnc
.setattr
= NULL
;
600 app
->fnc
.genkey
= NULL
;
601 app
->fnc
.sign
= do_sign
;
602 app
->fnc
.auth
= NULL
;
603 app
->fnc
.decipher
= do_decipher
;
604 app
->fnc
.change_pin
= do_change_pin
;
605 app
->fnc
.check_pin
= do_check_pin
;