~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to scd/app-nks.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* app-nks.c - The Telesec NKS 2.0 card application.
 
2
 *      Copyright (C) 2004 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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <errno.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <assert.h>
 
27
#include <time.h>
 
28
 
 
29
#include "scdaemon.h"
 
30
 
 
31
#include "iso7816.h"
 
32
#include "app-common.h"
 
33
#include "tlv.h"
 
34
 
 
35
static struct {
 
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. */
 
41
} filelist[] = {
 
42
  { 0x4531, 0,  0xC000, 1, 0 }, 
 
43
  { 0xC000, 101 },
 
44
  { 0x4331, 100 },
 
45
  { 0x4332, 100 },
 
46
  { 0xB000, 110 },
 
47
  { 0x45B1, 0,  0xC200, 0, 1 },
 
48
  { 0xC200, 101 },
 
49
  { 0x43B1, 100 },
 
50
  { 0x43B2, 100 },
 
51
  { 0, 0 }
 
52
};
 
53
 
 
54
 
 
55
 
 
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. */
 
58
static gpg_error_t
 
59
keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
 
60
{
 
61
  gpg_error_t err;
 
62
  unsigned char grip[20];
 
63
  unsigned char *buffer[2];
 
64
  size_t buflen[2];
 
65
  gcry_sexp_t sexp;
 
66
  int i;
 
67
  
 
68
  err = iso7816_select_file (slot, fid, 0, NULL, NULL);
 
69
  if (err)
 
70
    return err;
 
71
  err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]);
 
72
  if (err)
 
73
    return err;
 
74
  err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]);
 
75
  if (err)
 
76
    {
 
77
      xfree (buffer[0]);
 
78
      return err;
 
79
    }
 
80
  
 
81
  for (i=0; i < 2; i++)
 
82
    {
 
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. */
 
87
      if (buflen[i] < 3)
 
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);
 
91
    }
 
92
 
 
93
  if (!err)
 
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);
 
98
 
 
99
  xfree (buffer[0]);
 
100
  xfree (buffer[1]);
 
101
  if (err)
 
102
    return err;
 
103
 
 
104
  if (!gcry_pk_get_keygrip (sexp, grip))
 
105
    {
 
106
      err = gpg_error (GPG_ERR_INTERNAL); /* i.e. RSA not supported by
 
107
                                             libgcrypt. */
 
108
    }
 
109
  else
 
110
    {
 
111
      for (i=0; i < 20; i++)
 
112
        sprintf (r_gripstr+i*2, "%02X", grip[i]);
 
113
    }
 
114
  gcry_sexp_release (sexp);
 
115
  return err;
 
116
}
 
117
 
 
118
 
 
119
 
 
120
static int
 
121
do_learn_status (APP app, CTRL ctrl)
 
122
{
 
123
  gpg_error_t err;
 
124
  char ct_buf[100], id_buf[100];
 
125
  int i;
 
126
 
 
127
  /* Output information about all useful objects. */
 
128
  for (i=0; filelist[i].fid; i++)
 
129
    {
 
130
      if (filelist[i].certtype)
 
131
        {
 
132
          size_t len;
 
133
 
 
134
          len = app_help_read_length_of_cert (app->slot,
 
135
                                              filelist[i].fid, NULL);
 
136
          if (len)
 
137
            {
 
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), 
 
146
                                NULL, (size_t)0);
 
147
            }
 
148
        }
 
149
      else if (filelist[i].iskeypair)
 
150
        {
 
151
          char gripstr[40+1];
 
152
 
 
153
          err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
 
154
          if (err)
 
155
            log_error ("can't get keygrip from FID 0x%04X: %s\n",
 
156
                       filelist[i].fid, gpg_strerror (err));
 
157
          else
 
158
            {
 
159
              sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
 
160
              send_status_info (ctrl, "KEYPAIRINFO",
 
161
                                gripstr, 40, 
 
162
                                id_buf, strlen (id_buf), 
 
163
                                NULL, (size_t)0);
 
164
            }
 
165
        }
 
166
    }
 
167
 
 
168
  return 0;
 
169
}
 
170
 
 
171
 
 
172
 
 
173
 
 
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
 
177
   CERTLEN. */
 
178
static int
 
179
do_readcert (app_t app, const char *certid,
 
180
             unsigned char **cert, size_t *certlen)
 
181
{
 
182
  int i, fid;
 
183
  gpg_error_t err;
 
184
  unsigned char *buffer;
 
185
  const unsigned char *p;
 
186
  size_t buflen, n;
 
187
  int class, tag, constructed, ndef;
 
188
  size_t totobjlen, objlen, hdrlen;
 
189
  int rootca = 0;
 
190
 
 
191
  *cert = NULL;
 
192
  *certlen = 0;
 
193
  if (strncmp (certid, "NKS-DF01.", 9) ) 
 
194
    return gpg_error (GPG_ERR_INV_ID);
 
195
  certid += 9;
 
196
  if (!hexdigitp (certid) || !hexdigitp (certid+1)
 
197
      || !hexdigitp (certid+2) || !hexdigitp (certid+3) 
 
198
      || certid[4])
 
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)
 
204
      break;
 
205
  if (!filelist[i].fid)
 
206
    return gpg_error (GPG_ERR_NOT_FOUND);
 
207
 
 
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;
 
215
 
 
216
 
 
217
  /* Read the entire file.  fixme: This could be optimized by first
 
218
     reading the header to figure out how long the certificate
 
219
     actually is. */
 
220
  err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
 
221
  if (err)
 
222
    {
 
223
      log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
 
224
      return err;
 
225
    }
 
226
 
 
227
  err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
 
228
  if (err)
 
229
    {
 
230
      log_error ("error reading certificate from FID 0x%04X: %s\n",
 
231
                 fid, gpg_strerror (err));
 
232
      return err;
 
233
    }
 
234
  
 
235
  if (!buflen || *buffer == 0xff)
 
236
    {
 
237
      log_info ("no certificate contained in FID 0x%04X\n", fid);
 
238
      err = gpg_error (GPG_ERR_NOT_FOUND);
 
239
      goto leave;
 
240
    }
 
241
 
 
242
  /* Now figure something out about the object. */
 
243
  p = buffer;
 
244
  n = buflen;
 
245
  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
 
246
                          &ndef, &objlen, &hdrlen);
 
247
  if (err)
 
248
    goto leave;
 
249
  if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
 
250
    ;
 
251
  else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
 
252
    rootca = 1;
 
253
  else
 
254
    return gpg_error (GPG_ERR_INV_OBJ);
 
255
  totobjlen = objlen + hdrlen;
 
256
  assert (totobjlen <= buflen);
 
257
 
 
258
  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
 
259
                          &ndef, &objlen, &hdrlen);
 
260
  if (err)
 
261
    goto leave;
 
262
  
 
263
  if (rootca)
 
264
    ;
 
265
  else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
 
266
    {
 
267
      const unsigned char *save_p;
 
268
  
 
269
      /* The certificate seems to be contained in a userCertificate
 
270
         container.  Skip this and assume the following sequence is
 
271
         the certificate. */
 
272
      if (n < objlen)
 
273
        {
 
274
          err = gpg_error (GPG_ERR_INV_OBJ);
 
275
          goto leave;
 
276
        }
 
277
      p += objlen;
 
278
      n -= objlen;
 
279
      save_p = p;
 
280
      err = parse_ber_header (&p, &n, &class, &tag, &constructed,
 
281
                              &ndef, &objlen, &hdrlen);
 
282
      if (err) 
 
283
        goto leave;
 
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);
 
289
    }
 
290
  
 
291
  *cert = buffer;
 
292
  buffer = NULL;
 
293
  *certlen = totobjlen;
 
294
 
 
295
 leave:
 
296
  xfree (buffer);
 
297
  return err;
 
298
}
 
299
 
 
300
 
 
301
/* Verify the PIN if required.  */
 
302
static int
 
303
verify_pin (app_t app,
 
304
            int (pincb)(void*, const char *, char **),
 
305
            void *pincb_arg)
 
306
{
 
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 ) 
 
312
    {
 
313
      char *pinvalue;
 
314
      int rc;
 
315
 
 
316
      rc = pincb (pincb_arg, "PIN", &pinvalue); 
 
317
      if (rc)
 
318
        {
 
319
          log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
 
320
          return rc;
 
321
        }
 
322
 
 
323
      /* The follwoing limits are due to TCOS but also defined in the
 
324
         NKS specs. */
 
325
      if (strlen (pinvalue) < 6)
 
326
        {
 
327
          log_error ("PIN is too short; minimum length is 6\n");
 
328
          xfree (pinvalue);
 
329
          return gpg_error (GPG_ERR_BAD_PIN);
 
330
        }
 
331
      else if (strlen (pinvalue) > 16)
 
332
        {
 
333
          log_error ("PIN is too large; maximum length is 16\n");
 
334
          xfree (pinvalue);
 
335
          return gpg_error (GPG_ERR_BAD_PIN);
 
336
        }
 
337
 
 
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));
 
341
      if (rc)
 
342
        {
 
343
          log_error ("verify PIN failed\n");
 
344
          xfree (pinvalue);
 
345
          return rc;
 
346
        }
 
347
      app->did_chv1 = 1;
 
348
      xfree (pinvalue);
 
349
    }
 
350
 
 
351
  return 0;
 
352
}
 
353
 
 
354
 
 
355
 
 
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.  */
 
360
static int 
 
361
do_sign (app_t app, const char *keyidstr, int hashalgo,
 
362
         int (pincb)(void*, const char *, char **),
 
363
           void *pincb_arg,
 
364
           const void *indata, size_t indatalen,
 
365
           unsigned char **outdata, size_t *outdatalen )
 
366
{
 
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 };
 
373
  int rc, i;
 
374
  int fid;
 
375
  unsigned char data[35];   /* Must be large enough for a SHA-1 digest
 
376
                               + the largest OID _prefix above. */
 
377
 
 
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);
 
382
 
 
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);
 
387
  keyidstr += 9;
 
388
  if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
 
389
      || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3) 
 
390
      || keyidstr[4])
 
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)
 
395
      break;
 
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);
 
400
 
 
401
  /* Prepare the DER object from INDATA. */
 
402
  if (indatalen == 35)
 
403
    {
 
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))
 
408
        ;
 
409
      else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
 
410
        ;
 
411
      else 
 
412
        return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
 
413
      memcpy (data, indata, indatalen);
 
414
    }
 
415
  else
 
416
    {
 
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);
 
421
      else 
 
422
        return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
 
423
      memcpy (data+15, indata, indatalen);
 
424
    }
 
425
 
 
426
  rc = verify_pin (app, pincb, pincb_arg);
 
427
  if (!rc)
 
428
    rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
 
429
  return rc;
 
430
}
 
431
 
 
432
 
 
433
 
 
434
 
 
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.  */
 
438
static int 
 
439
do_decipher (app_t app, const char *keyidstr,
 
440
             int (pincb)(void*, const char *, char **),
 
441
             void *pincb_arg,
 
442
             const void *indata, size_t indatalen,
 
443
             unsigned char **outdata, size_t *outdatalen )
 
444
{
 
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. */
 
448
  };
 
449
  int rc, i;
 
450
  int fid;
 
451
 
 
452
  if (!keyidstr || !*keyidstr || !indatalen)
 
453
    return gpg_error (GPG_ERR_INV_VALUE);
 
454
 
 
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);
 
459
  keyidstr += 9;
 
460
  if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
 
461
      || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3) 
 
462
      || keyidstr[4])
 
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)
 
467
      break;
 
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);
 
472
 
 
473
  /* Do the TCOS specific MSE. */
 
474
  rc = iso7816_manage_security_env (app->slot, 
 
475
                                    0xC1, 0xB8,
 
476
                                    mse_parm, sizeof mse_parm);
 
477
  if (!rc)
 
478
    rc = verify_pin (app, pincb, pincb_arg);
 
479
  if (!rc)
 
480
    rc = iso7816_decipher (app->slot, indata, indatalen, 0x81,
 
481
                           outdata, outdatalen);
 
482
  return rc;
 
483
}
 
484
 
 
485
 
 
486
 
 
487
/* Select the NKS 2.0 application on the card in SLOT.  */
 
488
int
 
489
app_select_nks (APP app)
 
490
{
 
491
  static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
 
492
  int slot = app->slot;
 
493
  int rc;
 
494
  
 
495
  rc = iso7816_select_application (slot, aid, sizeof aid);
 
496
  if (!rc)
 
497
    {
 
498
      app->apptype = "NKS";
 
499
 
 
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;
 
510
   }
 
511
 
 
512
  return rc;
 
513
}
 
514
 
 
515