root/trunk/src/libopensc/card-jcop.c

Revision 3177, 29.5 KB (checked in by aj, 18 months ago)

fix compiler/sparse warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * card-jcop.c
3 *
4 * Copyright (C) 2003 Chaskiel Grundman <cg2v@andrew.cmu.edu>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include "internal.h"
22#include "cardctl.h"
23#include <string.h>
24#include <stdlib.h>
25
26static struct sc_atr_table jcop_atrs[] = {
27        { "3B:E6:00:FF:81:31:FE:45:4A:43:4F:50:33:31:06", NULL, NULL, SC_CARD_TYPE_JCOP_GENERIC, 0, NULL },
28#if 0
29        /* Requires secure messaging */
30        { "3B:E6:00:FF:81:31:FE:45:4A:43:4F:50:32:31:06", NULL, NULL, SC_CARD_TYPE_JCOP_GENERIC, 0, NULL },
31#endif
32        { NULL, NULL, NULL, 0, 0, NULL }
33};
34
35static struct sc_card_operations jcop_ops;
36static struct sc_card_driver jcop_drv = {
37        "JCOP cards with BlueZ PKCS#15 applet",
38        "jcop",
39        &jcop_ops,
40        NULL, 0, NULL
41};
42
43#define SELECT_MF 0
44#define SELECT_EFDIR 1
45#define SELECT_APPDF 2
46#define SELECT_EF 3
47#define SELECT_UNKNOWN 4
48#define SELECTING_TARGET 0xf
49#define SELECTING_ABS 0x80
50#define SELECTING_VIA_APPDF 0x100
51
52struct jcop_private_data
53{
54     sc_file_t *virtmf;
55     sc_file_t *virtdir;
56     sc_path_t aid;
57     int selected;
58     int invalid_senv;
59     int nfiles;
60     u8 *filelist;
61};
62#define DRVDATA(card)   ((struct jcop_private_data *) ((card)->drv_data))
63
64static int jcop_finish(sc_card_t *card)
65{
66     struct jcop_private_data *drvdata=DRVDATA(card);
67     if (drvdata) {
68          sc_file_free(drvdata->virtmf);
69          sc_file_free(drvdata->virtdir);
70          free(drvdata);
71          card->drv_data=NULL;
72     }
73     
74     return 0;
75}
76
77static int jcop_match_card(sc_card_t *card)
78{
79        int i;
80
81        i = _sc_match_atr(card, jcop_atrs, &card->type);
82        if (i < 0)
83                return 0;
84        return 1;
85}
86
87static unsigned char ef_dir_contents[128] = {
88     0x61, 0x21,
89     0x4f, 0xc, 0xA0, 0x0, 0x0, 0x0, 0x63, 'P', 'K', 'C', 'S', '-', '1', '5',
90     0x50, 0xb, 'O', 'p', 'e', 'n', 'S', 'C', ' ', 'C', 'a', 'r', 'd',
91     0x51, 0x04, 0x3f, 0x00, 0x50, 0x15
92};
93
94
95static int jcop_init(sc_card_t *card)
96{
97     struct jcop_private_data *drvdata;
98     sc_file_t *f;
99     int flags;
100     
101     drvdata=(struct jcop_private_data *) malloc(sizeof(struct jcop_private_data));
102     if (!drvdata)
103          return SC_ERROR_OUT_OF_MEMORY;
104     memset(drvdata, 0, sizeof(struct jcop_private_data));
105     
106     sc_format_path("A000:0000:6350:4B43:532D:3135", &drvdata->aid);
107     drvdata->aid.type = SC_PATH_TYPE_DF_NAME;
108     drvdata->selected=SELECT_MF;
109     drvdata->invalid_senv=1;
110     drvdata->nfiles=-1;
111     drvdata->filelist=NULL;
112     f=sc_file_new();
113     if (!f){
114          free(drvdata);
115          return SC_ERROR_OUT_OF_MEMORY;
116     }
117     
118     sc_format_path("3f00", &f->path);
119     f->type=SC_FILE_TYPE_DF;
120     f->shareable=0;
121     f->ef_structure=SC_FILE_EF_UNKNOWN;
122     f->size=0;
123     f->id=0x3f00;
124     f->status=SC_FILE_STATUS_ACTIVATED;
125     sc_file_add_acl_entry(f, SC_AC_OP_SELECT, SC_AC_NONE, 0);
126     sc_file_add_acl_entry(f, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0);
127     sc_file_add_acl_entry(f, SC_AC_OP_LOCK, SC_AC_NEVER, 0);
128     sc_file_add_acl_entry(f, SC_AC_OP_DELETE, SC_AC_NEVER, 0);
129     sc_file_add_acl_entry(f, SC_AC_OP_CREATE, SC_AC_NEVER, 0);
130
131     drvdata->virtmf=f;
132
133     f=sc_file_new();
134     if (!f){
135          sc_file_free(drvdata->virtmf);
136          free(drvdata);
137          return SC_ERROR_OUT_OF_MEMORY;
138     }
139     
140     sc_format_path("3f002f00", &f->path);
141     f->type=SC_FILE_TYPE_WORKING_EF;
142     f->shareable=0;
143     f->ef_structure=SC_FILE_EF_TRANSPARENT;
144     f->size=128;
145     f->id=0x2f00;
146     f->status=SC_FILE_STATUS_ACTIVATED;
147     sc_file_add_acl_entry(f, SC_AC_OP_READ, SC_AC_NONE, 0);
148     sc_file_add_acl_entry(f, SC_AC_OP_LOCK, SC_AC_NEVER, 0);
149     sc_file_add_acl_entry(f, SC_AC_OP_ERASE, SC_AC_NEVER, 0);
150     sc_file_add_acl_entry(f, SC_AC_OP_UPDATE, SC_AC_NEVER, 0);
151     sc_file_add_acl_entry(f, SC_AC_OP_WRITE, SC_AC_NEVER, 0);
152     sc_file_add_acl_entry(f, SC_AC_OP_CRYPTO, SC_AC_NEVER, 0);
153     
154     drvdata->virtdir=f;
155     
156     
157     card->drv_data = drvdata;
158     card->cla = 0x00;
159
160     /* card supports host-side padding, but not raw rsa */
161     flags = SC_ALGORITHM_RSA_PAD_PKCS1;
162     flags |= SC_ALGORITHM_RSA_HASH_NONE;
163     flags |= SC_ALGORITHM_RSA_HASH_SHA1;
164     flags |= SC_ALGORITHM_RSA_HASH_MD5;
165     /* only supports keygen with 3 and F-4  exponents */
166     flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
167     _sc_card_add_rsa_alg(card, 512, flags, 0);
168     _sc_card_add_rsa_alg(card, 768, flags, 0);
169     _sc_card_add_rsa_alg(card, 1024, flags, 0);
170     _sc_card_add_rsa_alg(card, 2048, flags, 0);
171     /* State that we have an RNG */
172     card->caps |= SC_CARD_CAP_RNG;
173
174     return 0;
175}
176
177static int jcop_get_default_key(sc_card_t *card,
178                                struct sc_cardctl_default_key *data)
179{
180        const char *key;
181
182        if (data->method != SC_AC_PRO || data->key_ref > 2)
183                return SC_ERROR_NO_DEFAULT_KEY;
184
185        key = "40:41:42:43:44:45:46:47:48:49:4A:4B:4C:4D:4E:4F";
186        return sc_hex_to_bin(key, data->key_data, &data->len);
187}
188
189/* since the card is actually a javacard, we're expected to use ISO
190   7816-4 direct application selection instead of reading the DIR
191   ourselves and selecting the AppDF by path. Since opensc doesn' do
192   that, I fake an MF containing the AppDF and a fixed DIR pointing at
193   the fake AppDF. This has the added advantage of allowing
194   opensc-explorer to be used with this driver */
195static int jcop_select_file(sc_card_t *card, const sc_path_t *path,
196                            sc_file_t **file)
197{
198     struct jcop_private_data *drvdata=DRVDATA(card);
199     int r,selecting;
200     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
201     const struct sc_card_operations *iso_ops = iso_drv->ops;
202     sc_path_t       shortpath;
203     sc_file_t  *tfile, **fileptr;
204     
205     if (!drvdata)
206          return SC_ERROR_FILE_NOT_FOUND;
207
208     /* Something about the card does not like Case 4 APDU's to be sent as
209        Case 3. you must send a length and accept a response. */
210       
211     if (file) {
212          fileptr=file;
213     } else {
214          fileptr=&tfile;
215     }
216
217     /* Selecting the MF. return a copy of the constructed MF */
218     if (path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0) {
219          drvdata->selected=SELECT_MF;
220          if (file) {
221                sc_file_dup(file, drvdata->virtmf);
222                if (*file == NULL)
223                        return SC_ERROR_OUT_OF_MEMORY;
224          }
225          return 0;
226     }
227     /* Selecting the EF(DIR). return a copy of the constructed EF(DIR) */
228     if ((path->len == 4 &&
229          memcmp(path->value, "\x3F\x00\x2F\x00", 4) == 0) ||
230         (drvdata->selected == SELECT_MF && path->len == 2 &&
231          memcmp(path->value, "\x2F\x00", 2) == 0)) {
232          drvdata->selected=SELECT_EFDIR;
233          if (file) {
234                sc_file_dup(file, drvdata->virtdir);
235                if (*file == NULL)
236                        return SC_ERROR_OUT_OF_MEMORY;
237          }
238          return 0;
239     }   
240     /* selecting the PKCS15 AppDF or a file in it. Select the applet, then
241        pass through any remaining path components to the applet's select
242        command
243     */
244     selecting=SELECT_UNKNOWN;
245     
246     if (path->len >= 4 &&
247         memcmp(path->value, "\x3F\x00\x50\x15", 4) == 0) {
248          if (path->len == 4)
249               selecting = SELECTING_ABS | SELECT_APPDF;
250          else
251               selecting = SELECTING_ABS | SELECT_EF;
252     }
253     
254     if  (drvdata->selected==SELECT_MF &&
255          memcmp(path->value, "\x50\x15", 2) == 0) {
256          if (path->len == 2)
257               selecting = SELECTING_VIA_APPDF | SELECT_APPDF;
258          else
259               selecting = SELECTING_VIA_APPDF | SELECT_EF;
260     }
261   
262     if (selecting & (SELECTING_ABS|SELECTING_VIA_APPDF))
263     {
264          if (file == NULL &&
265              (selecting & SELECTING_TARGET) == SELECT_APPDF  &&
266              drvdata->selected == SELECT_APPDF) {
267               return 0;
268          }
269          if ((r = iso_ops->select_file(card, &drvdata->aid, fileptr)) < 0)
270               return r;
271          if ((selecting & SELECTING_TARGET) == SELECT_APPDF) {
272               (*fileptr)->type = SC_FILE_TYPE_DF;
273               drvdata->selected=SELECT_APPDF;
274               goto select_ok;
275          }
276          sc_file_free(*fileptr);
277          *fileptr=NULL;
278          memset(&shortpath, 0, sizeof(sc_path_t));       
279          if (selecting & SELECTING_ABS) {
280               memcpy(&shortpath.value, &path->value[4], path->len-4);
281               shortpath.len=path->len-4;
282          } else {
283               memcpy(&shortpath.value, &path->value[2], path->len-2);
284               shortpath.len=path->len-2;
285          }
286          shortpath.type = shortpath.len == 2 ? SC_PATH_TYPE_FILE_ID :
287               path->type;
288          shortpath.index=path->index;
289          shortpath.count=path->count;
290          path=&shortpath;
291     } else {
292          /* There seems to be better debugging output if I call sc_check_sw
293           * with appropriate input than if I just return the appropriate
294           * SC_ERROR_*, so that's what I do for all errors returned by code
295           * related to the MF/DIR emulation
296           */
297          if (drvdata->selected == SELECT_MF ||
298              drvdata->selected == SELECT_EFDIR)
299               return sc_check_sw(card, 0x6A, 0x82);
300     }
301       
302     r = iso_ops->select_file(card, path, fileptr);
303     if (r)
304          return r;
305     drvdata->selected=SELECT_EF;
306 select_ok:
307     if (!file) {
308          sc_file_free(*fileptr);
309     }
310     return 0;
311}
312
313static int jcop_read_binary(sc_card_t *card, unsigned int idx,
314                            u8 * buf, size_t count, unsigned long flags) {
315     struct jcop_private_data *drvdata=DRVDATA(card);
316     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
317     const struct sc_card_operations *iso_ops = iso_drv->ops;
318     sc_file_t  *tfile;
319     int r;
320     
321     if (drvdata->selected == SELECT_MF) {
322          return sc_check_sw(card, 0x69, 0x86);
323     }
324     if (drvdata->selected == SELECT_EFDIR) {
325          if (idx > 127) {
326               return sc_check_sw(card, 0x6A, 0x86);
327          }
328          if (idx + count > 128) {
329               count=128-idx;
330          }
331          sc_ctx_suppress_errors_on(card->ctx);
332          r = iso_ops->select_file(card, &drvdata->aid, &tfile);
333          sc_ctx_suppress_errors_off(card->ctx);
334          if (r < 0) { /* no pkcs15 app, so return empty DIR. */
335               memset(buf, 0, count);
336          } else {
337               sc_file_free(tfile);
338               memcpy(buf, (u8 *)(ef_dir_contents + idx), count);
339          }
340          return count;
341     }
342     return iso_ops->read_binary(card, idx, buf, count, flags);
343}
344
345static int jcop_list_files(sc_card_t *card, u8 *buf, size_t buflen) {
346     struct jcop_private_data *drvdata=DRVDATA(card);
347     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
348     const struct sc_card_operations *iso_ops = iso_drv->ops;
349     sc_file_t  *tfile;
350     int r;
351
352     if (drvdata->selected == SELECT_MF) {
353          if (buflen < 2)
354               return 0;
355          memcpy(buf, "\x2f\x00", 2);
356          if (buflen < 4)
357               return 2;
358          /* AppDF only exists if applet is selectable */
359          sc_ctx_suppress_errors_on(card->ctx);
360          r = iso_ops->select_file(card, &drvdata->aid, &tfile);
361          sc_ctx_suppress_errors_off(card->ctx);
362          if (r < 0) {
363               return 2;
364          } else {
365               sc_file_free(tfile);
366               memcpy(buf+2, "\x50\x15", 2);
367               return 4;
368          }
369     }
370     
371     if (drvdata->nfiles == -1)
372          return SC_ERROR_NOT_ALLOWED;
373     if (drvdata->nfiles == 0)
374          return 0;
375     if (buflen > 2 * (size_t)drvdata->nfiles)
376          buflen=2*drvdata->nfiles;
377     memcpy(buf, drvdata->filelist, buflen);
378     return buflen;
379}
380
381static int sa_to_acl(sc_file_t *file, unsigned int operation,
382                     int nibble) {
383     switch (nibble & 0x7) {
384     case 0:
385          sc_file_add_acl_entry(file, operation, SC_AC_NONE, SC_AC_KEY_REF_NONE);
386          break;
387     case 1:
388          sc_file_add_acl_entry(file, operation, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
389          break;
390     case 2:
391          sc_file_add_acl_entry(file, operation, SC_AC_CHV, 1);
392          break;
393     case 3:
394          sc_file_add_acl_entry(file, operation, SC_AC_CHV, 2);
395          break;
396     case 4:
397          sc_file_add_acl_entry(file, operation, SC_AC_CHV, 3);
398          break;
399     case 5:
400          sc_file_add_acl_entry(file, operation, SC_AC_AUT, SC_AC_KEY_REF_NONE);
401          break;
402     case 6:
403          sc_file_add_acl_entry(file, operation, SC_AC_PRO, SC_AC_KEY_REF_NONE);
404          break;
405     default:
406          sc_file_add_acl_entry(file, operation, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);
407     }
408     return 0;
409}
410
411
412static int jcop_process_fci(sc_card_t *card, sc_file_t *file,
413                            const u8 *buf, size_t buflen) {
414     struct jcop_private_data *drvdata=DRVDATA(card);
415     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
416     const struct sc_card_operations *iso_ops = iso_drv->ops;
417     u8 *sa;
418     int r;
419
420     /* the FCI for EF's includes a bogus length for the overall structure!  */
421     if (buflen == 19)
422       buflen=24;
423     r=iso_ops->process_fci(card, file, buf, buflen);
424     
425     if (r < 0)
426          return r;
427     if (file->type != SC_FILE_TYPE_DF) {
428          if (drvdata->nfiles) {
429               drvdata->nfiles=-1;
430               free(drvdata->filelist);
431               drvdata->filelist=NULL;
432          }
433          if(file->sec_attr_len >=3) {
434               /* The security attribute bytes are divided into nibbles and are
435                  as follows:
436                  READ | MODIFY || SIGN | ENCIPHER || DECIPHER | DELETE
437               */
438               sa=file->sec_attr;
439               sa_to_acl(file, SC_AC_OP_READ, sa[0] >> 4);
440               sa_to_acl(file, SC_AC_OP_UPDATE, sa[0] & 0xf);
441               /* Files may be locked by anyone who can MODIFY. */
442               /* opensc seems to think LOCK ACs are only on DFs */
443               /* sa_to_acl(file, SC_AC_OP_LOCK, sa[0] & 0xf); */
444               /* there are seperate SIGN, ENCIPHER, and DECIPHER ACs.
445                  I use SIGN for SC_AC_OP_CRYPTO unless it is NEVER, in
446                  which case I use DECIPHER */
447               if ((sa[1] & 0xf0) == 0x10)
448                    sa_to_acl(file, SC_AC_OP_CRYPTO, sa[1] >> 4);
449               else
450                    sa_to_acl(file, SC_AC_OP_CRYPTO, sa[2] >> 4);
451               sa_to_acl(file, SC_AC_OP_ERASE, sa[2] & 0xf);
452          }
453     } else {
454          /* No AC information is reported for the AppDF */
455          sc_file_add_acl_entry(file, SC_AC_OP_SELECT, SC_AC_NONE, 0);
456          sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, 3);
457          sc_file_add_acl_entry(file, SC_AC_OP_DELETE, SC_AC_NONE, 0);
458          sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0);
459          if (drvdata->nfiles) {
460               drvdata->nfiles=0;
461               free(drvdata->filelist);
462               drvdata->filelist=NULL;
463          }   
464          /* the format of the poprietary attributes is:
465             4 bytes     unique id
466             1 byte      # files in DF
467             2 bytes     1st File ID
468             2 bytes     2nd File ID
469             ...
470          */
471          if (file->prop_attr_len > 4) {
472               int nfiles;
473               u8 *filelist;
474               nfiles=file->prop_attr[4];
475               if (nfiles) {
476                    filelist=(u8 *) malloc(2*nfiles);
477                    if (!filelist)
478                         return SC_ERROR_OUT_OF_MEMORY;
479                    memcpy(filelist, &file->prop_attr[5], 2*nfiles);
480                    drvdata->nfiles=nfiles;
481                    drvdata->filelist=filelist;
482               }
483          }
484     }
485     
486     return r;
487}
488static int acl_to_ac_nibble(const sc_acl_entry_t *e)
489{
490        if (e == NULL)
491                return -1;
492        if (e->next != NULL)    /* FIXME */
493                return -1;
494        switch (e->method) {
495        case SC_AC_NONE:
496                return 0x00;
497        case SC_AC_NEVER:
498                return 0x01;
499        case SC_AC_CHV:
500                switch (e->key_ref) {
501                case 1:
502                        return 0x02;
503                case 2:
504                        return 0x03;
505                case 3:
506                        return 0x04;
507                }
508                return -1;
509        case SC_AC_AUT:
510                return 0x05;
511        case SC_AC_PRO:
512                return 0x06;
513        }
514        return -1;
515}
516
517
518static int jcop_create_file(sc_card_t *card, sc_file_t *file) {
519     struct jcop_private_data *drvdata=DRVDATA(card);
520     unsigned char sec_attr_data[3];
521     int ops[6];
522     int i, r;
523     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
524     const struct sc_card_operations *iso_ops = iso_drv->ops;
525     
526     if (drvdata->selected == SELECT_MF || drvdata->selected == SELECT_EFDIR )
527          return sc_check_sw(card, 0x69, 0x82);
528     
529     /* Can't create DFs */
530     if (file->type != SC_FILE_TYPE_WORKING_EF)
531          return sc_check_sw(card, 0x6A, 0x80);
532     
533     ops[0] = SC_AC_OP_READ;      /* read */
534     ops[1] = SC_AC_OP_UPDATE;    /* modify */
535     ops[2] = SC_AC_OP_CRYPTO;    /* sign */
536     ops[3] = -1;                 /* encipher */
537     ops[4] = SC_AC_OP_CRYPTO;    /* decipher */
538     ops[5] = SC_AC_OP_ERASE;     /* delete */
539     memset(sec_attr_data, 0, 3);
540     for (i = 0; i < 6; i++) {
541          const sc_acl_entry_t *entry;
542          if (ops[i] == -1) {
543               sec_attr_data[i/2] |= 1 << ((i % 2) ? 0 : 4);
544               continue;
545          }
546         
547          entry = sc_file_get_acl_entry(file, ops[i]);
548          r = acl_to_ac_nibble(entry);
549          sec_attr_data[i/2] |= r << ((i % 2) ? 0 : 4);
550     }
551
552     sc_file_set_sec_attr(file, sec_attr_data, 3);
553     
554     r=iso_ops->create_file(card, file);
555     if (r > 0)
556          drvdata->selected=SELECT_EF;
557     return r;
558}
559
560/* no record oriented file services */
561static int jcop_read_record_unsupp(sc_card_t *card,
562                               unsigned int rec_nr, u8 *buf,
563                              size_t count, unsigned long flags) {
564     return SC_ERROR_NOT_SUPPORTED;
565}
566
567static int jcop_wrupd_record_unsupp(sc_card_t *card,
568                               unsigned int rec_nr, const u8 *buf,
569                              size_t count, unsigned long flags) {
570     return SC_ERROR_NOT_SUPPORTED;
571}
572
573static int jcop_append_record_unsupp(sc_card_t *card,
574                                 const u8 *buf, size_t count,
575                                 unsigned long flags) {
576     return SC_ERROR_NOT_SUPPORTED;
577}
578
579
580/* We need to trap these functions so that proper errors can be returned
581   when one of the virtual files is selected */
582static int jcop_write_binary(sc_card_t *card,
583                        unsigned int idx, const u8 *buf,
584                        size_t count, unsigned long flags) {
585     struct jcop_private_data *drvdata=DRVDATA(card);
586     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
587     const struct sc_card_operations *iso_ops = iso_drv->ops;
588
589     if (drvdata->selected == SELECT_MF)
590               return sc_check_sw(card, 0x6A, 0x86);
591     if (drvdata->selected == SELECT_EFDIR)
592               return sc_check_sw(card, 0x69, 0x82);
593
594     return iso_ops->write_binary(card, idx, buf, count, flags);
595}
596
597
598static int jcop_update_binary(sc_card_t *card,
599                         unsigned int idx, const u8 *buf,
600                         size_t count, unsigned long flags) {
601     
602     struct jcop_private_data *drvdata=DRVDATA(card);
603     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
604     const struct sc_card_operations *iso_ops = iso_drv->ops;
605     if (drvdata->selected == SELECT_MF)
606               return sc_check_sw(card, 0x69, 0x86);
607     if (drvdata->selected == SELECT_EFDIR)
608               return sc_check_sw(card, 0x69, 0x82);
609
610     return iso_ops->update_binary(card, idx, buf, count, flags);
611}
612
613static int jcop_delete_file(sc_card_t *card, const sc_path_t *path) {
614     struct jcop_private_data *drvdata=DRVDATA(card);
615     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
616     const struct sc_card_operations *iso_ops = iso_drv->ops;
617
618     if (drvdata->selected == SELECT_MF || drvdata->selected == SELECT_EFDIR )
619          return sc_check_sw(card, 0x69, 0x82);
620
621     return iso_ops->delete_file(card, path);
622}
623
624
625/* BlueZ doesn't support stored security environments. you have
626   to construct one with SET every time */
627static int jcop_set_security_env(sc_card_t *card,
628                                    const sc_security_env_t *env,
629                                    int se_num)
630{
631        sc_apdu_t apdu;
632        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
633        u8 *p;
634        int r;
635        struct jcop_private_data *drvdata=DRVDATA(card);
636
637        assert(card != NULL && env != NULL);
638        if (se_num)
639             SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
640        if (drvdata->selected == SELECT_MF ||
641            drvdata->selected == SELECT_EFDIR) {
642             drvdata->invalid_senv=1;
643             return 0;
644        }
645       
646        if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
647                sc_security_env_t tmp;
648
649                tmp = *env;
650                tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
651                tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
652                if (tmp.algorithm != SC_ALGORITHM_RSA) {
653                        sc_error(card->ctx, "Only RSA algorithm supported.\n");
654                        return SC_ERROR_NOT_SUPPORTED;
655                }
656                if (!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)){
657                        sc_error(card->ctx, "Card requires RSA padding\n");
658                        return SC_ERROR_NOT_SUPPORTED;
659                }
660                tmp.algorithm_ref = 0x02;
661                /* potential FIXME: return an error, if an unsupported
662                 * pad or hash was requested, although this shouldn't happen.
663                 */
664                if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
665                        tmp.algorithm_ref |= 0x10;
666                if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
667                        tmp.algorithm_ref |= 0x20;
668                env=&tmp;
669        }
670       
671        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0);
672        switch (env->operation) {
673        case SC_SEC_OPERATION_DECIPHER:
674             apdu.p2 = 0xB8;
675             break;
676        case SC_SEC_OPERATION_SIGN:
677             apdu.p2 = 0xB6;
678             break;
679        default:
680             return SC_ERROR_INVALID_ARGUMENTS;
681        }
682        apdu.le = 0;
683        if (!env->flags & SC_SEC_ENV_ALG_REF_PRESENT)
684             return SC_ERROR_INVALID_ARGUMENTS;
685        if (!env->flags & SC_SEC_ENV_FILE_REF_PRESENT)
686             return SC_ERROR_INVALID_ARGUMENTS;
687        if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
688             if (env->key_ref_len > 1 || env->key_ref[0] != 0)
689                  return SC_ERROR_INVALID_ARGUMENTS;
690        }
691
692        p = sbuf;
693        *p++ = 0x80;    /* algorithm reference */
694        *p++ = 0x01;
695        *p++ = env->algorithm_ref & 0xFF;
696
697        *p++ = 0x81;
698        *p++ = env->file_ref.len;
699        memcpy(p, env->file_ref.value, env->file_ref.len);
700        p += env->file_ref.len;
701
702        r = p - sbuf;
703        apdu.lc = r;
704        apdu.datalen = r;
705        apdu.data = sbuf;
706        apdu.resplen = 0;
707        r = sc_transmit_apdu(card, &apdu);
708        if (r) {
709             sc_perror(card->ctx, r, "APDU transmit failed");
710             return r;
711        }
712        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
713        if (r) {
714             sc_perror(card->ctx, r, "Card returned error");
715             return r;
716        }
717        drvdata->invalid_senv=0;
718        return 0;
719}
720static int jcop_compute_signature(sc_card_t *card,
721                                  const u8 * data, size_t datalen,
722                                  u8 * out, size_t outlen) {
723
724
725       int r;
726        sc_apdu_t apdu;
727        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
728        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
729        struct jcop_private_data *drvdata=DRVDATA(card);
730
731        assert(card != NULL && data != NULL && out != NULL);
732        if (datalen > 256)
733                SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
734
735        if (drvdata->invalid_senv)
736             return sc_check_sw(card, 0x69, 0x88);
737
738        /* INS: 0x2A  PERFORM SECURITY OPERATION
739         * P1:  0x9E  Resp: Digital Signature
740         * P2:  0x9A  Cmd: Input for Digital Signature */
741        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E,
742                       0x9A);
743        apdu.resp = rbuf;
744        apdu.resplen = sizeof(rbuf); /* FIXME */
745        apdu.le = 256;
746        if (datalen == 256) {
747             apdu.p2 = data[0];
748             memcpy(sbuf, data+1, datalen-1);
749             apdu.lc = datalen - 1;
750             apdu.datalen = datalen - 1;
751        } else {
752             memcpy(sbuf, data, datalen);
753             apdu.lc = datalen;
754             apdu.datalen = datalen;
755        }
756
757        apdu.data = sbuf;
758        apdu.sensitive = 1;
759        r = sc_transmit_apdu(card, &apdu);
760        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
761        if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
762                int len = apdu.resplen > outlen ? outlen : apdu.resplen;
763
764                memcpy(out, apdu.resp, len);
765                SC_FUNC_RETURN(card->ctx, 4, len);
766        }
767        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
768}
769 
770
771
772static int jcop_decipher(sc_card_t *card,
773                         const u8 * crgram, size_t crgram_len,
774                         u8 * out, size_t outlen) {
775
776        int r;
777        sc_apdu_t apdu;
778        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
779        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
780        struct jcop_private_data *drvdata=DRVDATA(card);
781
782        assert(card != NULL && crgram != NULL && out != NULL);
783        SC_FUNC_CALLED(card->ctx, 2);
784        if (crgram_len > 256)
785                SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
786        if (drvdata->invalid_senv)
787             return sc_check_sw(card, 0x69, 0x88);
788
789        /* INS: 0x2A  PERFORM SECURITY OPERATION
790         * P1:  0x80  Resp: Plain value
791         * P2:  0x86  Cmd: Padding indicator byte followed by cryptogram */
792        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
793        apdu.resp = rbuf;
794        apdu.resplen = sizeof(rbuf); /* FIXME */
795        apdu.le = crgram_len;
796        apdu.sensitive = 1;
797       
798        if (crgram_len == 256) {
799             apdu.p2 = crgram[0];
800             memcpy(sbuf, crgram+1, crgram_len-1);
801             apdu.lc = crgram_len - 1;
802             apdu.datalen = crgram_len -1;
803        } else {
804             sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
805             memcpy(sbuf + 1, crgram, crgram_len);
806             apdu.lc = crgram_len + 1;
807             apdu.datalen = crgram_len + 1;
808        }
809       
810        apdu.data = sbuf;
811        r = sc_transmit_apdu(card, &apdu);
812        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
813        if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
814                int len = apdu.resplen > outlen ? outlen : apdu.resplen;
815
816                memcpy(out, apdu.resp, len);
817                SC_FUNC_RETURN(card->ctx, 2, len);
818        }
819        SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
820}
821 
822static int jcop_generate_key(sc_card_t *card, struct sc_cardctl_jcop_genkey *a) {
823     int modlen;
824     int r;
825     sc_apdu_t apdu;
826     u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
827     u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
828     u8 *p;
829     int is_f4;
830     struct jcop_private_data *drvdata=DRVDATA(card);
831
832     if (drvdata->selected == SELECT_MF || drvdata->selected == SELECT_EFDIR )
833          return sc_check_sw(card, 0x6A, 0x82);
834
835     is_f4=0;
836     
837     if (a->exponent == 0x10001) {
838          is_f4=1;
839     } else if (a->exponent != 3) {
840          sc_perror(card->ctx, SC_ERROR_NOT_SUPPORTED, "Invalid exponent");
841          return SC_ERROR_NOT_SUPPORTED;
842     }
843     
844     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0xB6);
845
846     p = sbuf;
847     *p++ = 0x80;    /* algorithm reference */
848     *p++ = 0x01;
849     *p++ = is_f4 ? 0x6E : 0x6D;
850     
851     *p++ = 0x81;
852     *p++ = a->pub_file_ref.len;
853     memcpy(p, a->pub_file_ref.value, a->pub_file_ref.len);
854     p += a->pub_file_ref.len;
855     
856     *p++ = 0x81;
857     *p++ = a->pri_file_ref.len;
858     memcpy(p, a->pri_file_ref.value, a->pri_file_ref.len);
859     p += a->pri_file_ref.len;
860     
861     r = p - sbuf;
862
863     apdu.lc = r;
864     apdu.datalen = r;
865     apdu.data = sbuf;
866     apdu.resplen = 0;
867     r = sc_transmit_apdu(card, &apdu);
868     if (r) {
869          sc_perror(card->ctx, r, "APDU transmit failed");
870          return r;
871     }
872     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
873     if (r) {
874          sc_perror(card->ctx, r, "Card returned error");
875          return r;
876     }
877
878     sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x46, 0, 0);
879
880     apdu.le = 256;
881     apdu.resp=rbuf;
882     apdu.resplen = sizeof(rbuf);
883     
884     r = sc_transmit_apdu(card, &apdu);
885     if (r) {
886          sc_perror(card->ctx, r, "APDU transmit failed");
887          return r;
888     }
889     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
890     if (r) {
891          sc_perror(card->ctx, r, "Card returned error");
892          return r;
893     }
894
895     if (rbuf[0] != 0x4) {
896          return SC_ERROR_INVALID_DATA;
897     }
898     modlen=rbuf[1] * 32;
899     if (a->pubkey_len < rbuf[1])
900          return SC_ERROR_BUFFER_TOO_SMALL;
901     a->pubkey_len=rbuf[1] * 4;
902     memcpy(a->pubkey, &rbuf[2], a->pubkey_len);
903     
904     return 0;
905}
906
907static int jcop_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
908{
909        switch (cmd) {
910        case SC_CARDCTL_GET_DEFAULT_KEY:
911                return jcop_get_default_key(card,
912                                (struct sc_cardctl_default_key *) ptr);
913        case SC_CARDCTL_JCOP_LOCK:
914             /* XXX implement me */
915             return SC_ERROR_NOT_SUPPORTED;
916        case SC_CARDCTL_JCOP_GENERATE_KEY:
917                return jcop_generate_key(card,
918                                (struct sc_cardctl_jcop_genkey *) ptr);
919        }
920
921        return SC_ERROR_NOT_SUPPORTED;
922}
923
924/* "The PINs are "global" in a PKCS#15 sense, meaning that they remain valid
925 *  until card reset! Selecting another applet doesn't invalidate the PINs,
926 *  you need to reset the card." - javacard@zurich.ibm.com, when asked about
927 *  how to invalidate logged in pins.
928 */
929
930static struct sc_card_driver * sc_get_driver(void)
931{
932     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
933
934     jcop_ops = *iso_drv->ops;
935     jcop_ops.match_card = jcop_match_card;
936     jcop_ops.init = jcop_init;
937     jcop_ops.finish = jcop_finish;
938     jcop_ops.read_binary = jcop_read_binary;
939     jcop_ops.read_record = jcop_read_record_unsupp;
940     jcop_ops.write_record = jcop_wrupd_record_unsupp;
941     jcop_ops.append_record = jcop_append_record_unsupp;
942     jcop_ops.update_record = jcop_wrupd_record_unsupp;
943     jcop_ops.write_binary = jcop_write_binary;
944     jcop_ops.update_binary = jcop_update_binary;
945     jcop_ops.select_file = jcop_select_file;
946     jcop_ops.create_file = jcop_create_file;
947     jcop_ops.delete_file = jcop_delete_file;
948     jcop_ops.list_files = jcop_list_files;
949     jcop_ops.set_security_env = jcop_set_security_env;
950     jcop_ops.compute_signature = jcop_compute_signature;
951     jcop_ops.decipher = jcop_decipher;
952     jcop_ops.process_fci = jcop_process_fci;
953     jcop_ops.card_ctl = jcop_card_ctl;
954     
955     return &jcop_drv;
956}
957
958#if 1
959struct sc_card_driver * sc_get_jcop_driver(void)
960{
961     return sc_get_driver();
962}
963#endif
Note: See TracBrowser for help on using the browser.