root/trunk/src/libopensc/card-atrust-acos.c

Revision 3502, 27.2 KB (checked in by ludovic.rousseau, 7 months ago)

convert C++ in C comment

Line 
1/*
2 * atrust-acos.c: Support for A-Trust ACOS based cards
3 *
4 * Copyright (C) 2005  Franz Brandl <brandl@a-trust.at> based on work from
5 *                     Jörn Zukowski <zukowski@trustcenter.de> and
6 *                     Nils Larsch   <larsch@trustcenter.de>, TrustCenter AG
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22
23#include "internal.h"
24#include "asn1.h"
25#include "cardctl.h"
26#include <stdlib.h>
27#include <string.h>
28
29/*****************************************************************************/
30
31#define ACOS_EMV_A03            "A-TRUST ACOS"
32#define ACOS_EMV_A05            "A-TRUST ACOS A05"
33
34static const char *atrust_acos_atrs[] = {
35  "3B:BF:11:00:81:31:fe:45:45:50:41",
36  "3B:BF:11:00:81:31:fe:45:4d:43:41",
37  "3B:BF:13:00:81:31:fe:45:45:50:41",
38  "3B:BF:13:00:81:31:fe:45:4d:43:41",
39  NULL
40};
41
42/* sequence and number has to match atr table ! */
43static const char *atrust_acos_names[] = {
44  ACOS_EMV_A03,
45  ACOS_EMV_A03,
46  ACOS_EMV_A05,
47  ACOS_EMV_A05,
48  NULL
49};
50
51static struct sc_card_operations atrust_acos_ops;
52static struct sc_card_operations *iso_ops = NULL;
53
54static struct sc_card_driver atrust_acos_drv = {
55        "A-Trust ACOS cards",
56        "atrust-acos",
57        &atrust_acos_ops,
58        NULL, 0, NULL
59};
60
61/* internal structure to save the current security enviroment */
62typedef struct atrust_acos_ex_data_st {
63        int    sec_ops; /* the currently selected security operation,
64                         * i.e. SC_SEC_OPERATION_AUTHENTICATE etc. */
65        unsigned int    fix_digestInfo;
66} atrust_acos_ex_data;
67
68/*****************************************************************************/
69
70static int atrust_acos_match_card(struct sc_card *card)
71{
72        int             i, match = 0;
73 
74
75        for (i = 0; atrust_acos_atrs[i] != NULL; i++)
76        {
77                u8 defatr[SC_MAX_ATR_SIZE];
78                size_t len = sizeof(defatr);
79                const char *atrp = atrust_acos_atrs[i];
80     
81                if (sc_hex_to_bin(atrp, defatr, &len))
82                        continue;
83                /* we may only verify part of ATR since */
84                /* part of the hist chars is variable */
85                if (len > card->atr_len)
86                        continue;
87                if (memcmp(card->atr, defatr, len) != 0)
88                        continue;
89
90                match = 1;
91                card->name = atrust_acos_names[i];
92
93                break;
94    }
95        return match;
96}
97
98/*****************************************************************************/
99
100static int atrust_acos_init(struct sc_card *card)
101{
102        unsigned int flags;
103        atrust_acos_ex_data *ex_data;
104
105        ex_data = (atrust_acos_ex_data *) calloc(1, sizeof(atrust_acos_ex_data));
106        if (ex_data == NULL)
107                return SC_ERROR_OUT_OF_MEMORY;
108
109        card->cla  = 0x00;
110        card->drv_data = (void *)ex_data;
111
112        /* set the supported algorithm */
113
114        flags = SC_ALGORITHM_RSA_PAD_PKCS1
115                | SC_ALGORITHM_RSA_HASH_NONE
116                | SC_ALGORITHM_RSA_HASH_SHA1
117                | SC_ALGORITHM_RSA_HASH_MD5
118                | SC_ALGORITHM_RSA_HASH_RIPEMD160
119                | SC_ALGORITHM_RSA_HASH_MD5_SHA1;
120
121        if (!strcmp(card->name, ACOS_EMV_A05))
122                flags |= SC_ALGORITHM_RSA_HASH_SHA256;
123
124        _sc_card_add_rsa_alg(card, 1536, flags, 0x10001);
125
126        /* we need read_binary&friends with max 128 bytes per read */
127        if (card->max_send_size > 128)
128                card->max_send_size = 128;
129        if (card->max_recv_size > 128)
130                card->max_recv_size = 128;
131
132        return 0;
133}
134
135/*****************************************************************************/
136
137static int atrust_acos_finish(struct sc_card *card)
138{
139        if (card->drv_data)
140                free((atrust_acos_ex_data *)card->drv_data);
141        return 0;
142}
143
144/*****************************************************************************/
145
146static int process_fci(struct sc_context *ctx, struct sc_file *file,
147                       const u8 *buf, size_t buflen)
148{
149
150        size_t taglen, len = buflen;
151        const u8 *tag = NULL, *p;
152 
153        if (ctx->debug >= 3)
154                sc_debug(ctx, "processing FCI bytes\n");
155
156        if (buflen < 2)
157                return SC_ERROR_INTERNAL;
158        if (buf[0] != 0x6f)                                     /* FCI template */
159                return SC_ERROR_INVALID_DATA;
160        len = (size_t)buf[1];
161        if (buflen - 2 < len)
162                return SC_ERROR_INVALID_DATA;
163        p = buf + 2;
164
165        /* defaults */
166        file->type = SC_FILE_TYPE_WORKING_EF;
167        file->ef_structure = SC_FILE_EF_UNKNOWN;
168        file->shareable = 0;
169        file->record_length = 0;
170        file->size = 0;
171 
172        /* get file size */
173        tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
174        if (tag != NULL && taglen >= 2) {
175                int bytes = (tag[0] << 8) + tag[1];
176                if (ctx->debug >= 3)
177                        sc_debug(ctx, "  bytes in file: %d\n", bytes);
178                file->size = bytes;
179        }
180
181        /* get file type */
182        tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
183        if (tag != NULL) {
184                const char *type = "unknown";
185                const char *structure = "unknown";
186
187                if (taglen == 1 && tag[0] == 0x01) {
188                        /* transparent EF */
189                        type = "working EF";
190                        structure = "transparent";
191                        file->type = SC_FILE_TYPE_WORKING_EF;
192                        file->ef_structure = SC_FILE_EF_TRANSPARENT;
193                } else if (taglen == 1 && tag[0] == 0x11) {
194                        /* object EF */
195                        type = "working EF";
196                        structure = "object";
197                        file->type = SC_FILE_TYPE_WORKING_EF;
198                        file->ef_structure = SC_FILE_EF_TRANSPARENT; /* TODO */
199                } else if (taglen == 3 && tag[1] == 0x21) {
200                        type = "working EF";
201                        file->record_length = tag[2];
202                        file->type = SC_FILE_TYPE_WORKING_EF;
203                        /* linear fixed, cyclic or compute */
204                        switch ( tag[0] )
205                        {
206                                case 0x02:
207                                        structure = "linear fixed";
208                                        file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
209                                        break;
210                                case 0x07:
211                                        structure = "cyclic";
212                                        file->ef_structure = SC_FILE_EF_CYCLIC;
213                                        break;
214                                case 0x17:
215                                        structure = "compute";
216                                        file->ef_structure = SC_FILE_EF_UNKNOWN;
217                                        break;
218                                default:
219                                        structure = "unknown";
220                                        file->ef_structure = SC_FILE_EF_UNKNOWN;
221                                        file->record_length = 0;
222                                        break;
223                        }
224                }
225
226                if (ctx->debug >= 3) {
227                        sc_debug(ctx, "  type: %s\n", type);
228                        sc_debug(ctx, "  EF structure: %s\n", structure);
229                }
230        }
231        file->magic = SC_FILE_MAGIC;
232
233        return SC_SUCCESS;
234}
235
236/*****************************************************************************/
237
238static int atrust_acos_select_aid(struct sc_card *card,
239                              u8 aid[16], size_t len,
240                              struct sc_file **file_out)
241{
242        sc_apdu_t apdu;
243        int r;
244        size_t i = 0;
245
246        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
247        apdu.lc = len;
248        apdu.data = (u8*)aid;
249        apdu.datalen = len;
250        apdu.resplen = 0;
251        apdu.le = 0;
252        r = sc_transmit_apdu(card, &apdu);
253        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
254
255        /* check return value */
256        if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 )
257                SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
258 
259        /* update cache */
260        card->cache.current_path.type = SC_PATH_TYPE_DF_NAME;
261        card->cache.current_path.len = len;
262        memcpy(card->cache.current_path.value, aid, len);
263
264        if (file_out) {
265                sc_file_t *file = sc_file_new();
266                if (!file)
267                        SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
268                file->type = SC_FILE_TYPE_DF;
269                file->ef_structure = SC_FILE_EF_UNKNOWN;
270                file->path.len = 0;
271                file->size = 0;
272                /* AID */
273                for (i = 0; i < len; i++) 
274                        file->name[i] = aid[i];
275                file->namelen = len;
276                file->id = 0x0000;
277                file->magic = SC_FILE_MAGIC;
278                *file_out = file;
279        }
280        SC_FUNC_RETURN(card->ctx, 2, SC_SUCCESS);
281}
282
283/*****************************************************************************/
284
285static int atrust_acos_select_fid(struct sc_card *card,
286                              unsigned int id_hi, unsigned int id_lo,
287                              struct sc_file **file_out)
288{
289        sc_apdu_t apdu;
290        u8 data[] = {id_hi & 0xff, id_lo & 0xff};
291        u8 resp[SC_MAX_APDU_BUFFER_SIZE];
292        int bIsDF = 0, r;
293
294        /* request FCI to distinguish between EFs and DFs */
295        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00);
296        apdu.resp = (u8*)resp;
297        apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
298        apdu.le = 256;
299        apdu.lc = 2;
300        apdu.data = (u8*)data;
301        apdu.datalen = 2;
302
303        r = sc_transmit_apdu(card, &apdu);
304        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
305
306        if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) {
307                /* no FCI => we have a DF (see comment in process_fci()) */
308                bIsDF = 1;
309                apdu.p2 = 0x0C;
310                apdu.cse = SC_APDU_CASE_3_SHORT;
311                apdu.resplen = 0;
312                apdu.le = 0;
313                r = sc_transmit_apdu(card, &apdu);
314                SC_TEST_RET(card->ctx, r, "APDU re-transmit failed");
315        } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)) {
316                /* SELECT returned some data (possible FCI) =>
317                 * try a READ BINARY to see if a EF is selected */
318                sc_apdu_t apdu2;
319                u8 resp2[2];
320                sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0);
321                apdu2.resp = (u8*)resp2;
322                apdu2.resplen = 2;
323                apdu2.le = 1;
324                apdu2.lc = 0;
325                r = sc_transmit_apdu(card, &apdu2);
326                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
327                if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86)
328                        /* no current EF is selected => we have a DF */
329                        bIsDF = 1;
330        }
331
332        if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00))
333                SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
334
335        /* update cache */
336        if (bIsDF) {
337                card->cache.current_path.type = SC_PATH_TYPE_PATH;
338                card->cache.current_path.value[0] = 0x3f;
339                card->cache.current_path.value[1] = 0x00;
340                if (id_hi == 0x3f && id_lo == 0x00)
341                        card->cache.current_path.len = 2;
342                else {
343                        card->cache.current_path.len = 4;
344                        card->cache.current_path.value[2] = id_hi;
345                        card->cache.current_path.value[3] = id_lo;
346                }
347        }
348
349        if (file_out) {
350                sc_file_t *file = sc_file_new();
351                if (!file)
352                        SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
353                file->id   = (id_hi << 8) + id_lo;
354                file->path = card->cache.current_path;
355
356                if (bIsDF) {
357                        /* we have a DF */
358                        file->type = SC_FILE_TYPE_DF;
359                        file->ef_structure = SC_FILE_EF_UNKNOWN;
360                        file->size = 0;
361                        file->namelen = 0;
362                        file->magic = SC_FILE_MAGIC;
363                        *file_out = file;
364                } else {
365                        /* ok, assume we have a EF */
366                        r = process_fci(card->ctx, file, apdu.resp,
367                                        apdu.resplen);
368                        if (r != SC_SUCCESS) {
369                                sc_file_free(file);
370                                return r;
371                        }
372
373                        *file_out = file;
374                }
375        }
376
377        SC_FUNC_RETURN(card->ctx, 2, SC_SUCCESS);
378}
379
380/*****************************************************************************/
381
382static int atrust_acos_select_file(struct sc_card *card,
383                               const struct sc_path *in_path,
384                               struct sc_file **file_out)
385{
386        u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
387        int    r;
388        size_t i, pathlen;
389
390        if (card->ctx->debug >= 4) {
391                char pbuf[SC_MAX_PATH_STRING_SIZE];
392
393                r = sc_path_print(pbuf, sizeof(pbuf), &card->cache.current_path);
394                if (r != SC_SUCCESS)
395                        pbuf[0] = '\0';
396
397                sc_debug(card->ctx, "current path (%s, %s): %s (len: %u)\n",
398                        (card->cache.current_path.type==SC_PATH_TYPE_DF_NAME?"aid":"path"),
399                        (card->cache_valid?"valid":"invalid"), pbuf,
400                        card->cache.current_path.len);
401        }
402 
403        memcpy(path, in_path->value, in_path->len);
404        pathlen = in_path->len;
405
406        if (in_path->type == SC_PATH_TYPE_FILE_ID)
407        {       /* SELECT EF/DF with ID */
408                /* Select with 2byte File-ID */
409                if (pathlen != 2)
410                        SC_FUNC_RETURN(card->ctx,2,SC_ERROR_INVALID_ARGUMENTS);
411                return atrust_acos_select_fid(card, path[0], path[1], file_out);
412        }
413        else if (in_path->type == SC_PATH_TYPE_DF_NAME)
414        {       /* SELECT DF with AID */
415                /* Select with 1-16byte Application-ID */
416                if (card->cache_valid
417                    && card->cache.current_path.type == SC_PATH_TYPE_DF_NAME
418                    && card->cache.current_path.len == pathlen
419                    && memcmp(card->cache.current_path.value, pathbuf, pathlen) == 0 )
420                {
421                        if (card->ctx->debug >= 4)
422                                sc_debug(card->ctx, "cache hit\n");
423                        SC_FUNC_RETURN(card->ctx, 2, SC_SUCCESS);
424                }
425                else
426                        return atrust_acos_select_aid(card, pathbuf, pathlen, file_out);
427        }
428        else if (in_path->type == SC_PATH_TYPE_PATH)
429        {
430                u8 n_pathbuf[SC_MAX_PATH_SIZE];
431                int bMatch = -1;
432
433                /* Select with path (sequence of File-IDs) */
434                /* ACOS only supports one
435                 * level of subdirectories, therefore a path is
436                 * at most 3 FID long (the last one being the FID
437                 * of a EF) => pathlen must be even and less than 6
438                 */
439                if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
440                        SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
441                /* if pathlen == 6 then the first FID must be MF (== 3F00) */
442                if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
443                        SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
444
445                /* unify path (the first FID should be MF) */
446                if (path[0] != 0x3f || path[1] != 0x00)
447                {
448                        n_pathbuf[0] = 0x3f;
449                        n_pathbuf[1] = 0x00;
450                        for (i=0; i< pathlen; i++)
451                                n_pathbuf[i+2] = pathbuf[i];
452                        path = n_pathbuf;
453                        pathlen += 2;
454                }
455       
456                /* check current working directory */
457                if (card->cache_valid
458                    && card->cache.current_path.type == SC_PATH_TYPE_PATH
459                    && card->cache.current_path.len >= 2
460                    && card->cache.current_path.len <= pathlen )
461                {
462                        bMatch = 0;
463                        for (i=0; i < card->cache.current_path.len; i+=2)
464                                if (card->cache.current_path.value[i] == path[i]
465                                    && card->cache.current_path.value[i+1] == path[i+1] )
466                                        bMatch += 2;
467                }
468
469                if ( card->cache_valid && bMatch >= 0 )
470                {
471                        if ( pathlen - bMatch == 2 )
472                                /* we are in the rigth directory */
473                                return atrust_acos_select_fid(card, path[bMatch], path[bMatch+1], file_out);
474                        else if ( pathlen - bMatch > 2 )
475                        {
476                                /* two more steps to go */
477                                sc_path_t new_path;
478       
479                                /* first step: change directory */
480                                r = atrust_acos_select_fid(card, path[bMatch], path[bMatch+1], NULL);
481                                SC_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
482               
483                                new_path.type = SC_PATH_TYPE_PATH;
484                                new_path.len  = pathlen - bMatch-2;
485                                memcpy(new_path.value, &(path[bMatch+2]), new_path.len);
486                                /* final step: select file */
487                                return atrust_acos_select_file(card, &new_path, file_out);
488                        }
489                        else /* if (bMatch - pathlen == 0) */
490                        {
491                                /* done: we are already in the
492                                 * requested directory */
493                                if ( card->ctx->debug >= 4 )
494                                        sc_debug(card->ctx, "cache hit\n");
495                                /* copy file info (if necessary) */
496                                if (file_out) {
497                                        sc_file_t *file = sc_file_new();
498                                        if (!file)
499                                                SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
500                                        file->id = (path[pathlen-2] << 8) +
501                                                   path[pathlen-1];
502                                        file->path = card->cache.current_path;
503                                        file->type = SC_FILE_TYPE_DF;
504                                        file->ef_structure = SC_FILE_EF_UNKNOWN;
505                                        file->size = 0;
506                                        file->namelen = 0;
507                                        file->magic = SC_FILE_MAGIC;
508                                        *file_out = file;
509                                }
510                                /* nothing left to do */
511                                return SC_SUCCESS;
512                        }
513                }
514                else
515                {
516                        /* no usable cache */
517                        for ( i=0; i<pathlen-2; i+=2 )
518                        {
519                                r = atrust_acos_select_fid(card, path[i], path[i+1], NULL);
520                                SC_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
521                        }
522                        return atrust_acos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out);
523                }
524        }
525        else
526                SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
527}
528
529/** atrust_acos_set_security_env
530 * sets the security enviroment
531 * \param card pointer to the sc_card object
532 * \param env pointer to a sc_security_env object
533 * \param se_num not used here
534 * \return SC_SUCCESS on success or an error code
535 *
536 * This function sets the security enviroment (using the
537 * command MANAGE SECURITY ENVIROMENT). In case a COMPUTE SIGNATURE
538 * operation is requested , this function tries to detect whether
539 * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE must be used for signature
540 * calculation.
541 */
542static int atrust_acos_set_security_env(struct sc_card *card,
543                                    const struct sc_security_env *env,
544                                    int se_num)
545{
546        u8              *p, *pp, keyID;
547        int              r, operation = env->operation;
548        struct sc_apdu   apdu;
549        u8               sbuf[SC_MAX_APDU_BUFFER_SIZE];
550        atrust_acos_ex_data *ex_data = (atrust_acos_ex_data *)card->drv_data;
551
552        p     = sbuf;
553        keyID = env->key_ref[0];
554
555        /* copy key reference, if present */
556        if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
557                if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC)
558                        *p++ = 0x83;
559                else
560                        *p++ = 0x84;
561                *p++ = env->key_ref_len;
562                memcpy(p, env->key_ref, env->key_ref_len);
563                p += env->key_ref_len;
564        }
565        pp = p;
566        if (operation == SC_SEC_OPERATION_DECIPHER){
567                if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
568                        *p++ = 0x80;
569                        *p++ = 0x01;
570                        *p++ = 0x02;
571                } else
572                        return SC_ERROR_INVALID_ARGUMENTS;
573                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81,
574                               0xb8);
575                apdu.data    = sbuf;
576                apdu.datalen = p - sbuf;
577                apdu.lc      = p - sbuf;
578                apdu.le      = 0;
579                r = sc_transmit_apdu(card, &apdu);
580                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
581                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
582                        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
583                return SC_SUCCESS;
584        }
585        /* try COMPUTE SIGNATURE */
586        if (operation == SC_SEC_OPERATION_SIGN && (
587            env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1 ||
588            env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796)) {
589                if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
590                        *p++ = 0x80;
591                        *p++ = 0x01;
592                        *p++ = env->algorithm_ref & 0xFF;
593                } else if (env->flags & SC_SEC_ENV_ALG_PRESENT &&
594                            env->algorithm == SC_ALGORITHM_RSA) {
595                        /* set the method to use based on the algorithm_flags */
596                        *p++ = 0x80;
597                        *p++ = 0x01;
598                        if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
599                                if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
600                                        *p++ = 0x12;
601                                else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160)
602                                        *p++ = 0x22;
603                                else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
604                                        *p++ = 0x32;
605                                else {
606                                        /* can't use COMPUTE SIGNATURE =>
607                                         * try INTERNAL AUTHENTICATE */
608                                        p = pp;
609                                        operation = SC_SEC_OPERATION_AUTHENTICATE;
610                                        goto try_authenticate;
611                                }
612                        } else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796) {
613                                if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
614                                        *p++ = 0x11;
615                                else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160)
616                                        *p++ = 0x21;
617                                else
618                                        return SC_ERROR_INVALID_ARGUMENTS;
619                        } else
620                                return SC_ERROR_INVALID_ARGUMENTS;
621                }
622                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xb6);
623                apdu.data    = sbuf;
624                apdu.datalen = p - sbuf;
625                apdu.lc      = p - sbuf;
626                apdu.le      = 0;
627                /* suppress errors, as don't know whether to use
628                 * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE */
629                sc_ctx_suppress_errors_on(card->ctx);
630                r = sc_transmit_apdu(card, &apdu);
631                sc_ctx_suppress_errors_off(card->ctx);
632                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
633                if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
634                        ex_data->fix_digestInfo = 0;
635                        ex_data->sec_ops        = SC_SEC_OPERATION_SIGN;
636                        return SC_SUCCESS;
637                }
638                /* reset pointer */
639                p = pp;
640                /* doesn't work => try next op */
641                operation = SC_SEC_OPERATION_AUTHENTICATE;
642        }
643try_authenticate:
644        /* try INTERNAL AUTHENTICATE */
645        if (operation == SC_SEC_OPERATION_AUTHENTICATE &&
646            env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
647                *p++ = 0x80;
648                *p++ = 0x01;
649                *p++ = 0x01;
650               
651                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xa4);
652                apdu.data    = sbuf;
653                apdu.datalen = p - sbuf;
654                apdu.lc      = p - sbuf;
655                apdu.le      = 0;
656                r = sc_transmit_apdu(card, &apdu);
657                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
658                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
659                        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
660                ex_data->fix_digestInfo = env->algorithm_flags;
661                ex_data->sec_ops        = SC_SEC_OPERATION_AUTHENTICATE;
662                return SC_SUCCESS;
663        }
664
665        return SC_ERROR_INVALID_ARGUMENTS;
666}
667
668/*****************************************************************************/
669
670static int atrust_acos_compute_signature(struct sc_card *card,
671                                     const u8 * data, size_t datalen,
672                                     u8 * out, size_t outlen)
673{
674        int r;
675        struct sc_apdu apdu;
676        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
677        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
678        atrust_acos_ex_data *ex_data = (atrust_acos_ex_data *)card->drv_data;
679
680        if (datalen > SC_MAX_APDU_BUFFER_SIZE)
681                SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
682
683        if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) {
684                /* compute signature with the COMPUTE SIGNATURE command */
685               
686                /* set the hash value     */
687                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A,
688                               0x90, 0x81);
689                apdu.resp = rbuf;
690                apdu.resplen = sizeof(rbuf);
691                apdu.le = 0;
692                memcpy(sbuf, data, datalen);
693                apdu.data = sbuf;
694                apdu.lc = datalen;
695                apdu.datalen = datalen;
696                r = sc_transmit_apdu(card, &apdu);
697                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
698                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
699                        SC_FUNC_RETURN(card->ctx, 4,
700                                       sc_check_sw(card, apdu.sw1, apdu.sw2));
701
702                /* call COMPUTE SIGNATURE */
703                sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A,
704                               0x9E, 0x9A);
705                apdu.resp = rbuf;
706                apdu.resplen = sizeof(rbuf);
707                apdu.le = 256;
708
709                apdu.lc = 0;
710                apdu.datalen = 0;
711                apdu.sensitive = 1;
712                r = sc_transmit_apdu(card, &apdu);
713                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
714                if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
715                        size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
716                        memcpy(out, apdu.resp, len);
717                        SC_FUNC_RETURN(card->ctx, 4, len);
718                }
719        } else if (ex_data->sec_ops == SC_SEC_OPERATION_AUTHENTICATE) {
720                size_t tmp_len;
721                /* call INTERNAL AUTHENTICATE */
722                sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x10, 0x00);
723                /* fix/create DigestInfo structure (if necessary) */
724                if (ex_data->fix_digestInfo) {
725                        unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES;
726                        if (flags == 0x0)
727                                /* XXX: assume no hash is wanted */
728                                flags = SC_ALGORITHM_RSA_HASH_NONE;
729                        tmp_len = sizeof(sbuf);
730                        r = sc_pkcs1_encode(card->ctx, flags, data, datalen,
731                                        sbuf, &tmp_len, sizeof(sbuf));
732                        if (r < 0)
733                                return r;
734                } else {
735                        memcpy(sbuf, data, datalen);
736                        tmp_len = datalen;
737                }
738                apdu.lc = tmp_len;
739                apdu.data = sbuf;
740                apdu.datalen = tmp_len;
741                apdu.resp = rbuf;
742                apdu.resplen = sizeof(rbuf);
743                apdu.le = 256;
744                r = sc_transmit_apdu(card, &apdu);
745                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
746                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
747                        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
748                {
749                        size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
750
751                        memcpy(out, apdu.resp, len);
752                        SC_FUNC_RETURN(card->ctx, 4, len);
753                }
754        } else
755                SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
756
757        /* clear old state */
758        ex_data->sec_ops = 0;
759        ex_data->fix_digestInfo = 0;
760
761        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
762}
763
764/*****************************************************************************/
765
766static int atrust_acos_decipher(struct sc_card *card,
767                            const u8 * crgram, size_t crgram_len,
768                            u8 * out, size_t outlen)
769{
770        int r;
771        struct sc_apdu apdu;
772        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
773        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
774
775        assert(card != NULL && crgram != NULL && out != NULL);
776        SC_FUNC_CALLED(card->ctx, 2);
777        if (crgram_len > 255)
778                SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
779
780        /* INS: 0x2A  PERFORM SECURITY OPERATION
781         * P1:  0x80  Resp: Plain value
782         * P2:  0x86  Cmd: Padding indicator byte followed by cryptogram */
783        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
784        apdu.resp = rbuf;
785        apdu.resplen = sizeof(rbuf);
786        apdu.sensitive = 1;
787       
788        sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
789        memcpy(sbuf + 1, crgram, crgram_len);
790        apdu.data = sbuf;
791        apdu.lc = crgram_len + 1;
792        apdu.datalen = crgram_len + 1;
793        apdu.le = 256;
794        r = sc_transmit_apdu(card, &apdu);
795        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
796        if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
797                size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
798
799                memcpy(out, apdu.resp, len);
800                SC_FUNC_RETURN(card->ctx, 2, len);
801        }
802
803        SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
804}
805
806/*****************************************************************************/
807
808static int atrust_acos_check_sw(struct sc_card *card, unsigned int sw1,
809        unsigned int sw2)
810{
811
812        if (card->ctx->debug >= 3)
813                sc_debug(card->ctx, "sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
814 
815        if (sw1 == 0x90)
816                return SC_NO_ERROR;
817        if (sw1 == 0x63 && (sw2 & ~0x0fU) == 0xc0 )
818        {
819                sc_error(card->ctx, "Verification failed (remaining tries: %d)\n",
820                (sw2 & 0x0f));
821                return SC_ERROR_PIN_CODE_INCORRECT;
822        }
823 
824        /* iso error */
825        return iso_ops->check_sw(card, sw1, sw2);
826}
827
828/*****************************************************************************/
829
830static int acos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
831{
832        int r;
833        u8  rbuf[SC_MAX_APDU_BUFFER_SIZE];
834        sc_apdu_t apdu;
835
836        if (!serial)
837                return SC_ERROR_INVALID_ARGUMENTS;
838        /* see if we have cached serial number */
839        if (card->serialnr.len) {
840                memcpy(serial, &card->serialnr, sizeof(*serial));
841                return SC_SUCCESS;
842        }
843        /* get serial number via GET CARD DATA */
844        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00);
845        apdu.cla |= 0x80;
846        apdu.resp = rbuf;
847        apdu.resplen = sizeof(rbuf);
848        apdu.le   = 256;
849        apdu.lc   = 0;
850        apdu.datalen = 0;
851        r = sc_transmit_apdu(card, &apdu);
852        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
853        if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
854                return SC_ERROR_INTERNAL;
855        /* cache serial number */
856        memcpy(card->serialnr.value, apdu.resp, apdu.resplen);
857        card->serialnr.len = apdu.resplen;
858        /* copy and return serial number */
859        memcpy(serial, &card->serialnr, sizeof(*serial));
860        return SC_SUCCESS;
861}
862
863/*****************************************************************************/
864
865static int atrust_acos_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
866{
867
868        switch (cmd)
869        {
870        case SC_CARDCTL_GET_SERIALNR:
871                return acos_get_serialnr(card, (sc_serial_number_t *)ptr);
872        default:
873                return SC_ERROR_NOT_SUPPORTED;
874        }
875}
876
877/*****************************************************************************/
878
879static int atrust_acos_logout(struct sc_card *card)
880{
881        int r;
882        struct sc_apdu apdu;
883        const u8 mf_buf[2] = {0x3f, 0x00};
884
885        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
886        apdu.le = 0;
887        apdu.lc = 2;
888        apdu.data    = mf_buf;
889        apdu.datalen = 2;
890        apdu.resplen = 0;
891       
892        sc_ctx_suppress_errors_on(card->ctx);
893        r = sc_transmit_apdu(card, &apdu);
894        sc_ctx_suppress_errors_off(card->ctx);
895        SC_TEST_RET(card->ctx, r, "APDU re-transmit failed");
896
897        if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85)
898                /* the only possible reason for this error here is, afaik,
899                 * that no MF exists, but then there's no need to logout
900                 * => return SC_SUCCESS
901                 */
902                return SC_SUCCESS;
903        return sc_check_sw(card, apdu.sw1, apdu.sw2);
904}
905
906/*****************************************************************************/
907
908static struct sc_card_driver * sc_get_driver(void)
909{
910        struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
911        if (iso_ops == NULL)
912                iso_ops = iso_drv->ops;
913 
914        atrust_acos_ops = *iso_drv->ops;
915        atrust_acos_ops.match_card = atrust_acos_match_card;
916        atrust_acos_ops.init   = atrust_acos_init;
917        atrust_acos_ops.finish = atrust_acos_finish;
918        atrust_acos_ops.select_file = atrust_acos_select_file;
919        atrust_acos_ops.check_sw    = atrust_acos_check_sw;
920        atrust_acos_ops.create_file = NULL;
921        atrust_acos_ops.delete_file = NULL;
922        atrust_acos_ops.set_security_env  = atrust_acos_set_security_env;
923        atrust_acos_ops.compute_signature = atrust_acos_compute_signature;
924        atrust_acos_ops.decipher    = atrust_acos_decipher;
925        atrust_acos_ops.card_ctl    = atrust_acos_card_ctl;
926        atrust_acos_ops.logout      = atrust_acos_logout;
927 
928        return &atrust_acos_drv;
929}
930
931/*****************************************************************************/
932
933struct sc_card_driver * sc_get_atrust_acos_driver(void)
934{
935        return sc_get_driver();
936}
Note: See TracBrowser for help on using the browser.