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

Revision 3490, 41.1 KB (checked in by alonbl, 7 months ago)

rutoken: Some MSVC fixups, by Aktiv Co. Aleksey Samsonov

Line 
1/*
2 *  card-rutoken.c: Support for Rutoken cards
3 *
4 * Copyright (C) 2007  Pavel Mironchik <rutoken@rutoken.ru>
5 * Copyright (C) 2007  Eugene Hermann <rutoken@rutoken.ru>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20*/
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#if defined(HAVE_INTTYPES_H)
26#include <inttypes.h>
27#elif defined(HAVE_STDINT_H)
28#include <stdint.h>
29#elif defined(_MSC_VER)
30typedef unsigned __int32 uint32_t;
31typedef unsigned __int16 uint16_t;
32typedef __int8 int8_t;
33#else
34#warning no uint32_t type available, please contact opensc-devel@opensc-project.org
35#endif
36#include <sys/types.h>
37#include <ctype.h>
38#include <string.h>
39#include <stdlib.h>
40#include <stdio.h>
41#include "opensc.h"
42#include "pkcs15.h"
43#include "internal.h"
44#include "cardctl.h"
45
46#ifdef ENABLE_OPENSSL
47#include <openssl/evp.h>
48#include <openssl/rsa.h>
49#include <openssl/dsa.h>
50#include <opensc/asn1.h>
51#include <openssl/x509.h>
52#include <openssl/err.h>
53#endif
54
55#define FDESCR_DF           0x38 /*00111000b*/
56#define FDESCR_EF           0x01
57#define ID_RESERVED_CURDF   0x3FFF /*Reserved ID for current DF*/
58
59struct auth_senv {
60        unsigned int algorithm;
61};
62typedef struct auth_senv auth_senv_t;
63
64static const sc_SecAttrV2_t default_sec_attr = {
65        0x42,
66        0, 1, 0, 0, 0, 0, 1,
67        0, 2, 0, 0, 0, 0, 2
68};
69
70static struct sc_card_operations rutoken_ops;
71
72static struct sc_card_driver rutoken_drv = {
73        "Rutoken driver",
74        "rutoken",
75        &rutoken_ops,
76        NULL, 0, NULL
77};
78
79static struct sc_atr_table rutoken_atrs[] = {
80        { "3b:6f:00:ff:00:56:72:75:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL },
81        { NULL, NULL, NULL, 0, 0, NULL }
82};
83
84static const char *hexdump(const void *data, size_t len)
85{
86        static char string[1024];
87        unsigned char *d = (unsigned char *)data;
88        unsigned int i, left;
89
90        string[0] = '\0';
91        left = sizeof(string);
92        for (i = 0; len--; i += 3) {
93                if (i >= sizeof(string) - 4)
94                        break;
95                snprintf(string + i, 4, " %02x", *d++);
96        }
97        return string;
98}
99
100static int rutoken_finish(sc_card_t *card)
101{
102        SC_FUNC_CALLED(card->ctx, 1);
103        free(card->drv_data);
104        SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
105}
106
107static int rutoken_match_card(sc_card_t *card)
108{
109        SC_FUNC_CALLED(card->ctx, 1);
110        if (_sc_match_atr(card, rutoken_atrs, &card->type) >= 0)
111        {
112                sc_debug(card->ctx, "ATR recognized as Rutoken\n");
113                SC_FUNC_RETURN(card->ctx, 1, 1);
114        }
115        SC_FUNC_RETURN(card->ctx, 1, 0);
116}
117
118static int token_init(sc_card_t *card, const char *card_name)
119{
120        unsigned int flags;
121        sc_algorithm_info_t info;
122
123        SC_FUNC_CALLED(card->ctx, 3);
124
125        card->name = card_name;
126        card->caps |= SC_CARD_CAP_RSA_2048 | SC_CARD_CAP_NO_FCI | SC_CARD_CAP_RNG;
127        card->drv_data = calloc(1, sizeof(auth_senv_t));
128        if (card->drv_data == NULL)
129                SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_OUT_OF_MEMORY);
130
131        flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
132        _sc_card_add_rsa_alg(card, 256, flags, 0);
133        _sc_card_add_rsa_alg(card, 512, flags, 0);
134        _sc_card_add_rsa_alg(card, 768, flags, 0);
135        _sc_card_add_rsa_alg(card, 1024, flags, 0);
136        _sc_card_add_rsa_alg(card, 2048, flags, 0);
137
138        memset(&info, 0, sizeof(info));
139        info.algorithm = SC_ALGORITHM_GOST;
140        info.flags = SC_ALGORITHM_GOST_CRYPT_PZ | SC_ALGORITHM_GOST_CRYPT_GAMM
141                | SC_ALGORITHM_GOST_CRYPT_GAMMOS;
142        info.key_length = 32;
143        _sc_card_add_algorithm(card, &info);
144
145        SC_FUNC_RETURN(card->ctx, 3, SC_SUCCESS);
146}
147
148static int rutoken_init(sc_card_t *card)
149{
150        int ret;
151
152        SC_FUNC_CALLED(card->ctx, 1);
153        ret = token_init(card, "Rutoken card");
154        SC_FUNC_RETURN(card->ctx, 1, ret);
155}
156
157static const struct sc_card_error rutoken_errors[] = {
158
159        { 0x6300, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
160        { 0x63C1, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed. One tries left"},
161        { 0x63C2, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed. Two tries left"},
162        { 0x63C3, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
163        { 0x63C4, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
164        { 0x63C5, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
165        { 0x63C6, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
166        { 0x63C7, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
167        { 0x63C8, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
168        { 0x63C9, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
169        { 0x63CA, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
170        { 0x63CB, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
171        { 0x63CC, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
172        { 0x63CD, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
173        { 0x63CE, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
174        { 0x63CF, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
175
176        { 0x6400, SC_ERROR_CARD_CMD_FAILED,     "Aborting"},
177
178        { 0x6500, SC_ERROR_MEMORY_FAILURE,      "Memory failure"},
179        { 0x6581, SC_ERROR_MEMORY_FAILURE,      "Memory failure"},
180
181        { 0x6700, SC_ERROR_WRONG_LENGTH,        "Lc or Le invalid"},
182
183        { 0x6883, SC_ERROR_CARD_CMD_FAILED,     "The finishing command of a chain is expected"},
184
185        { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Required access right not granted"},
186        { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "DO blocked"},
187        { 0x6985, SC_ERROR_CARD_CMD_FAILED,     "Command not allowed (unsuitable conditions)"},
188        { 0x6986, SC_ERROR_INCORRECT_PARAMETERS,"No current EF selected"},
189
190        { 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Invalid parameters in data field"},
191        { 0x6A81, SC_ERROR_NOT_SUPPORTED,       "Function/mode not supported"},
192        { 0x6A82, SC_ERROR_FILE_NOT_FOUND,      "File (DO) not found"},
193        { 0x6A84, SC_ERROR_CARD_CMD_FAILED,     "Not enough memory space in the token"},
194        { 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"P1 or P2 invalid"},
195        { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File (DO) already exists"},
196
197        { 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Out of maximum file length"},
198
199        { 0x6C00, SC_ERROR_WRONG_LENGTH,        "Le does not fit the data to be sent"},
200
201        { 0x6D00, SC_ERROR_INS_NOT_SUPPORTED,   "Ins invalid (not supported)"},
202
203        /* Own class of an error*/
204        { 0x6F01, SC_ERROR_CARD_CMD_FAILED,     "Rutoken has the exchange protocol which is not supported by the USB-driver (newer, than in the driver)"},
205        { 0x6F83, SC_ERROR_CARD_CMD_FAILED,     "Infringement of the exchange protocol with Rutoken is revealed"},
206        { 0x6F84, SC_ERROR_CARD_CMD_FAILED,     "Rutoken is busy by processing of other command"},
207        { 0x6F85, SC_ERROR_CARD_CMD_FAILED,     "In the current folder the maximum quantity of file system objects is already created"},
208        { 0x6F86, SC_ERROR_CARD_CMD_FAILED,     "Invalid access right. Already login"},
209
210        { 0x9000, SC_NO_ERROR,                  NULL}
211};
212
213static int rutoken_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
214{
215        size_t i;
216
217        for (i = 0; i < sizeof(rutoken_errors)/sizeof(rutoken_errors[0]); ++i) {
218                if (rutoken_errors[i].SWs == ((sw1 << 8) | sw2)) {
219                        if ( rutoken_errors[i].errorstr )
220                                sc_error(card->ctx, "%s\n", rutoken_errors[i].errorstr);
221                        sc_debug(card->ctx, "sw1 = %x, sw2 = %x", sw1, sw2);
222                        return rutoken_errors[i].errorno;
223                }
224        }
225        sc_error(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X\n", sw1, sw2);
226        return SC_ERROR_CARD_CMD_FAILED;
227}
228
229static int rutoken_dir_up(sc_card_t *card)
230{
231        u8 rbuf[256];
232        sc_apdu_t apdu;
233        int ret;
234
235        SC_FUNC_CALLED(card->ctx, 3);
236
237        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0x00);
238        apdu.cla = 0x00;
239        apdu.resplen = sizeof(rbuf);
240        apdu.resp = rbuf;
241        apdu.le = sizeof(rbuf);
242
243        ret = sc_transmit_apdu(card, &apdu);
244        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
245        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
246        SC_FUNC_RETURN(card->ctx, 3, ret);
247}
248
249static int rutoken_list_files(sc_card_t *card, u8 *buf, size_t buflen)
250{
251        u8 rbuf[256];
252        u8 previd[2];
253        sc_apdu_t apdu;
254        size_t len = 0;
255        int ret, first = 1;
256
257        SC_FUNC_CALLED(card->ctx, 1);
258        while (1)
259        {
260                if (first)
261                        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x00, 0x00);
262                else
263                {
264                        /*  00 a4 00 02 02 prev id - next  */
265                        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x02);
266                        apdu.lc = sizeof(previd);
267                        apdu.data = previd;
268                        apdu.datalen = sizeof(previd);
269                }
270                apdu.cla = 0x00;
271                apdu.resplen = sizeof(rbuf);
272                apdu.resp = rbuf;
273                apdu.le = sizeof(rbuf);
274                ret = sc_transmit_apdu(card, &apdu);
275                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
276
277                if (apdu.sw1 == 0x6A  &&  apdu.sw2 == 0x82)
278                        break; /*  if (first) "end list" else "empty dir"  */
279
280                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
281                SC_TEST_RET(card->ctx, ret, "Get list files failed");
282
283                /*  save first file(dir) ID  */
284                if (len + 2 <= buflen)
285                {
286                        buf[len++] = rbuf[6];
287                        buf[len++] = rbuf[7];
288                }
289                memcpy(previd, rbuf+6, sizeof(previd));
290                if (rbuf[4] == FDESCR_DF)
291                        rutoken_dir_up(card);
292                first = 0;
293        }
294        SC_FUNC_RETURN(card->ctx, 1, len);
295}
296
297static void rutoken_process_fcp(sc_card_t *card, u8 *pIn, sc_file_t *file)
298{
299        file->size = pIn[3] + ((uint16_t)pIn[2])*256;
300        file->id = pIn[7] + ((uint16_t)pIn[6])*256;
301
302        if (pIn[4] == FDESCR_DF)
303        {
304                file->type = SC_FILE_TYPE_DF;
305        }
306        else
307        {
308                file->type = SC_FILE_TYPE_WORKING_EF;
309                file->ef_structure = SC_FILE_EF_TRANSPARENT;
310        }
311        sc_file_set_sec_attr(file, pIn + 17, SEC_ATTR_SIZE);
312
313        if (file->sec_attr  &&  file->sec_attr_len == SEC_ATTR_SIZE
314#ifndef SET_ACL_FOR_EF_LENLESS8_RUTOKEN
315/*
316 * No set ACL for EF:
317 *  PrKDF_path: "3F00FF000001" - SC_PKCS15_PRKDF
318 *  PuKDF_path: "3F00FF000002" - SC_PKCS15_PUKDF
319 *  CDF_path:   "3F00FF000003" - SC_PKCS15_CDF
320 *  DODF_path:  "3F00FF000004" - SC_PKCS15_DODF
321 *  (see files: src/libopensc/pkcs15-rutoken.c, src/pkcs15init/rutoken.profile)
322 */
323                        && (file->type != SC_FILE_TYPE_WORKING_EF || file->path.len >= 8)
324#endif
325        )
326        {
327                sc_file_add_acl_entry(file, SC_AC_OP_SELECT,
328                                SC_AC_NONE, SC_AC_KEY_REF_NONE);
329                if (file->sec_attr[0] & 0x40) /* if AccessMode.6 */
330                {
331                        sc_debug(card->ctx, "SC_AC_OP_DELETE %i %i",
332                                        (int)(*(int8_t*)&file->sec_attr[1 +6]),
333                                        file->sec_attr[1+7 +6]);
334                        sc_file_add_acl_entry(file, SC_AC_OP_DELETE,
335                                        (int)(*(int8_t*)&file->sec_attr[1 +6]),
336                                        file->sec_attr[1+7 +6]);
337                }
338                if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */
339                {
340                        sc_debug(card->ctx, (file->type == SC_FILE_TYPE_DF) ?
341                                        "SC_AC_OP_CREATE %i %i" : "SC_AC_OP_READ %i %i",
342                                        (int)(*(int8_t*)&file->sec_attr[1 +0]),
343                                        file->sec_attr[1+7 +0]);
344                        sc_file_add_acl_entry(file,
345                                        (file->type == SC_FILE_TYPE_DF) ?
346                                        SC_AC_OP_CREATE : SC_AC_OP_READ,
347                                        (int)(*(int8_t*)&file->sec_attr[1 +0]),
348                                        file->sec_attr[1+7 +0]);
349                }
350                if (file->type == SC_FILE_TYPE_DF)
351                {
352                        sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES,
353                                        SC_AC_NONE, SC_AC_KEY_REF_NONE);
354                }
355                else
356                        if (file->sec_attr[0] & 0x02) /* if AccessMode.1 */
357                        {
358                                sc_debug(card->ctx, "SC_AC_OP_UPDATE %i %i",
359                                                (int)(*(int8_t*)&file->sec_attr[1 +1]),
360                                                file->sec_attr[1+7 +1]);
361                                sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
362                                                (int)(*(int8_t*)&file->sec_attr[1 +1]),
363                                                file->sec_attr[1+7 +1]);
364                                sc_debug(card->ctx, "SC_AC_OP_WRITE %i %i",
365                                                (int)(*(int8_t*)&file->sec_attr[1 +1]),
366                                                file->sec_attr[1+7 +1]);
367                                sc_file_add_acl_entry(file, SC_AC_OP_WRITE,
368                                                (int)(*(int8_t*)&file->sec_attr[1 +1]),
369                                                file->sec_attr[1+7 +1]);
370                        }
371        }
372}
373
374static int rutoken_select_file(sc_card_t *card,
375                        const sc_path_t *in_path, sc_file_t **file)
376{
377        int ret;
378        u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
379        int pathlen;
380        u8 buf[SC_MAX_APDU_BUFFER_SIZE];
381        sc_apdu_t apdu;
382
383        SC_FUNC_CALLED(card->ctx, 1);
384        if (!in_path || in_path->len < 2)
385                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
386
387        pathlen = in_path->len;
388        memcpy(path, in_path->value, pathlen);
389
390        sc_debug(card->ctx, "\n\tpath = %s\n\ttype = %d",
391                        hexdump(path, pathlen), in_path->type);
392
393        ret = SC_ERROR_INVALID_ARGUMENTS;
394        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
395        switch (in_path->type)
396        {
397        case SC_PATH_TYPE_FILE_ID:
398                if (pathlen == 2) /*  select file in current df  */
399                {
400                        apdu.p1 = 2;
401                        ret = SC_SUCCESS;
402                }
403                break;
404        case SC_PATH_TYPE_PATH:
405                apdu.p1 = 8;
406                if (path[0] == 0x3F  && path[1] == 0x00)
407                {
408                        if (pathlen == 2) /* select MF  */
409                        {
410                                apdu.p1 = 0;
411                        }
412                        else /* select DF  */
413                        {
414                                path += 2;
415                                pathlen -= 2;
416                        }
417                }
418                ret = SC_SUCCESS;
419                break;
420        default:
421                ret = SC_ERROR_NOT_SUPPORTED;
422                break;
423        }
424        if (ret == SC_SUCCESS)
425        {
426                apdu.lc = pathlen;
427                apdu.data = path;
428                apdu.datalen = pathlen;
429
430                if (file != NULL) {
431                        apdu.resp = buf;
432                        apdu.resplen = sizeof(buf);
433                        apdu.le = 256;
434                } else {
435                        apdu.resplen = 0;
436                        apdu.le = 0;
437                        apdu.cse = SC_APDU_CASE_3_SHORT;
438                }
439                ret = sc_transmit_apdu(card, &apdu);
440                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
441                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
442
443                if (file == NULL)
444                {
445                        /*  We don't need file info  */
446                        if (apdu.sw1 == 0x61)
447                                SC_FUNC_RETURN(card->ctx, 2, SC_NO_ERROR);
448                        SC_FUNC_RETURN(card->ctx, 1, ret);
449                }
450                /*  New file structure  */
451                if ((ret == SC_SUCCESS) && (apdu.resplen == 32))
452                {
453                        *file = sc_file_new();
454                        if (*file == NULL)
455                                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OUT_OF_MEMORY);
456                        (*file)->path = *in_path;
457                        /*  what about selecting EF by ID (SC_PATH_TYPE_FILE_ID)?  */
458
459                        rutoken_process_fcp(card, buf, *file);
460
461                        sc_debug(card->ctx,
462                                "nfile ID = %04X, path = %s, type = %02X, len = %d",
463                                (*file)->id, hexdump((*file)->path.value, (*file)->path.len),
464                                (*file)->type, (*file)->size);
465                        sc_debug(card->ctx, "sec attr = %s",
466                                hexdump((*file)->sec_attr, (*file)->sec_attr_len));
467                }
468        }
469        SC_FUNC_RETURN(card->ctx, 1, ret);
470}
471
472static int rutoken_construct_fcp(sc_card_t *card, const sc_file_t *file, u8 *out)
473{
474        SC_FUNC_CALLED(card->ctx, 3);
475
476        if ((!file) || (file->id == ID_RESERVED_CURDF))
477                SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
478        memset(out, 0, 32);
479        switch (file->type)
480        {
481        case SC_FILE_TYPE_DF:
482                out[4] = 0x38;
483                out[0] = file->size / 256;
484                out[1] = file->size % 256;
485                break;
486        case SC_FILE_TYPE_WORKING_EF:
487                out[4] = 0x01;
488                /*   set the length (write to wBodyLen)  */
489                out[2] = file->size / 256;
490                out[3] = file->size % 256;
491                break;
492        case SC_FILE_TYPE_INTERNAL_EF:
493        default:
494                SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_NOT_SUPPORTED);
495        }
496        /*   set file ID  */
497        out[6] = file->id / 256;
498        out[7] = file->id % 256;
499
500        /*  set sec_attr  */
501        if (file->sec_attr_len == SEC_ATTR_SIZE)
502                memcpy(out + 17, file->sec_attr, SEC_ATTR_SIZE);
503        else
504                memcpy(out + 17, &default_sec_attr, SEC_ATTR_SIZE);
505
506        SC_FUNC_RETURN(card->ctx, 3, SC_NO_ERROR);
507}
508
509static int rutoken_create_file(sc_card_t *card, sc_file_t *file)
510{
511        int ret;
512        sc_apdu_t apdu;
513        u8 sbuf[32] = { 0 };
514
515        SC_FUNC_CALLED(card->ctx, 1);
516        ret = rutoken_construct_fcp(card, file, sbuf);
517        if (ret == SC_NO_ERROR)
518        {
519                sc_debug(card->ctx, "fcp = %s", hexdump(sbuf, 32));
520                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
521                apdu.data = sbuf;
522                apdu.datalen = 32;
523                apdu.lc = 32;
524
525                ret = sc_transmit_apdu(card, &apdu);
526                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
527                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
528        }
529        SC_FUNC_RETURN(card->ctx, 1, ret);
530}
531
532static int rutoken_delete_file(sc_card_t *card, const sc_path_t *path)
533{
534        u8 sbuf[2];
535        sc_apdu_t apdu;
536
537        SC_FUNC_CALLED(card->ctx, 1);
538        if (!path || path->type != SC_PATH_TYPE_FILE_ID || (path->len != 0 && path->len != 2))
539        {
540                sc_error(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
541                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
542        }
543        if (path->len == sizeof(sbuf))
544        {
545                sbuf[0] = path->value[0];
546                sbuf[1] = path->value[1];
547                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
548                apdu.lc = sizeof(sbuf);
549                apdu.datalen = sizeof(sbuf);
550                apdu.data = sbuf;
551        }
552        else /* No file ID given: means currently selected file */
553                sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
554        SC_TEST_RET(card->ctx, sc_transmit_apdu(card, &apdu), "APDU transmit failed");
555        SC_FUNC_RETURN(card->ctx, 1, sc_check_sw(card, apdu.sw1, apdu.sw2));
556}
557
558static int rutoken_verify(sc_card_t *card, unsigned int type, int ref_qualifier,
559                        const u8 *data, size_t data_len, int *tries_left)
560{
561        sc_apdu_t apdu;
562        int ret;
563
564        SC_FUNC_CALLED(card->ctx, 1);
565        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
566        ret = sc_transmit_apdu(card, &apdu);
567        if (ret == SC_SUCCESS  &&  apdu.sw1 == 0x90  &&  apdu.sw2 == 0x00)
568        {
569                /* already login */
570                /* RESET ACCESS RIGHTS */
571                sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
572                apdu.cla = 0x80;
573                ret = sc_transmit_apdu(card, &apdu);
574                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
575                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
576                SC_TEST_RET(card->ctx, ret, "Reset access rights failed");
577        }
578
579        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, ref_qualifier);
580        apdu.lc = data_len;
581        apdu.datalen = data_len;
582        apdu.data = data;
583        ret = sc_transmit_apdu(card, &apdu);
584        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
585        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
586        if (ret == SC_ERROR_PIN_CODE_INCORRECT  &&  tries_left)
587        {
588                sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
589                ret = sc_transmit_apdu(card, &apdu);
590                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
591                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
592                if (ret == SC_ERROR_PIN_CODE_INCORRECT)
593                        *tries_left = (int)(apdu.sw2 & 0x0f);
594        }
595        SC_FUNC_RETURN(card->ctx, 1, ret);
596}
597
598static int rutoken_logout(sc_card_t *card)
599{
600        sc_apdu_t apdu;
601        sc_path_t path;
602        int ret;
603
604        SC_FUNC_CALLED(card->ctx, 1);
605        sc_format_path("3F00", &path);
606        ret = rutoken_select_file(card, &path, NULL);
607        SC_TEST_RET(card->ctx, ret, "Select MF failed");
608
609        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
610        apdu.cla = 0x80;
611        ret = sc_transmit_apdu(card, &apdu);
612        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
613        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
614        SC_FUNC_RETURN(card->ctx, 1, ret);
615}
616
617static int rutoken_change_reference_data(sc_card_t *card, unsigned int type,
618                        int ref_qualifier, const u8 *old, size_t oldlen,
619                        const u8 *newref, size_t newlen, int *tries_left)
620{
621        sc_apdu_t apdu;
622        int ret;
623
624        SC_FUNC_CALLED(card->ctx, 1);
625        if (old && oldlen)
626        {
627                ret = rutoken_verify(card, type, ref_qualifier, old, oldlen, tries_left);
628                SC_TEST_RET(card->ctx, ret, "Invalid 'old' pass");
629        }
630        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
631        apdu.lc = newlen;
632        apdu.datalen = newlen;
633        apdu.data = newref;
634        ret = sc_transmit_apdu(card, &apdu);
635        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
636        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
637        SC_FUNC_RETURN(card->ctx, 1, ret);
638}
639
640static int rutoken_reset_retry_counter(sc_card_t *card, unsigned int type,
641                        int ref_qualifier, const u8 *puk, size_t puklen,
642                        const u8 *newref, size_t newlen)
643{
644#ifdef FORCE_VERIFY_RUTOKEN
645        int left;
646#endif
647        sc_apdu_t apdu;
648        int ret;
649
650        SC_FUNC_CALLED(card->ctx, 1);
651#ifdef FORCE_VERIFY_RUTOKEN
652        if (puk && puklen)
653        {
654                ret = rutoken_verify(card, type, ref_qualifier, puk, puklen, &left);
655                sc_error(card->ctx, "Tries left: %i\n", left);
656                SC_TEST_RET(card->ctx, ret, "Invalid 'puk' pass");
657        }
658#endif
659        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, ref_qualifier);
660        ret = sc_transmit_apdu(card, &apdu);
661        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
662        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
663        SC_FUNC_RETURN(card->ctx, 1, ret);
664}
665
666static int rutoken_restore_security_env(sc_card_t *card, int se_num)
667{
668        sc_apdu_t apdu;
669        int ret;
670
671        SC_FUNC_CALLED(card->ctx, 1);
672        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 3, se_num);
673        ret = sc_transmit_apdu(card, &apdu);
674        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
675        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
676        SC_FUNC_RETURN(card->ctx, 1, ret);
677}
678
679static int rutoken_set_security_env(sc_card_t *card,
680                        const sc_security_env_t *env,
681                        int se_num)
682{
683        sc_apdu_t apdu;
684        auth_senv_t *senv;
685        u8 data[3] = { 0x83, 0x01 };
686        int ret;
687
688        SC_FUNC_CALLED(card->ctx, 1);
689        if (!env)
690                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);       
691        senv = (auth_senv_t*)card->drv_data;
692        if (!senv)
693                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
694        if (env->algorithm == SC_ALGORITHM_RSA)
695        {
696                senv->algorithm = SC_ALGORITHM_RSA_RAW;
697                SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
698        }
699
700        senv->algorithm = SC_ALGORITHM_GOST;
701        if (env->key_ref_len != 1)
702        {
703                sc_error(card->ctx, "No or invalid key reference\n");
704                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
705        }
706        data[2] = env->key_ref[0];
707        /*  select component  */
708        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 1, 0);
709        apdu.lc = apdu.datalen = sizeof(data);
710        apdu.data = data;
711        switch (env->operation)
712        {
713                case SC_SEC_OPERATION_AUTHENTICATE:
714                        apdu.p2 = 0xA4;
715                        break;
716                case SC_SEC_OPERATION_DECIPHER:
717                        apdu.p2 = 0xB8;
718                        break;
719                case SC_SEC_OPERATION_SIGN:
720                        apdu.p2 = 0xAA;
721                        break;
722                default:
723                        SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
724        }
725        /*  set SE  */
726        ret = sc_transmit_apdu(card, &apdu);
727        SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
728        ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
729        SC_FUNC_RETURN(card->ctx, 1, ret);
730}
731
732static void rutoken_set_do_hdr(u8 *data, sc_DOHdrV2_t *pHdr)
733{
734        if (data)
735        {
736                data[0] = (u8)(pHdr->wDOBodyLen / 0x100);
737                data[1] = (u8)(pHdr->wDOBodyLen % 0x100);
738                data[2] = (u8)(pHdr->OTID.byObjectType);
739                data[3] = (u8)(pHdr->OTID.byObjectID);
740                data[4] = (u8)(pHdr->OP.byObjectOptions);
741                data[5] = (u8)(pHdr->OP.byObjectFlags);
742                data[6] = (u8)(pHdr->OP.byObjectTry);
743                memcpy(data + 7, pHdr->dwReserv1, 4);
744                memcpy(data + 11, pHdr->abyReserv2, 6);
745                memcpy(data + 17, pHdr->SA_V2, SEC_ATTR_SIZE);
746        }
747}
748
749static int rutoken_key_gen(sc_card_t *card, sc_DOHdrV2_t *pHdr)
750{
751        u8 data[SC_RUTOKEN_DO_HDR_LEN];
752        sc_apdu_t apdu;
753        int ret;
754
755        SC_FUNC_CALLED(card->ctx, 3);
756        if (
757             (pHdr->wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST) ||
758             (pHdr->OTID.byObjectType != SC_RUTOKEN_TYPE_KEY) ||
759             (pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) ||
760             (pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_FULL_OPEN_DO) ||
761             (pHdr->OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
762             (pHdr->OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)
763        )
764        {
765                ret = SC_ERROR_INVALID_ARGUMENTS;
766        }
767        else
768        {
769                pHdr->OP.byObjectTry = 0;
770                rutoken_set_do_hdr(data, pHdr);
771                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x65);
772                apdu.data = data;
773                apdu.datalen = apdu.lc = sizeof(data);
774                ret = sc_transmit_apdu(card, &apdu);
775                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
776                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
777        }
778        SC_FUNC_RETURN(card->ctx, 3, ret);
779}
780
781static int rutoken_create_do(sc_card_t *card, sc_DO_V2_t * pDO)
782{
783        u8 data[SC_RUTOKEN_DO_HDR_LEN + SC_RUTOKEN_DO_PART_BODY_LEN];
784        sc_apdu_t apdu;
785        int ret;
786
787        SC_FUNC_CALLED(card->ctx, 3);
788        if (
789             ((pDO->HDR.OTID.byObjectType & SC_RUTOKEN_TYPE_CHV) &&
790              (pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_USER) &&
791              (pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_ADMIN)) ||
792             ((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_GOST) &&
793              (pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST)) ||
794             ((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_SE) &&
795              (pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_SE)) ||
796             (pDO->HDR.OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
797             (pDO->HDR.OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2) ||
798             ((pDO->HDR.OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) &&
799              (pDO->HDR.wDOBodyLen > SC_RUTOKEN_COMPACT_DO_MAX_LEN)) ||
800             (pDO->HDR.wDOBodyLen > SC_RUTOKEN_DO_PART_BODY_LEN)
801           )
802        {
803                ret = SC_ERROR_INVALID_ARGUMENTS;
804        }
805        else
806        {
807                rutoken_set_do_hdr(data, &pDO->HDR);
808                memcpy(data + SC_RUTOKEN_DO_HDR_LEN, pDO->abyDOBody, pDO->HDR.wDOBodyLen);
809                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x62);
810                apdu.data = data;
811                apdu.datalen = apdu.lc = SC_RUTOKEN_DO_HDR_LEN + pDO->HDR.wDOBodyLen;
812                ret = sc_transmit_apdu(card, &apdu);
813                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
814                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
815        }
816        SC_FUNC_RETURN(card->ctx, 3, ret);
817}
818
819static int rutoken_get_do_info(sc_card_t *card, sc_DO_INFO_t * pInfo)
820{
821        u8 data[1];
822        sc_apdu_t apdu;
823        int ret;
824
825        SC_FUNC_CALLED(card->ctx, 3);
826        if ((pInfo->SelType != select_first) &&
827            ((pInfo->DoId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
828             (pInfo->DoId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)))
829        {
830                ret = SC_ERROR_INVALID_ARGUMENTS;
831        }
832        else
833        {
834                sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x30, 0x00, 0x00);
835                apdu.cla = 0x80;
836                apdu.resp = pInfo->pDoData;
837                apdu.resplen = sizeof(pInfo->pDoData);
838                apdu.le = 255;
839                memset(apdu.resp, 0, apdu.resplen);
840                switch(pInfo->SelType)
841                {
842                case select_first:
843                        apdu.cse = SC_APDU_CASE_2_SHORT;
844                        break;
845                case select_next:
846                        apdu.p2  = 0x02;
847                case select_by_id:
848                        data[0] = pInfo->DoId;
849                        apdu.data = data;
850                        apdu.datalen = sizeof(data);
851                        apdu.lc = sizeof(data);
852                        break;
853                default:
854                        SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
855                        break;
856                }
857                ret = sc_transmit_apdu(card, &apdu);
858                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
859                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
860        }
861        SC_FUNC_RETURN(card->ctx, 3, ret);
862}
863
864static int rutoken_delete_do(sc_card_t *card, u8 *pId)
865{
866        u8 data[1];
867        sc_apdu_t apdu;
868        int ret;
869
870        SC_FUNC_CALLED(card->ctx, 3);
871        if ((*pId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
872            (*pId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2))
873        {
874                ret = SC_ERROR_INVALID_ARGUMENTS;
875        }
876        else
877        {
878                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x64);
879                data[0] = *pId;
880                apdu.data = data;
881                apdu.datalen = sizeof(data);
882                apdu.lc = sizeof(data);
883                ret = sc_transmit_apdu(card, &apdu);
884                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
885                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
886        }
887        SC_FUNC_RETURN(card->ctx, 3, ret);
888}
889
890/*  Both direction GOST cipher  */
891
892static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_len,
893                        u8 * out, size_t outlen, int p1, int p2, int isIV)
894{
895        u8 buf[248]; /* 248 (cipher_chunk) <= SC_MAX_APDU_BUFFER_SIZE  */
896        size_t len, outlen_tail = outlen;
897        int ret;
898        sc_apdu_t apdu;
899
900        SC_FUNC_CALLED(card->ctx, 3);
901        sc_debug(card->ctx, ": crgram_len %i; outlen %i", crgram_len, outlen);
902
903        if (!out)
904                SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
905        if (crgram_len < 16 || ((crgram_len) % 8))
906                SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_WRONG_LENGTH);
907
908        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, p1, p2);
909        do
910        {
911                len = (crgram_len > sizeof(buf)) ? sizeof(buf) : crgram_len;
912                apdu.lc = len;
913                apdu.datalen = len;
914                apdu.data = crgram;
915                crgram += len;
916                crgram_len -= len;
917
918                apdu.cla = (crgram_len == 0) ? 0x00 : 0x10;
919                apdu.le = len;
920                apdu.resplen = len;
921                apdu.resp = buf;
922
923                ret = sc_transmit_apdu(card, &apdu);
924                SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
925                ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
926                if (ret == SC_NO_ERROR)
927                {
928                        if (isIV)
929                        {
930                                apdu.resp += 8;
931                                apdu.resplen -= 8;
932                                isIV = 0;
933                        }
934                        if (apdu.resplen > outlen_tail)
935                                ret = SC_ERROR_BUFFER_TOO_SMALL;
936                        else
937                        {
938                                memcpy(out, apdu.resp, apdu.resplen);
939                                out += apdu.resplen;
940                                outlen_tail -= apdu.resplen;
941                        }
942                }
943        } while (ret == SC_NO_ERROR  &&  crgram_len != 0);
944        sc_debug(card->ctx, "len out cipher %d\n", outlen - outlen_tail);
945        if (ret == SC_NO_ERROR)
946                ret = (outlen_tail == 0) ? (int)outlen : SC_ERROR_WRONG_LENGTH;
947        SC_FUNC_RETURN(card->ctx, 3, ret);
948}
949
950/*  Launcher for cipher  */
951
952static int rutoken_cipher_gost(sc_card_t *card,
953                        struct sc_rutoken_decipherinfo *ptr, char is_encipher)
954{
955        int ret;
956
957        if (is_encipher)
958                ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
959                                ptr->outbuf, ptr->outlen, 0x86, 0x80, 0);
960        else
961                ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
962                                ptr->outbuf, ptr->outlen, 0x80, 0x86, 1);
963        if (ret > 0)
964        {
965                if ((size_t)ret == ptr->outlen)
966                        ret = SC_SUCCESS;
967                else
968                        ret = SC_ERROR_INTERNAL; /* SC_ERROR_DECRYPT_FAILED; */
969        }
970        return ret;
971
972}
973
974static int rutoken_compute_mac_gost(sc_card_t *card,
975                        const u8 *in, size_t ilen,
976                        u8 *out, size_t olen)
977{
978        const size_t signing_chunk = 248;
979        size_t len;
980        int ret;
981        sc_apdu_t apdu;
982
983        SC_FUNC_CALLED(card->ctx, 3);
984        if (!in || !out || olen != 4 || ilen == 0)
985                SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
986