1 /*
2 * card-westcos.c: support for westcos card
3 *
4 * Copyright (C) 2009 francois.leblanc@cev-sa.com
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 #if HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <assert.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 #include "internal.h"
31 #include "asn1.h"
32 #include "cardctl.h"
33
34 #ifdef ENABLE_OPENSSL
35 #include <openssl/des.h>
36 #include <openssl/rsa.h>
37 #include <openssl/evp.h>
38 #include <openssl/pem.h>
39 #include <openssl/err.h>
40 #include <openssl/bio.h>
41 #endif
42
43 #ifndef min
44 #define min(a,b) (((a)<(b))?(a):(b))
45 #endif
46
47 #define DEFAULT_TRANSPORT_KEY "6f:59:b0:ed:6e:62:46:4a:5d:25:37:68:23:a8:a2:2d"
48
49 #define JAVACARD (0x01) /* westcos applet on javacard */
50 #define RSA_CRYPTO_COMPONENT (0x02) /* card component can do crypto */
51
52 #define WESTCOS_RSA_NO_HASH_NO_PAD (0x20)
53 #define WESTCOS_RSA_NO_HASH_PAD_PKCS1 (0x21)
54
55 #ifdef ENABLE_OPENSSL
56 #define DEBUG_SSL
57 #ifdef DEBUG_SSL
print_openssl_error(void)58 static void print_openssl_error(void)
59 {
60 static int charge = 0;
61 long r;
62
63 if (!charge) {
64 ERR_load_crypto_strings();
65 charge = 1;
66 }
67 while ((r = ERR_get_error()) != 0)
68 fprintf(stderr, "%s\n", ERR_error_string(r, NULL));
69 }
70 #endif
71 #endif
72
73 typedef struct {
74 sc_security_env_t env;
75 sc_autkey_t default_key;
76 int flags;
77 int file_id;
78 } priv_data_t;
79
80 static const struct sc_card_operations *iso_ops = NULL;
81 static struct sc_card_operations westcos_ops;
82
83 static struct sc_card_driver westcos_drv = {
84 "WESTCOS compatible cards", "westcos", &westcos_ops, NULL, 0, NULL
85 };
86
westcos_get_default_key(sc_card_t * card,struct sc_cardctl_default_key * data)87 static int westcos_get_default_key(sc_card_t * card,
88 struct sc_cardctl_default_key *data)
89 {
90 const char *default_key;
91 sc_log(card->ctx,
92 "westcos_get_default_key:data->method=%d, data->key_ref=%d\n",
93 data->method, data->key_ref);
94 if (data->method != SC_AC_AUT || data->key_ref != 0)
95 return SC_ERROR_NO_DEFAULT_KEY;
96 default_key =
97 scconf_get_str(card->ctx->conf_blocks[0], "westcos_default_key",
98 DEFAULT_TRANSPORT_KEY);
99 return sc_hex_to_bin(default_key, data->key_data, &data->len);
100 }
101
102 #define CRC_A 1
103 #define CRC_B 2
104
westcos_update_crc(unsigned char ch,unsigned short * lpwCrc)105 static unsigned short westcos_update_crc(unsigned char ch, unsigned short *lpwCrc)
106 {
107 ch = (ch ^ (unsigned char)((*lpwCrc) & 0x00FF));
108 ch = (ch ^ (ch << 4));
109 *lpwCrc =
110 (*lpwCrc >> 8) ^ ((unsigned short)ch << 8) ^ ((unsigned short)ch <<
111 3) ^ ((unsigned short)
112 ch >> 4);
113 return (*lpwCrc);
114 }
115
westcos_compute_aetb_crc(int CRCType,unsigned char * Data,size_t Length,unsigned char * TransmitFirst,unsigned char * TransmitSecond)116 static void westcos_compute_aetb_crc(int CRCType,
117 unsigned char *Data,
118 size_t Length,
119 unsigned char * TransmitFirst,
120 unsigned char * TransmitSecond)
121 {
122 unsigned char chBlock;
123 unsigned short wCrc;
124 switch (CRCType) {
125 case CRC_A:
126 wCrc = 0x6363; /* ITU-V.41 */
127 break;
128 case CRC_B:
129 wCrc = 0xFFFF; /* ISO 3309 */
130 break;
131 default:
132 return;
133 }
134
135 do {
136 chBlock = *Data++;
137 westcos_update_crc(chBlock, &wCrc);
138 } while (--Length);
139 if (CRCType == CRC_B)
140 wCrc = ~wCrc; /* ISO 3309 */
141 *TransmitFirst = (unsigned char) (wCrc & 0xFF);
142 *TransmitSecond = (unsigned char) ((wCrc >> 8) & 0xFF);
143 return;
144 }
145
westcos_check_sw(sc_card_t * card,unsigned int sw1,unsigned int sw2)146 static int westcos_check_sw(sc_card_t * card, unsigned int sw1,
147 unsigned int sw2)
148 {
149 if ((sw1 == 0x69) && (sw2 == 0x88))
150 return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
151 assert(iso_ops && iso_ops->check_sw);
152 return iso_ops->check_sw(card, sw1, sw2);
153 }
154
155 static const struct sc_atr_table westcos_atrs[] = {
156 /* westcos 2ko */
157 { "3F:69:00:00:00:64:01:00:00:00:80:90:00", "ff:ff:ff:ff:ff:ff:ff:00:00:00:f0:ff:ff", NULL, 0x00, 0, NULL },
158 /* westcos applet */
159 { "3B:95:94:80:1F:C3:80:73:C8:21:13:54", "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff", NULL, JAVACARD, 0, NULL },
160 { NULL, NULL, NULL, 0, 0, NULL }
161 };
162
westcos_finish(sc_card_t * card)163 static int westcos_finish(sc_card_t * card)
164 {
165 if (card->algorithms)
166 free(card->algorithms);
167 card->algorithms = NULL;
168 card->algorithm_count = 0;
169 if (card->drv_data)
170 free(card->drv_data);
171 return 0;
172 }
173
westcos_match_card(sc_card_t * card)174 static int westcos_match_card(sc_card_t * card)
175 {
176 int i;
177
178 i = _sc_match_atr(card, westcos_atrs, &card->type);
179 if (i < 0)
180 return 0;
181
182 /* JAVACARD, look for westcos applet */
183 if (i == 1) {
184 int r;
185 sc_apdu_t apdu;
186 u8 aid[] = {
187 0xA0, 0x00, 0xCE, 0x00, 0x07, 0x01
188 };
189 sc_format_apdu(card, &apdu,
190 SC_APDU_CASE_3_SHORT, 0xA4, 0x04,
191 0);
192 apdu.cla = 0x00;
193 apdu.lc = sizeof(aid);
194 apdu.datalen = sizeof(aid);
195 apdu.data = aid;
196 r = sc_transmit_apdu(card, &apdu);
197 if (r)
198 return 0;
199 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
200 if (r)
201 return 0;
202 }
203
204 return 1;
205 }
206
westcos_init(sc_card_t * card)207 static int westcos_init(sc_card_t * card)
208 {
209 int r;
210 const char *default_key;
211 unsigned long exponent, flags;
212 priv_data_t *priv_data;
213
214 if (card == NULL)
215 return SC_ERROR_INVALID_ARGUMENTS;
216
217 card->drv_data = malloc(sizeof(priv_data_t));
218 if (card->drv_data == NULL)
219 return SC_ERROR_OUT_OF_MEMORY;
220 memset(card->drv_data, 0, sizeof(priv_data_t));
221
222 priv_data = (priv_data_t *) card->drv_data;
223
224 default_key =
225 scconf_get_str(card->ctx->conf_blocks[0], "westcos_default_key",
226 DEFAULT_TRANSPORT_KEY);
227 if (default_key) {
228 priv_data = (priv_data_t *) (card->drv_data);
229 priv_data->default_key.key_reference = 0;
230 priv_data->default_key.key_len =
231 sizeof(priv_data->default_key.key_value);
232 r = sc_hex_to_bin(default_key, priv_data->default_key.key_value,
233 &(priv_data->default_key.key_len));
234 if (r) {
235 free (priv_data);
236 card->drv_data = NULL;
237 return (r);
238 }
239 }
240
241 if (card->type & JAVACARD) {
242 priv_data->flags |= JAVACARD;
243 }
244
245 /* check for crypto component */
246 if(card->atr.value[9] == 0xD0)
247 {
248 priv_data->flags |= RSA_CRYPTO_COMPONENT;
249 }
250
251 card->cla = 0x00;
252 card->max_send_size = 240;
253 card->max_recv_size = 240;
254 exponent = 0;
255 flags = SC_ALGORITHM_RSA_RAW;
256 flags |= SC_ALGORITHM_RSA_HASH_NONE;
257 flags |= SC_ALGORITHM_RSA_PAD_NONE | SC_ALGORITHM_RSA_PAD_PKCS1;
258 flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
259 _sc_card_add_rsa_alg(card, 128, flags, exponent);
260 _sc_card_add_rsa_alg(card, 256, flags, exponent);
261 _sc_card_add_rsa_alg(card, 512, flags, exponent);
262 _sc_card_add_rsa_alg(card, 768, flags, exponent);
263 _sc_card_add_rsa_alg(card, 1024, flags, exponent);
264 _sc_card_add_rsa_alg(card, 1100, flags, exponent);
265 _sc_card_add_rsa_alg(card, 1200, flags, exponent);
266 _sc_card_add_rsa_alg(card, 1300, flags, exponent);
267 _sc_card_add_rsa_alg(card, 1400, flags, exponent);
268 _sc_card_add_rsa_alg(card, 1536, flags, exponent);
269 _sc_card_add_rsa_alg(card, 2048, flags, exponent);
270 return 0;
271 }
272
westcos_select_file(sc_card_t * card,const sc_path_t * in_path,sc_file_t ** file_out)273 static int westcos_select_file(sc_card_t * card, const sc_path_t * in_path,
274 sc_file_t ** file_out)
275 {
276 priv_data_t *priv_data = (priv_data_t *) card->drv_data;
277
278 assert(iso_ops && iso_ops->select_file);
279 priv_data->file_id = 0;
280 return iso_ops->select_file(card, in_path, file_out);
281 }
282
_westcos2opensc_ac(u8 flag)283 static int _westcos2opensc_ac(u8 flag)
284 {
285 if (flag == 0)
286 return SC_AC_NEVER;
287 else if (flag == 1)
288 return SC_AC_CHV;
289 else if (flag == 2)
290 return SC_AC_AUT;
291 else if (flag == 15)
292 return SC_AC_NONE;
293 return SC_AC_UNKNOWN;
294 }
295
westcos_process_fci(sc_card_t * card,sc_file_t * file,const u8 * buf,size_t buflen)296 static int westcos_process_fci(sc_card_t * card, sc_file_t * file,
297 const u8 * buf, size_t buflen)
298 {
299 sc_context_t *ctx = card->ctx;
300 size_t taglen, len = buflen;
301 const u8 *tag = NULL, *p = buf;
302 sc_log(card->ctx, "processing FCI bytes\n");
303 tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
304 if (tag != NULL && taglen == 2) {
305 file->id = (tag[0] << 8) | tag[1];
306 sc_log(card->ctx,
307 " file identifier: 0x%02X%02X\n", tag[0], tag[1]);
308 }
309 tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
310 if (tag != NULL && taglen >= 2) {
311 int bytes = (tag[0] << 8) + tag[1];
312 sc_log(card->ctx,
313 " bytes in file: %d\n", bytes);
314 file->size = bytes;
315 }
316 if (tag == NULL) {
317 tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen);
318 if (tag != NULL && taglen >= 2) {
319 int bytes = (tag[0] << 8) + tag[1];
320 sc_log(card->ctx,
321 " bytes in file: %d\n", bytes);
322 file->size = bytes;
323 }
324 }
325 tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
326 if (tag != NULL) {
327 if (taglen > 0) {
328 unsigned char byte = tag[0];
329 const char *type;
330 file->shareable = 0;
331 sc_log(card->ctx,
332 " shareable: %s\n",
333 (file->shareable) ? "yes" : "no");
334 file->ef_structure = SC_FILE_EF_UNKNOWN;
335 switch (byte) {
336 case 0x38:
337 type = "DF";
338 file->type = SC_FILE_TYPE_DF;
339 break;
340 case 0x01:
341 type = "working or internal EF";
342 file->type = SC_FILE_TYPE_WORKING_EF;
343 file->ef_structure = SC_FILE_EF_TRANSPARENT;
344 break;
345 case 0x02:
346 type = "working or internal EF";
347 file->type = SC_FILE_TYPE_WORKING_EF;
348 file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
349 break;
350 case 0x06:
351 type = "working or internal EF";
352 file->type = SC_FILE_TYPE_WORKING_EF;
353 file->ef_structure = SC_FILE_EF_CYCLIC;
354 break;
355 default:
356 type = "unknown";
357 }
358 sc_log(card->ctx,
359 " type: %s\n", type);
360 sc_log(card->ctx,
361 " EF structure: %d\n", file->ef_structure);
362 }
363 }
364 tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
365 if (tag != NULL && taglen > 0 && taglen <= 16) {
366 memcpy(file->name, tag, taglen);
367 file->namelen = taglen;
368 sc_log_hex(card->ctx, " File name", file->name, file->namelen);
369 }
370 if (file->type == SC_FILE_TYPE_DF) {
371 tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
372 if (tag != NULL && taglen == 3) {
373 file->size = tag[1] * 256 + tag[2];
374 } else
375 file->size = 0;
376 }
377 tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen);
378 if (tag != NULL && taglen) {
379 sc_file_set_prop_attr(file, tag, taglen);
380 }
381 tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen);
382 if (tag != NULL && taglen) {
383 sc_file_set_sec_attr(file, tag, taglen);
384
385 /* FIXME: compact file system only */
386 if (file->type == SC_FILE_TYPE_DF) {
387 sc_file_add_acl_entry(file, SC_AC_OP_SELECT,
388 _westcos2opensc_ac(tag[0] >>
389 4),
390 tag[0 + 4] >> 4);
391 sc_file_add_acl_entry(file, SC_AC_OP_CREATE,
392 _westcos2opensc_ac(tag[0] &
393 0x0f),
394 tag[0 + 4] & 0x0f);
395 sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE,
396 _westcos2opensc_ac(tag[1] >>
397 4),
398 tag[1 + 4] >> 4);
399 }
400
401 else {
402 if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
403 sc_file_add_acl_entry(file, SC_AC_OP_READ,
404 _westcos2opensc_ac(tag[0]
405 >>
406 4),
407 tag[0 + 4] >> 4);
408 sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
409 _westcos2opensc_ac(tag[0]
410 &
411 0x0f),
412 tag[0 + 4] & 0x0f);
413 sc_file_add_acl_entry(file,
414 SC_AC_OP_INVALIDATE,
415 _westcos2opensc_ac(tag[1]
416 >>
417 4),
418 tag[1 + 4] >> 4);
419 sc_file_add_acl_entry(file, SC_AC_OP_ERASE,
420 _westcos2opensc_ac(tag[1]
421 &
422 0x0f),
423 tag[1 + 4] & 0x0f);
424 }
425
426 else {
427 sc_file_add_acl_entry(file, SC_AC_OP_READ,
428 _westcos2opensc_ac(tag[0]
429 >>
430 4),
431 tag[0 + 4] >> 4);
432 sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
433 _westcos2opensc_ac(tag[0]
434 &
435 0x0f),
436 tag[0 + 4] & 0x0f);
437 sc_file_add_acl_entry(file,
438 SC_AC_OP_INVALIDATE,
439 _westcos2opensc_ac(tag[1]
440 >>
441 4),
442 tag[1 + 4] >> 4);
443 }
444 }
445 }
446 return 0;
447 }
448
449 #define HIGH (0)
450 #define LOW (1)
_convertion_ac_methode(sc_file_t * file,int low,unsigned int operation,u8 * buf,u8 * buf_key)451 static int _convertion_ac_methode(sc_file_t * file, int low,
452 unsigned int operation, u8 * buf,
453 u8 * buf_key)
454 {
455 const struct sc_acl_entry *acl;
456 acl = sc_file_get_acl_entry(file, operation);
457 if (acl == NULL) {
458
459 /* per default always */
460 *buf = 0xff;
461 *buf_key = 0x00;
462 return 0;
463 }
464 switch (acl->method) {
465 case SC_AC_NONE:
466 if (low)
467 *buf |= 0x0f;
468
469 else
470 *buf |= 0xf0;
471 break;
472 case SC_AC_CHV: /* Card Holder Verif. */
473 if (low)
474 *buf |= 0x01;
475
476 else
477 *buf |= 0x10;
478 break;
479 case SC_AC_TERM: /* Terminal auth. */
480 return SC_ERROR_NOT_SUPPORTED;
481 case SC_AC_PRO: /* Secure Messaging */
482 return SC_ERROR_NOT_SUPPORTED;
483 case SC_AC_AUT: /* Key auth. */
484 if (low)
485 *buf |= 0x02;
486
487 else
488 *buf |= 0x20;
489 if (acl->key_ref > 15)
490 return SC_ERROR_NOT_SUPPORTED;
491 if (low)
492 *buf_key |= acl->key_ref;
493
494 else
495 *buf_key |= (acl->key_ref) << 4;
496 break;
497 case SC_AC_NEVER:
498 *buf |= 0;
499 break;
500 default:
501 return SC_ERROR_NOT_SUPPORTED;
502 }
503 return 0;
504 }
505
westcos_create_file(sc_card_t * card,struct sc_file * file)506 static int westcos_create_file(sc_card_t *card, struct sc_file *file)
507 {
508 int r;
509 sc_apdu_t apdu;
510 u8 buf[12], p1 = 0, p2 = 0;
511 int buflen;
512 if (card == NULL)
513 return SC_ERROR_INVALID_ARGUMENTS;
514 sc_log(card->ctx, "westcos_create_file\n");
515 memset(buf, 0, sizeof(buf));
516
517 /* transport key */
518 r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL);
519 if (r)
520 return (r);
521 buflen = sizeof(buf);
522 switch (file->type) {
523 case SC_FILE_TYPE_DF:
524 buf[0] = 0x00;
525 buf[1] = 0x01;
526 _convertion_ac_methode(file, HIGH, SC_AC_OP_SELECT, &buf[2],
527 &buf[2 + 4]);
528 _convertion_ac_methode(file, LOW, SC_AC_OP_CREATE, &buf[2],
529 &buf[2 + 4]);
530 _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE,
531 &buf[3], &buf[3 + 4]);
532 buflen = 10;
533 break;
534 case SC_FILE_TYPE_INTERNAL_EF:
535 buf[0] |= 0x80;
536 /* fall through */
537 case SC_FILE_TYPE_WORKING_EF:
538 switch (file->ef_structure) {
539 case SC_FILE_EF_TRANSPARENT:
540 buf[0] |= 0x20; /* no transaction support */
541 buf[1] |= 0;
542 _convertion_ac_methode(file, HIGH, SC_AC_OP_READ,
543 &buf[2], &buf[2 + 4]);
544 _convertion_ac_methode(file, LOW, SC_AC_OP_UPDATE,
545 &buf[2], &buf[2 + 4]);
546 _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE,
547 &buf[3], &buf[3 + 4]);
548 _convertion_ac_methode(file, LOW, SC_AC_OP_ERASE,
549 &buf[3], &buf[3 + 4]);
550 buf[10] = (u8) ((file->size) / 256);
551 buf[11] = (u8) ((file->size) % 256);
552 break;
553 case SC_FILE_EF_LINEAR_FIXED:
554 buf[0] |= 0x40; /* no transaction support */
555 buf[1] |= 0;
556 _convertion_ac_methode(file, HIGH, SC_AC_OP_READ,
557 &buf[2], &buf[2 + 4]);
558 _convertion_ac_methode(file, LOW, SC_AC_OP_UPDATE,
559 &buf[2], &buf[2 + 4]);
560 _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE,
561 &buf[3], &buf[3 + 4]);
562 buf[10] = file->record_count;
563 buf[11] = file->record_length;
564 break;
565 case SC_FILE_EF_CYCLIC:
566 buf[0] |= 0x60; /* no transaction support */
567 buf[1] |= 0;
568 _convertion_ac_methode(file, HIGH, SC_AC_OP_READ,
569 &buf[2], &buf[2 + 4]);
570 _convertion_ac_methode(file, LOW, SC_AC_OP_UPDATE,
571 &buf[2], &buf[2 + 4]);
572 _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE,
573 &buf[3], &buf[3 + 4]);
574 buf[10] = file->record_count;
575 buf[11] = file->record_length;
576 break;
577 case SC_FILE_EF_LINEAR_VARIABLE:
578 case SC_FILE_EF_UNKNOWN:
579 case SC_FILE_EF_LINEAR_FIXED_TLV:
580 case SC_FILE_EF_LINEAR_VARIABLE_TLV:
581 case SC_FILE_EF_CYCLIC_TLV:
582 default:
583 return SC_ERROR_NOT_SUPPORTED;
584 }
585 break;
586 default:
587 return SC_ERROR_NOT_SUPPORTED;
588 }
589 if (file->shareable)
590 buf[0] |= 0x08;
591 if (file->path.len >= 2) {
592 p1 = file->path.value[file->path.len - 2];
593 p2 = file->path.value[file->path.len - 1];
594 }
595
596 else if (file->id) {
597 p1 = (file->id) / 256;
598 p2 = (file->id) % 256;
599 }
600 sc_log(card->ctx,
601 "create file %s, id %X size %"SC_FORMAT_LEN_SIZE_T"u\n",
602 file->path.value, file->id, file->size);
603 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, p1, p2);
604 apdu.cla = 0x80;
605 apdu.lc = buflen;
606 apdu.datalen = buflen;
607 apdu.data = buf;
608 r = sc_transmit_apdu(card, &apdu);
609 if (r)
610 return (r);
611 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
612 return r;
613 }
614
westcos_delete_file(sc_card_t * card,const sc_path_t * path_in)615 static int westcos_delete_file(sc_card_t * card, const sc_path_t * path_in)
616 {
617 int r;
618 sc_apdu_t apdu;
619 if (card == NULL || path_in == NULL || path_in->len < 2)
620 return SC_ERROR_INVALID_ARGUMENTS;
621 sc_log(card->ctx, "westcos_delete_file\n");
622 if (path_in->len > 2) {
623 r = sc_select_file(card, path_in, NULL);
624 if (r)
625 return (r);
626 }
627 sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4,
628 path_in->value[path_in->len - 2],
629 path_in->value[path_in->len - 1]);
630 apdu.cla = 0x80;
631 r = sc_transmit_apdu(card, &apdu);
632 if (r)
633 return (r);
634 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
635 if (r)
636 return (r);
637 return 0;
638 }
639
westcos_list_files(sc_card_t * card,u8 * buf,size_t buflen)640 static int westcos_list_files(sc_card_t * card, u8 * buf, size_t buflen)
641 {
642 int r;
643 sc_apdu_t apdu;
644 if (card == NULL)
645 return SC_ERROR_INVALID_ARGUMENTS;
646 sc_log(card->ctx, "westcos_list_files\n");
647 sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x34, 0x00, 0x00);
648 apdu.cla = 0x80;
649 apdu.le = buflen;
650 apdu.resplen = buflen;
651 apdu.resp = buf;
652 r = sc_transmit_apdu(card, &apdu);
653 if (r)
654 return (r);
655 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
656 if (r)
657 return (r);
658 return apdu.resplen;
659 }
660
westcos_get_crypte_challenge(sc_card_t * card,const u8 * key,u8 * result,size_t * len)661 static int westcos_get_crypte_challenge(sc_card_t * card, const u8 * key,
662 u8 * result, size_t * len)
663 {
664 int r;
665 #ifdef ENABLE_OPENSSL
666 DES_key_schedule ks1, ks2;
667 #endif
668 u8 buf[8];
669 if ((*len) < sizeof(buf))
670 return SC_ERROR_INVALID_ARGUMENTS;
671 *len = 8;
672 r = sc_get_challenge(card, buf, *len);
673 if (r)
674 return r;
675 #ifdef ENABLE_OPENSSL
676 DES_set_key((const_DES_cblock *) & key[0], &ks1);
677 DES_set_key((const_DES_cblock *) & key[8], &ks2);
678 DES_ecb2_encrypt((const_DES_cblock *)buf, (DES_cblock*)result, &ks1, &ks2, DES_ENCRYPT);
679 return SC_SUCCESS;
680 #else
681 return SC_ERROR_NOT_SUPPORTED;
682 #endif
683 }
684
westcos_pin_cmd(sc_card_t * card,struct sc_pin_cmd_data * data,int * tries_left)685 static int westcos_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data,
686 int *tries_left)
687 {
688 int r;
689 u8 buf[20];
690 sc_apdu_t apdu;
691 size_t len = 0;
692 int pad = 0, use_pin_pad = 0, ins, p1 = 0;
693 if (card == NULL)
694 return SC_ERROR_INVALID_ARGUMENTS;
695 sc_log(card->ctx,
696 "westcos_pin_cmd:data->pin_type=%X, data->cmd=%X\n",
697 data->pin_type, data->cmd);
698 if (tries_left)
699 *tries_left = -1;
700 switch (data->pin_type) {
701 case SC_AC_AUT:
702 len = sizeof(buf);
703 r = westcos_get_crypte_challenge(card, data->pin1.data, buf,
704 &len);
705 if (r)
706 return (r);
707 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x00,
708 data->pin_reference);
709 apdu.lc = len;
710 apdu.datalen = len;
711 apdu.data = buf;
712 r = sc_transmit_apdu(card, &apdu);
713 if (r)
714 return (r);
715 return sc_check_sw(card, apdu.sw1, apdu.sw2);
716 break;
717 case SC_AC_CHV:
718 if (data->flags & SC_PIN_CMD_NEED_PADDING)
719 pad = 1;
720 if (data->flags & SC_PIN_CMD_USE_PINPAD)
721 use_pin_pad = 1;
722 data->pin1.offset = 0;
723 data->pin1.encoding = SC_PIN_ENCODING_GLP;
724 if (data->pin1.min_length == 0)
725 data->pin1.min_length = 4;
726 if (data->pin1.max_length == 0)
727 data->pin1.max_length = 12;
728 switch (data->cmd) {
729 case SC_PIN_CMD_VERIFY:
730 ins = 0x20;
731 if ((r =
732 sc_build_pin(buf, sizeof(buf), &data->pin1,
733 pad)) < 0)
734 return r;
735 len = r;
736 break;
737 case SC_PIN_CMD_CHANGE:
738 ins = 0x24;
739 if (data->pin1.len != 0 || use_pin_pad) {
740 if ((r =
741 sc_build_pin(buf, sizeof(buf),
742 &data->pin1, pad)) < 0)
743 return r;
744 len += r;
745 } else {
746
747 /* implicit test */
748 p1 = 1;
749 }
750 data->pin2.offset = data->pin1.offset + len;
751 data->pin2.encoding = SC_PIN_ENCODING_GLP;
752 if ((r =
753 sc_build_pin(buf + len, sizeof(buf) - len,
754 &data->pin2, pad)) < 0)
755 return r;
756 len += r;
757 break;
758 case SC_PIN_CMD_UNBLOCK:
759 ins = 0x2C;
760 if (data->pin1.len != 0 || use_pin_pad) {
761 if ((r =
762 sc_build_pin(buf, sizeof(buf),
763 &data->pin1, pad)) < 0)
764 return r;
765 len += r;
766 } else {
767 p1 |= 0x02;
768 }
769 if (data->pin2.len != 0 || use_pin_pad) {
770 data->pin2.offset = data->pin1.offset + len;
771 data->pin2.encoding = SC_PIN_ENCODING_GLP;
772 if ((r =
773 sc_build_pin(buf + len, sizeof(buf) - len,
774 &data->pin2, pad)) < 0)
775 return r;
776 len += r;
777 } else {
778 p1 |= 0x01;
779 }
780 break;
781 default:
782 return SC_ERROR_NOT_SUPPORTED;
783 }
784 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, ins, p1,
785 data->pin_reference);
786 apdu.lc = len;
787 apdu.datalen = len;
788 apdu.data = buf;
789 apdu.resplen = 0;
790 if (!use_pin_pad) {
791
792 /* Transmit the APDU to the card */
793 r = sc_transmit_apdu(card, &apdu);
794
795 /* Clear the buffer - it may contain pins */
796 sc_mem_clear(buf, sizeof(buf));
797 } else {
798 data->apdu = &apdu;
799 if (card->reader
800 && card->reader->ops
801 && card->reader->ops->perform_verify) {
802 r = card->reader->ops->perform_verify(card->
803 reader,
804 data);
805 } else {
806 r = SC_ERROR_NOT_SUPPORTED;
807 }
808 data->apdu = NULL;
809 }
810 if (r)
811 return (r);
812 return sc_check_sw(card, apdu.sw1, apdu.sw2);
813 default:
814 return SC_ERROR_NOT_SUPPORTED;
815 }
816 }
817
sc_get_atr(sc_card_t * card)818 static int sc_get_atr(sc_card_t * card)
819 {
820 int r;
821 sc_apdu_t apdu;
822 u8 buf[sizeof(card->atr.value)];
823 if (card == NULL)
824 return SC_ERROR_INVALID_ARGUMENTS;
825 sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xEC, 0x00, 0x00);
826 apdu.cla = 0x80;
827 apdu.le = 0x0d;
828 apdu.resplen = 0x0d;
829 apdu.resp = buf;
830 r = sc_transmit_apdu(card, &apdu);
831 if (r)
832 return (r);
833 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
834 if (r)
835 return (r);
836 memcpy(card->atr.value, buf, sizeof(card->atr.value));
837 card->atr.len = apdu.resplen;
838 return r;
839 }
840
sc_lock_phase(sc_card_t * card,u8 phase)841 static int sc_lock_phase(sc_card_t * card, u8 phase)
842 {
843 int r;
844 sc_apdu_t apdu;
845 if (card == NULL)
846 return SC_ERROR_INVALID_ARGUMENTS;
847 sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x16, phase, 0x00);
848 apdu.cla = 0x80;
849 r = sc_transmit_apdu(card, &apdu);
850 if (r)
851 return (r);
852 return sc_check_sw(card, apdu.sw1, apdu.sw2);
853 }
854
westcos_card_ctl(sc_card_t * card,unsigned long cmd,void * ptr)855 static int westcos_card_ctl(sc_card_t * card, unsigned long cmd, void *ptr)
856 {
857 unsigned int i;
858 int r;
859 size_t buflen;
860 u8 buf[256];
861 sc_apdu_t apdu;
862 struct sc_pin_cmd_data data;
863 sc_serial_number_t *serialnr;
864 priv_data_t *priv_data = NULL;
865 if (card == NULL)
866 return SC_ERROR_INVALID_ARGUMENTS;
867 sc_log(card->ctx,
868 "westcos_card_ctl cmd = %lX\n", cmd);
869 priv_data = (priv_data_t *) card->drv_data;
870 switch (cmd) {
871 case SC_CARDCTL_GET_DEFAULT_KEY:
872 return westcos_get_default_key(card,
873 (struct sc_cardctl_default_key
874 *)ptr);
875 break;
876 case SC_CARDCTL_LIFECYCLE_SET:
877 if (1) {
878 int mode = *((int *)ptr);
879 switch (mode) {
880 case SC_CARDCTRL_LIFECYCLE_ADMIN:
881 if (priv_data->flags & JAVACARD) {
882 return 0;
883 }
884 if (card->atr.value[10] == 0x80
885 || card->atr.value[10] == 0x81)
886 return 0;
887 return SC_ERROR_CARD_CMD_FAILED;
888 case SC_CARDCTRL_LIFECYCLE_USER:
889 if (card->atr.value[10] == 0x80) {
890 r = sc_lock_phase(card, 0x02);
891 if (r)
892 return (r);
893 r = sc_get_atr(card);
894 if (r)
895 return (r);
896 r = sc_card_ctl(card,
897 SC_CARDCTL_WESTCOS_AUT_KEY,
898 NULL);
899 if (r)
900 return (r);
901 }
902 if (card->atr.value[10] == 0x81) {
903 r = sc_lock_phase(card, 0x01);
904 if (r)
905 return (r);
906 r = sc_get_atr(card);
907 if (r)
908 return (r);
909 return 0;
910 }
911 return SC_ERROR_CARD_CMD_FAILED;
912 case SC_CARDCTRL_LIFECYCLE_OTHER:
913 default:
914 break;
915 }
916 }
917 break;
918 case SC_CARDCTL_GET_SERIALNR:
919 sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xEE, 0x00,
920 0x00);
921 apdu.cla = 0xb0;
922 apdu.le = 8;
923 apdu.resp = buf;
924 apdu.resplen = 10; /* include SW's */
925 r = sc_transmit_apdu(card, &apdu);
926 if (r)
927 return (r);
928 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
929 if (r)
930 return (r);
931 if (SC_MAX_SERIALNR < 8)
932 return SC_ERROR_NOT_SUPPORTED;
933 serialnr = (sc_serial_number_t *) ptr;
934 serialnr->len = 8;
935 memcpy(serialnr->value, buf, serialnr->len);
936 return 0;
937 case SC_CARDCTL_WESTCOS_CREATE_MF:
938 buf[0] = *((u8 *) ptr);
939 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x3F,
940 0x00);
941 apdu.cla = 0x80;
942 apdu.lc = 1;
943 apdu.datalen = 1;
944 apdu.data = buf;
945 apdu.le = 0;
946 r = sc_transmit_apdu(card, &apdu);
947 if (r)
948 return (r);
949 return sc_check_sw(card, apdu.sw1, apdu.sw2);
950 case SC_CARDCTL_WESTCOS_COMMIT:
951 sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2C, 0x00, 0x00);
952 apdu.cla = 0x80;
953 r = sc_transmit_apdu(card, &apdu);
954 if (r)
955 return (r);
956 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
957 if (r)
958 return (r);
959 return r;
960 case SC_CARDCTL_WESTCOS_ROLLBACK:
961 sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x24, 0x00, 0x00);
962 apdu.cla = 0x80;
963 r = sc_transmit_apdu(card, &apdu);
964 if (r)
965 return (r);
966 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
967 if (r)
968 return (r);
969 return r;
970 case SC_CARDCTL_WESTCOS_AUT_KEY:
971 if (ptr != NULL)
972 priv_data->default_key = *((sc_autkey_t *) ptr);
973 memset(&data, 0, sizeof(data));
974 data.pin_type = SC_AC_AUT;
975 data.pin_reference = priv_data->default_key.key_reference;
976 data.pin1.len = priv_data->default_key.key_len;
977 data.pin1.data = priv_data->default_key.key_value;
978 return sc_pin_cmd(card, &data, NULL);
979 case SC_CARDCTL_WESTCOS_CHANGE_KEY:
980 {
981 int lrc;
982 u8 temp[7];
983 sc_changekey_t *ck = (sc_changekey_t *) ptr;
984 sc_autkey_t master_key;
985 if (ck->master_key.key_len != 0)
986 master_key = ck->master_key;
987
988 else
989 master_key = priv_data->default_key;
990 memcpy(temp, ck->key_template, sizeof(temp));
991 westcos_compute_aetb_crc(CRC_A, ck->new_key.key_value,
992 ck->new_key.key_len, &temp[5], &temp[6]);
993 for (i = 0, temp[4] = 0xAA, lrc = 0; i < sizeof(temp);
994 i++)
995 lrc += temp[i];
996 temp[4] = (lrc % 256);
997 buflen = sizeof(buf);
998 r = westcos_get_crypte_challenge(card,
999 master_key.key_value,
1000 buf, &buflen);
1001 if (r)
1002 return (r);
1003 memcpy(&buf[buflen], temp, sizeof(temp));
1004 buflen += sizeof(temp);
1005 memcpy(&buf[buflen], ck->new_key.key_value,
1006 ck->new_key.key_len);
1007 buflen += ck->new_key.key_len;
1008 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT,
1009 0xD8, ck->new_key.key_reference,
1010 master_key.key_reference);
1011 apdu.cla = 0x80;
1012 apdu.lc = buflen;
1013 apdu.datalen = buflen;
1014 apdu.data = buf;
1015 r = sc_transmit_apdu(card, &apdu);
1016 if (r)
1017 return (r);
1018 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1019 if (r)
1020 return (r);
1021 return r;
1022 }
1023 case SC_CARDCTL_WESTCOS_SET_DEFAULT_KEY:
1024 priv_data->default_key = *((sc_autkey_t *) ptr);
1025 return 0;
1026 case SC_CARDCTL_WESTCOS_LOAD_DATA:
1027
1028 /* ptr[0] = 0x01 pour generique appli, 0x81 pour appli avec pme */
1029 buf[0] = *((u8 *) ptr);
1030 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xB2, 0x80,
1031 0x14);
1032 apdu.cla = 0xB0;
1033 apdu.lc = 1;
1034 apdu.datalen = 1;
1035 apdu.data = buf;
1036 r = sc_transmit_apdu(card, &apdu);
1037 if (r)
1038 return (r);
1039 return sc_check_sw(card, apdu.sw1, apdu.sw2);
1040 }
1041 return SC_ERROR_NOT_SUPPORTED;
1042 }
1043
westcos_set_security_env(sc_card_t * card,const struct sc_security_env * env,int se_num)1044 static int westcos_set_security_env(sc_card_t *card,
1045 const struct sc_security_env *env,
1046 int se_num)
1047 {
1048 int r = 0;
1049 priv_data_t *priv_data = NULL;
1050 if (card == NULL)
1051 return SC_ERROR_INVALID_ARGUMENTS;
1052 sc_log(card->ctx,
1053 "westcos_set_security_env\n");
1054 priv_data = (priv_data_t *) card->drv_data;
1055 priv_data->env = *env;
1056
1057 if(priv_data->flags & RSA_CRYPTO_COMPONENT)
1058 {
1059 sc_apdu_t apdu;
1060 unsigned char mode = 0;
1061 u8 buf[128];
1062
1063 if ((priv_data->env.flags) & SC_ALGORITHM_RSA_PAD_PKCS1)
1064 mode = WESTCOS_RSA_NO_HASH_PAD_PKCS1;
1065 else if ((priv_data->env.flags) & SC_ALGORITHM_RSA_RAW)
1066 mode = WESTCOS_RSA_NO_HASH_NO_PAD;
1067
1068 r = sc_path_print((char *)buf, sizeof(buf), &(env->file_ref));
1069 if(r)
1070 return r;
1071
1072 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xf0, mode);
1073 apdu.cla = 0x00;
1074 apdu.lc = strlen((char *)buf);
1075 apdu.datalen = apdu.lc;
1076 apdu.data = buf;
1077 r = sc_transmit_apdu(card, &apdu);
1078 if (r)
1079 return (r);
1080 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1081 }
1082
1083 return r;
1084 }
1085
westcos_restore_security_env(sc_card_t * card,int se_num)1086 static int westcos_restore_security_env(sc_card_t *card, int se_num)
1087 {
1088 if (card == NULL)
1089 return SC_ERROR_INVALID_ARGUMENTS;
1090 sc_log(card->ctx,
1091 "westcos_restore_security_env\n");
1092 return 0;
1093 }
1094
westcos_sign_decipher(int mode,sc_card_t * card,const u8 * data,size_t data_len,u8 * out,size_t outlen)1095 static int westcos_sign_decipher(int mode, sc_card_t *card,
1096 const u8 * data, size_t data_len, u8 * out,
1097 size_t outlen)
1098 {
1099 int r;
1100 sc_file_t *keyfile = NULL;
1101 #ifdef ENABLE_OPENSSL
1102 int idx = 0;
1103 u8 buf[180];
1104 priv_data_t *priv_data = NULL;
1105 int pad;
1106 RSA *rsa = NULL;
1107 BIO *mem = BIO_new(BIO_s_mem());
1108 #endif
1109
1110 if (card == NULL)
1111 return SC_ERROR_INVALID_ARGUMENTS;
1112
1113 sc_log(card->ctx,
1114 "westcos_sign_decipher outlen=%"SC_FORMAT_LEN_SIZE_T"u\n",
1115 outlen);
1116
1117 #ifndef ENABLE_OPENSSL
1118 r = SC_ERROR_NOT_SUPPORTED;
1119 #else
1120 if (mem == NULL || card->drv_data == NULL) {
1121 r = SC_ERROR_OUT_OF_MEMORY;
1122 goto out;
1123 }
1124
1125 priv_data = (priv_data_t *) card->drv_data;
1126
1127 if(priv_data->flags & RSA_CRYPTO_COMPONENT)
1128 {
1129 sc_apdu_t apdu;
1130
1131 sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x00, mode);
1132 apdu.datalen = data_len;
1133 apdu.data = data;
1134 apdu.lc = data_len;
1135 apdu.le = outlen > 240 ? 240 : outlen;
1136 apdu.resp = out;
1137 apdu.resplen = outlen;
1138
1139 r = sc_transmit_apdu(card, &apdu);
1140 if (r)
1141 goto out2;
1142 r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1143 if(r)
1144 goto out2;
1145
1146 /* correct */
1147 r = apdu.resplen;
1148 goto out2;
1149 }
1150 if ((priv_data->env.flags) & SC_ALGORITHM_RSA_PAD_PKCS1)
1151 pad = RSA_PKCS1_PADDING;
1152
1153 else if ((priv_data->env.flags) & SC_ALGORITHM_RSA_RAW)
1154 pad = RSA_NO_PADDING;
1155
1156 else {
1157 r = SC_ERROR_INVALID_ARGUMENTS;
1158 goto out;
1159 }
1160 r = sc_select_file(card, &(priv_data->env.file_ref), &keyfile);
1161 if (r || !keyfile)
1162 goto out;
1163
1164 do {
1165 int alire;
1166 alire = min(((keyfile->size) - idx), sizeof(buf));
1167 if (alire <= 0)
1168 break;
1169 sc_log(card->ctx,
1170 "idx = %d, alire=%d\n", idx, alire);
1171 r = sc_read_binary(card, idx, buf, alire, 0);
1172 if (r < 0)
1173 goto out;
1174 BIO_write(mem, buf, r);
1175 idx += r;
1176 } while (1);
1177 BIO_set_mem_eof_return(mem, -1);
1178 if (!d2i_RSAPrivateKey_bio(mem, &rsa)) {
1179 sc_log(card->ctx,
1180 "RSA key invalid, %lu\n", ERR_get_error());
1181 r = SC_ERROR_UNKNOWN;
1182 goto out;
1183 }
1184
1185 /* pkcs11 reset openssl functions */
1186 RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
1187
1188 if ((size_t)RSA_size(rsa) > outlen) {
1189 sc_log(card->ctx, "Buffer too small\n");
1190 r = SC_ERROR_OUT_OF_MEMORY;
1191 goto out;
1192 }
1193 #if 1
1194 if (mode) { /* decipher */
1195 r = RSA_private_decrypt(data_len, data, out, rsa, pad);
1196 if (r == -1) {
1197
1198 #ifdef DEBUG_SSL
1199 print_openssl_error();
1200
1201 #endif
1202 sc_log(card->ctx,
1203 "Decipher error %lu\n", ERR_get_error());
1204 r = SC_ERROR_UNKNOWN;
1205 goto out;
1206 }
1207 }
1208
1209 else { /* sign */
1210
1211 r = RSA_private_encrypt(data_len, data, out, rsa, pad);
1212 if (r == -1) {
1213
1214 #ifdef DEBUG_SSL
1215 print_openssl_error();
1216
1217 #endif
1218 sc_log(card->ctx,
1219 "Signature error %lu\n", ERR_get_error());
1220 r = SC_ERROR_UNKNOWN;
1221 goto out;
1222 }
1223 }
1224
1225 #else
1226 if (RSA_sign(nid, data, data_len, out, &outlen, rsa) != 1) {
1227 sc_log(card->ctx,
1228 "RSA_sign error %d \n", ERR_get_error());
1229 r = SC_ERROR_UNKNOWN;
1230 goto out;
1231 }
1232 r = outlen;
1233
1234 #endif
1235 out:
1236 if (mem)
1237 BIO_free(mem);
1238 if (rsa)
1239 RSA_free(rsa);
1240 out2:
1241 #endif /* ENABLE_OPENSSL */
1242 sc_file_free(keyfile);
1243 return r;
1244 }
1245
westcos_compute_signature(sc_card_t * card,const u8 * data,size_t data_len,u8 * out,size_t outlen)1246 static int westcos_compute_signature(sc_card_t *card, const u8 * data,
1247 size_t data_len, u8 * out, size_t outlen)
1248 {
1249 return westcos_sign_decipher(0, card, data, data_len, out, outlen);
1250 }
1251
westcos_decipher(sc_card_t * card,const u8 * crgram,size_t crgram_len,u8 * out,size_t outlen)1252 static int westcos_decipher(sc_card_t *card, const u8 * crgram,
1253 size_t crgram_len, u8 * out, size_t outlen)
1254 {
1255 return westcos_sign_decipher(1, card, crgram, crgram_len, out, outlen);
1256 }
1257
sc_get_westcos_driver(void)1258 struct sc_card_driver *sc_get_westcos_driver(void)
1259 {
1260 if (iso_ops == NULL)
1261 iso_ops = sc_get_iso7816_driver()->ops;
1262 westcos_ops = *iso_ops;
1263
1264 westcos_ops.match_card = westcos_match_card;
1265 westcos_ops.init = westcos_init;
1266 westcos_ops.finish = westcos_finish;
1267 /* read_binary */
1268 /* write_binary */
1269 /* update_binary */
1270 /* read_record */
1271 /* write_record */
1272 /* append_record */
1273 /* update_record */
1274 westcos_ops.select_file = westcos_select_file;
1275 /* get_response */
1276 /* get_challenge */
1277 westcos_ops.restore_security_env = westcos_restore_security_env;
1278 westcos_ops.set_security_env = westcos_set_security_env;
1279 westcos_ops.decipher = westcos_decipher;
1280 westcos_ops.compute_signature = westcos_compute_signature;
1281 westcos_ops.create_file = westcos_create_file;
1282 westcos_ops.delete_file = westcos_delete_file;
1283 westcos_ops.list_files = westcos_list_files;
1284 westcos_ops.check_sw = westcos_check_sw;
1285 westcos_ops.card_ctl = westcos_card_ctl;
1286 westcos_ops.process_fci = westcos_process_fci;
1287 westcos_ops.construct_fci = NULL;
1288 westcos_ops.pin_cmd = westcos_pin_cmd;
1289
1290 return &westcos_drv;
1291 }
1292
1293