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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
32
#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
for (i=0; i < 20; i++)
112
sprintf (r_gripstr+i*2, "%02X", grip[i]);
114
gcry_sexp_release (sexp);
121
do_learn_status (APP app, CTRL ctrl)
124
char ct_buf[100], id_buf[100];
127
/* Output information about all useful objects. */
128
for (i=0; filelist[i].fid; i++)
130
if (filelist[i].certtype)
134
len = app_help_read_length_of_cert (app->slot,
135
filelist[i].fid, NULL);
138
/* FIXME: We should store the length in the application's
139
context so that a following readcert does only need to
140
read that many bytes. */
141
sprintf (ct_buf, "%d", filelist[i].certtype);
142
sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
143
send_status_info (ctrl, "CERTINFO",
144
ct_buf, strlen (ct_buf),
145
id_buf, strlen (id_buf),
149
else if (filelist[i].iskeypair)
153
err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
155
log_error ("can't get keygrip from FID 0x%04X: %s\n",
156
filelist[i].fid, gpg_strerror (err));
159
sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
160
send_status_info (ctrl, "KEYPAIRINFO",
162
id_buf, strlen (id_buf),
174
/* Read the certificate with id CERTID (as returned by learn_status in
175
the CERTINFO status lines) and return it in the freshly allocated
176
buffer put into CERT and the length of the certificate put into
179
do_readcert (app_t app, const char *certid,
180
unsigned char **cert, size_t *certlen)
184
unsigned char *buffer;
185
const unsigned char *p;
187
int class, tag, constructed, ndef;
188
size_t totobjlen, objlen, hdrlen;
193
if (strncmp (certid, "NKS-DF01.", 9) )
194
return gpg_error (GPG_ERR_INV_ID);
196
if (!hexdigitp (certid) || !hexdigitp (certid+1)
197
|| !hexdigitp (certid+2) || !hexdigitp (certid+3)
199
return gpg_error (GPG_ERR_INV_ID);
200
fid = xtoi_4 (certid);
201
for (i=0; filelist[i].fid; i++)
202
if ((filelist[i].certtype || filelist[i].iskeypair)
203
&& filelist[i].fid == fid)
205
if (!filelist[i].fid)
206
return gpg_error (GPG_ERR_NOT_FOUND);
208
/* If the requested objects is a plain public key, redirect it to
209
the corresponding certificate. The whole system is a bit messy
210
becuase we sometime use the key directly or let the caller
211
retrieve the key from the certificate. The valid point behind
212
that is to support not-yet stored certificates. */
213
if (filelist[i].iskeypair)
214
fid = filelist[i].iskeypair;
217
/* Read the entire file. fixme: This could be optimized by first
218
reading the header to figure out how long the certificate
220
err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
223
log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
227
err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
230
log_error ("error reading certificate from FID 0x%04X: %s\n",
231
fid, gpg_strerror (err));
235
if (!buflen || *buffer == 0xff)
237
log_info ("no certificate contained in FID 0x%04X\n", fid);
238
err = gpg_error (GPG_ERR_NOT_FOUND);
242
/* Now figure something out about the object. */
245
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
246
&ndef, &objlen, &hdrlen);
249
if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
251
else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
254
return gpg_error (GPG_ERR_INV_OBJ);
255
totobjlen = objlen + hdrlen;
256
assert (totobjlen <= buflen);
258
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
259
&ndef, &objlen, &hdrlen);
265
else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
267
const unsigned char *save_p;
269
/* The certificate seems to be contained in a userCertificate
270
container. Skip this and assume the following sequence is
274
err = gpg_error (GPG_ERR_INV_OBJ);
280
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
281
&ndef, &objlen, &hdrlen);
284
if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) )
285
return gpg_error (GPG_ERR_INV_OBJ);
286
totobjlen = objlen + hdrlen;
287
assert (save_p + totobjlen <= buffer + buflen);
288
memmove (buffer, save_p, totobjlen);
293
*certlen = totobjlen;
301
/* Verify the PIN if required. */
303
verify_pin (app_t app,
304
int (pincb)(void*, const char *, char **),
307
/* Note that force_chv1 is never set but we do it here anyway so
308
that other applications may euse this function. For example it
309
makes sense to set force_chv1 for German signature law cards.
310
NKS is very similar to the DINSIG draft standard. */
311
if (!app->did_chv1 || app->force_chv1 )
316
rc = pincb (pincb_arg, "PIN", &pinvalue);
319
log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
323
/* The follwoing limits are due to TCOS but also defined in the
325
if (strlen (pinvalue) < 6)
327
log_error ("PIN is too short; minimum length is 6\n");
329
return gpg_error (GPG_ERR_BAD_PIN);
331
else if (strlen (pinvalue) > 16)
333
log_error ("PIN is too large; maximum length is 16\n");
335
return gpg_error (GPG_ERR_BAD_PIN);
338
/* Also it is possible to use a local PIN, we use the gloabl
339
PIN for this application. */
340
rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
343
log_error ("verify PIN failed\n");
356
/* Create the signature and return the allocated result in OUTDATA.
357
If a PIN is required the PINCB will be used to ask for the PIN;
358
that callback should return the PIN in an allocated buffer and
359
store that in the 3rd argument. */
361
do_sign (app_t app, const char *keyidstr, int hashalgo,
362
int (pincb)(void*, const char *, char **),
364
const void *indata, size_t indatalen,
365
unsigned char **outdata, size_t *outdatalen )
367
static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
368
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
369
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
370
static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
371
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
372
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
375
unsigned char data[35]; /* Must be large enough for a SHA-1 digest
376
+ the largest OID _prefix above. */
378
if (!keyidstr || !*keyidstr)
379
return gpg_error (GPG_ERR_INV_VALUE);
380
if (indatalen != 20 && indatalen != 16 && indatalen != 35)
381
return gpg_error (GPG_ERR_INV_VALUE);
383
/* Check that the provided ID is vaid. This is not really needed
384
but we do it to to enforce correct usage by the caller. */
385
if (strncmp (keyidstr, "NKS-DF01.", 9) )
386
return gpg_error (GPG_ERR_INV_ID);
388
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
389
|| !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
391
return gpg_error (GPG_ERR_INV_ID);
392
fid = xtoi_4 (keyidstr);
393
for (i=0; filelist[i].fid; i++)
394
if (filelist[i].iskeypair && filelist[i].fid == fid)
396
if (!filelist[i].fid)
397
return gpg_error (GPG_ERR_NOT_FOUND);
398
if (!filelist[i].issignkey)
399
return gpg_error (GPG_ERR_INV_ID);
401
/* Prepare the DER object from INDATA. */
404
/* Alright, the caller was so kind to send us an already
405
prepared DER object. Check that it is waht we want and that
406
it matches the hash algorithm. */
407
if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
409
else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
412
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
413
memcpy (data, indata, indatalen);
417
if (hashalgo == GCRY_MD_SHA1)
418
memcpy (data, sha1_prefix, 15);
419
else if (hashalgo == GCRY_MD_RMD160)
420
memcpy (data, rmd160_prefix, 15);
422
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
423
memcpy (data+15, indata, indatalen);
426
rc = verify_pin (app, pincb, pincb_arg);
428
rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
435
/* Decrypt the data in INDATA and return the allocated result in OUTDATA.
436
If a PIN is required the PINCB will be used to ask for the PIN; it
437
should return the PIN in an allocated buffer and put it into PIN. */
439
do_decipher (app_t app, const char *keyidstr,
440
int (pincb)(void*, const char *, char **),
442
const void *indata, size_t indatalen,
443
unsigned char **outdata, size_t *outdatalen )
445
static const unsigned char mse_parm[] = {
446
0x80, 1, 0x10, /* Select algorithm RSA. */
447
0x84, 1, 0x81 /* Select locak secret key 1 for descryption. */
452
if (!keyidstr || !*keyidstr || !indatalen)
453
return gpg_error (GPG_ERR_INV_VALUE);
455
/* Check that the provided ID is vaid. This is not really needed
456
but we do it to to enforce correct usage by the caller. */
457
if (strncmp (keyidstr, "NKS-DF01.", 9) )
458
return gpg_error (GPG_ERR_INV_ID);
460
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
461
|| !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
463
return gpg_error (GPG_ERR_INV_ID);
464
fid = xtoi_4 (keyidstr);
465
for (i=0; filelist[i].fid; i++)
466
if (filelist[i].iskeypair && filelist[i].fid == fid)
468
if (!filelist[i].fid)
469
return gpg_error (GPG_ERR_NOT_FOUND);
470
if (!filelist[i].isenckey)
471
return gpg_error (GPG_ERR_INV_ID);
473
/* Do the TCOS specific MSE. */
474
rc = iso7816_manage_security_env (app->slot,
476
mse_parm, sizeof mse_parm);
478
rc = verify_pin (app, pincb, pincb_arg);
480
rc = iso7816_decipher (app->slot, indata, indatalen, 0x81,
481
outdata, outdatalen);
487
/* Select the NKS 2.0 application on the card in SLOT. */
489
app_select_nks (APP app)
491
static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
492
int slot = app->slot;
495
rc = iso7816_select_application (slot, aid, sizeof aid);
498
app->apptype = "NKS";
500
app->fnc.learn_status = do_learn_status;
501
app->fnc.readcert = do_readcert;
502
app->fnc.getattr = NULL;
503
app->fnc.setattr = NULL;
504
app->fnc.genkey = NULL;
505
app->fnc.sign = do_sign;
506
app->fnc.auth = NULL;
507
app->fnc.decipher = do_decipher;
508
app->fnc.change_pin = NULL;
509
app->fnc.check_pin = NULL;