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,
33 #include "app-common.h"
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. */
43 { 0x4531, 0, 0xC000, 1, 0 },
48 { 0x45B1, 0, 0xC200, 0, 1 },
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. */
60 keygripstr_from_pk_file (int slot
, int fid
, char *r_gripstr
)
63 unsigned char grip
[20];
64 unsigned char *buffer
[2];
69 err
= iso7816_select_file (slot
, fid
, 0, NULL
, NULL
);
72 err
= iso7816_read_record (slot
, 1, 1, 0, &buffer
[0], &buflen
[0]);
75 err
= iso7816_read_record (slot
, 2, 1, 0, &buffer
[1], &buflen
[1]);
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. */
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
);
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);
105 if (!gcry_pk_get_keygrip (sexp
, grip
))
107 err
= gpg_error (GPG_ERR_INTERNAL
); /* i.e. RSA not supported by
112 for (i
=0; i
< 20; i
++)
113 sprintf (r_gripstr
+i
*2, "%02X", grip
[i
]);
115 gcry_sexp_release (sexp
);
122 do_learn_status (app_t app
, ctrl_t ctrl
)
125 char ct_buf
[100], id_buf
[100];
128 /* Output information about all useful objects. */
129 for (i
=0; filelist
[i
].fid
; i
++)
131 if (filelist
[i
].certtype
)
135 len
= app_help_read_length_of_cert (app
->slot
,
136 filelist
[i
].fid
, NULL
);
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
),
150 else if (filelist
[i
].iskeypair
)
154 err
= keygripstr_from_pk_file (app
->slot
, filelist
[i
].fid
, gripstr
);
156 log_error ("can't get keygrip from FID 0x%04X: %s\n",
157 filelist
[i
].fid
, gpg_strerror (err
));
160 sprintf (id_buf
, "NKS-DF01.%04X", filelist
[i
].fid
);
161 send_status_info (ctrl
, "KEYPAIRINFO",
163 id_buf
, strlen (id_buf
),
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
180 do_readcert (app_t app
, const char *certid
,
181 unsigned char **cert
, size_t *certlen
)
185 unsigned char *buffer
;
186 const unsigned char *p
;
188 int class, tag
, constructed
, ndef
;
189 size_t totobjlen
, objlen
, hdrlen
;
194 if (strncmp (certid
, "NKS-DF01.", 9) )
195 return gpg_error (GPG_ERR_INV_ID
);
197 if (!hexdigitp (certid
) || !hexdigitp (certid
+1)
198 || !hexdigitp (certid
+2) || !hexdigitp (certid
+3)
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
)
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
221 err
= iso7816_select_file (app
->slot
, fid
, 0, NULL
, NULL
);
224 log_error ("error selecting FID 0x%04X: %s\n", fid
, gpg_strerror (err
));
228 err
= iso7816_read_binary (app
->slot
, 0, 0, &buffer
, &buflen
);
231 log_error ("error reading certificate from FID 0x%04X: %s\n",
232 fid
, gpg_strerror (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
);
243 /* Now figure something out about the object. */
246 err
= parse_ber_header (&p
, &n
, &class, &tag
, &constructed
,
247 &ndef
, &objlen
, &hdrlen
);
250 if ( class == CLASS_UNIVERSAL
&& tag
== TAG_SEQUENCE
&& constructed
)
252 else if ( class == CLASS_UNIVERSAL
&& tag
== TAG_SET
&& constructed
)
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
);
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
275 err
= gpg_error (GPG_ERR_INV_OBJ
);
281 err
= parse_ber_header (&p
, &n
, &class, &tag
, &constructed
,
282 &ndef
, &objlen
, &hdrlen
);
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
);
294 *certlen
= totobjlen
;
302 /* Verify the PIN if required. */
304 verify_pin (app_t app
,
305 gpg_error_t (*pincb
)(void*, const char *, char **),
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
)
317 rc
= pincb (pincb_arg
, "PIN", &pinvalue
);
320 log_info ("PIN callback returned error: %s\n", gpg_strerror (rc
));
324 /* The following limits are due to TCOS but also defined in the
326 if (strlen (pinvalue
) < 6)
328 log_error ("PIN is too short; minimum length is 6\n");
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");
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
));
344 if ( gpg_error (rc
) == GPG_ERR_USE_CONDITIONS
)
345 log_error (_("the NullPIN has not yet been changed\n"));
347 log_error ("verify PIN failed\n");
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. */
365 do_sign (app_t app
, const char *keyidstr
, int hashalgo
,
366 gpg_error_t (*pincb
)(void*, const char *, char **),
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 };
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
);
392 if (!hexdigitp (keyidstr
) || !hexdigitp (keyidstr
+1)
393 || !hexdigitp (keyidstr
+2) || !hexdigitp (keyidstr
+3)
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
)
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. */
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))
416 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
417 memcpy (data
, indata
, indatalen
);
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);
426 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
427 memcpy (data
+15, indata
, indatalen
);
430 rc
= verify_pin (app
, pincb
, pincb_arg
);
432 rc
= iso7816_compute_ds (app
->slot
, data
, 35, outdata
, outdatalen
);
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. */
443 do_decipher (app_t app
, const char *keyidstr
,
444 gpg_error_t (*pincb
)(void*, const char *, char **),
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. */
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
);
464 if (!hexdigitp (keyidstr
) || !hexdigitp (keyidstr
+1)
465 || !hexdigitp (keyidstr
+2) || !hexdigitp (keyidstr
+3)
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
)
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
,
480 mse_parm
, sizeof mse_parm
);
482 rc
= verify_pin (app
, pincb
, pincb_arg
);
484 rc
= iso7816_decipher (app
->slot
, indata
, indatalen
, 0x81,
485 outdata
, outdatalen
);
491 /* Select the NKS 2.0 application on the card in SLOT. */
493 app_select_nks (app_t app
)
495 static char const aid
[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
496 int slot
= app
->slot
;
499 rc
= iso7816_select_application (slot
, aid
, sizeof aid
, 0);
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
;