root/trunk/src/libopensc/ctbcs.c

Revision 2832, 5.6 kB (checked in by nils, 3 years ago)

sc_mutex_destroy should have a return value

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * ctbcs.c: Extended CTBCS commands, used for pcsc and ct-api readers
3 *
4 * Copyright (C) 2002  Olaf Kirch <okir@lst.de>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include "internal.h"
22#include "ctbcs.h"
23#include <assert.h>
24#include <stdlib.h>
25#include <string.h>
26
27static void
28ctbcs_init_apdu(sc_apdu_t *apdu, int cse, int ins, int p1, int p2)
29{
30        memset(apdu, 0, sizeof(*apdu));
31        apdu->cse = cse;
32        apdu->cla = 0x20;
33        apdu->ins = ins;
34        apdu->p1  = p1;
35        apdu->p2  = p2;
36
37        apdu->control = 1;
38}
39
40#if 0
41static int
42ctbcs_build_input_apdu(sc_apdu_t *apdu, int echo, const char *prompt,
43                        u8 *rbuf, size_t rbuflen)
44{
45        ctbcs_init_apdu(apdu, SC_APDU_CASE_2_SHORT,
46                        CTBCS_INS_INPUT,
47                        CTBCS_P1_KEYPAD,
48                        echo? CTBCS_P2_INPUT_ECHO : CTBCS_P2_INPUT_ASTERISKS);
49
50        if (prompt && *prompt) {
51                apdu->cse = SC_APDU_CASE_4_SHORT;
52                apdu->data = (u8 *) prompt;
53                apdu->lc = apdu->datalen = strlen(prompt);
54        }
55
56        apdu->le = apdu->resplen = rbuflen;
57        apdu->resp = rbuf;
58        return 0;
59}
60
61static int
62ctbcs_build_output_apdu(sc_apdu_t *apdu, const char *message)
63{
64        ctbcs_init_apdu(apdu,
65                        SC_APDU_CASE_3_SHORT,
66                        CTBCS_INS_INPUT,
67                        CTBCS_P1_DISPLAY,
68                        0);
69
70        if (!message || !*message)
71                message = " ";
72
73        apdu->lc = apdu->datalen = strlen(message);
74
75        return 0;
76}
77#endif
78
79static int
80ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot)
81{
82        const char *prompt;
83        size_t buflen, count = 0, j = 0, len;
84        static u8 buf[254];
85        u8 control;
86
87        ctbcs_init_apdu(apdu,
88                        SC_APDU_CASE_3_SHORT,
89                        CTBCS_INS_PERFORM_VERIFICATION,
90                        CTBCS_P1_INTERFACE1 + (slot ? slot->id : 0),
91                        0);
92
93        buflen = sizeof(buf);
94        prompt = data->pin1.prompt;
95        if (prompt && *prompt) {
96                len = strlen(prompt);
97                if (count + len + 2 > buflen || len > 255)
98                        return SC_ERROR_BUFFER_TOO_SMALL;
99                buf[count++] = CTBCS_TAG_PROMPT;
100                buf[count++] = len;
101                memcpy(buf + count, prompt, len);
102                count += len;
103        }
104
105        /* card apdu must be last in packet */
106        if (!data->apdu)
107                return SC_ERROR_INTERNAL;
108        if (count + 7 > buflen)
109                return SC_ERROR_BUFFER_TOO_SMALL;
110
111        j = count;
112        buf[j++] = CTBCS_TAG_VERIFY_CMD;
113        buf[j++] = 0x00;
114
115        /* Control byte - length of PIN, and encoding */
116        control = 0x00;
117        if (data->pin1.encoding == SC_PIN_ENCODING_ASCII)
118                control |= CTBCS_PIN_CONTROL_ENCODE_ASCII;
119        else if (data->pin1.encoding != SC_PIN_ENCODING_BCD)
120                return SC_ERROR_INVALID_ARGUMENTS;
121        if (data->pin1.min_length == data->pin1.max_length)
122                control |= data->pin1.min_length << CTBCS_PIN_CONTROL_LEN_SHIFT;
123        buf[j++] = control;
124        buf[j++] = data->pin1.offset+1; /* Looks like offset is 1-based in CTBCS */
125        buf[j++] = data->apdu->cla;
126        buf[j++] = data->apdu->ins;
127        buf[j++] = data->apdu->p1;
128        buf[j++] = data->apdu->p2;
129
130        if (data->flags & SC_PIN_CMD_NEED_PADDING) {
131                len = data->pin1.pad_length;
132                if (j + len > buflen || len > 256)
133                        return SC_ERROR_BUFFER_TOO_SMALL;
134                buf[j++] = len;
135                memset(buf+j, data->pin1.pad_char, len);
136                j += len;
137        }
138        buf[count+1] = j - count - 2;
139        count = j;
140
141        apdu->lc = apdu->datalen = count;
142        apdu->data = buf;
143
144        return 0;
145}
146
147static int
148ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot)
149{
150        /* to be implemented */
151        return SC_ERROR_NOT_SUPPORTED;
152}
153
154int
155ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot,
156              struct sc_pin_cmd_data *data)
157{
158        sc_card_t dummy_card, *card;
159        sc_apdu_t apdu;
160        struct sc_card_operations ops;
161        int r, s;
162
163        switch (data->cmd) {
164        case SC_PIN_CMD_VERIFY:
165                r = ctbcs_build_perform_verification_apdu(&apdu, data, slot);
166                break;
167        case SC_PIN_CMD_CHANGE:
168        case SC_PIN_CMD_UNBLOCK:
169                r = ctbcs_build_modify_verification_apdu(&apdu, data, slot);
170                break;
171        default:
172                sc_error(reader->ctx, "Unknown PIN command %d", data->cmd);
173                return SC_ERROR_NOT_SUPPORTED;
174        }
175
176        memset(&ops, 0, sizeof(ops));
177        memset(&dummy_card, 0, sizeof(dummy_card));
178        dummy_card.reader = reader;
179        dummy_card.slot = slot;
180        dummy_card.ctx = reader->ctx;
181        r = sc_mutex_create(reader->ctx, &dummy_card.mutex);
182        if (r != SC_SUCCESS)
183                return r;
184        dummy_card.ops   = &ops;
185        card = &dummy_card;
186
187        r = sc_transmit_apdu(card, &apdu);
188        s = sc_mutex_destroy(reader->ctx, card->mutex);
189        if (s != SC_SUCCESS) {
190                sc_error(reader->ctx, "unable to destroy mutex\n");
191                return s;
192        }
193        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
194       
195        /* Check CTBCS status word */
196        switch (((unsigned int) apdu.sw1 << 8) | apdu.sw2) {
197        case 0x9000:
198                r = 0;
199                break;
200        case 0x6400: /* Input timed out */
201                r = SC_ERROR_KEYPAD_TIMEOUT;
202                break;
203        case 0x6401: /* Input cancelled */
204                r = SC_ERROR_KEYPAD_CANCELLED;
205                break;
206        case 0x6402: /* PINs did not match */
207                r = SC_ERROR_KEYPAD_PIN_MISMATCH;
208                break;
209        case 0x6700: /* message too long */
210                r = SC_ERROR_KEYPAD_MSG_TOO_LONG;
211                break;
212        default:
213                r = SC_ERROR_CARD_CMD_FAILED;
214                break;
215        }
216        SC_TEST_RET(card->ctx, r, "PIN command failed");
217
218        /* Calling Function may expect SW1/SW2 in data-apdu set... */
219        if (data->apdu) {
220                data->apdu->sw1 = apdu.sw1;
221                data->apdu->sw2 = apdu.sw2;
222        }
223
224        return 0;
225}
Note: See TracBrowser for help on using the browser.