| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | #include "internal.h" |
|---|
| 22 | #include "ctbcs.h" |
|---|
| 23 | #include <assert.h> |
|---|
| 24 | #include <stdlib.h> |
|---|
| 25 | #include <string.h> |
|---|
| 26 | |
|---|
| 27 | static void |
|---|
| 28 | ctbcs_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 |
|---|
| 41 | static int |
|---|
| 42 | ctbcs_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 | |
|---|
| 61 | static int |
|---|
| 62 | ctbcs_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 | |
|---|
| 79 | static int |
|---|
| 80 | ctbcs_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 | |
|---|
| 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 | |
|---|
| 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; |
|---|
| 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 | |
|---|
| 147 | static int |
|---|
| 148 | ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot) |
|---|
| 149 | { |
|---|
| 150 | |
|---|
| 151 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | int |
|---|
| 155 | ctbcs_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 | |
|---|
| 196 | switch (((unsigned int) apdu.sw1 << 8) | apdu.sw2) { |
|---|
| 197 | case 0x9000: |
|---|
| 198 | r = 0; |
|---|
| 199 | break; |
|---|
| 200 | case 0x6400: |
|---|
| 201 | r = SC_ERROR_KEYPAD_TIMEOUT; |
|---|
| 202 | break; |
|---|
| 203 | case 0x6401: |
|---|
| 204 | r = SC_ERROR_KEYPAD_CANCELLED; |
|---|
| 205 | break; |
|---|
| 206 | case 0x6402: |
|---|
| 207 | r = SC_ERROR_KEYPAD_PIN_MISMATCH; |
|---|
| 208 | break; |
|---|
| 209 | case 0x6700: |
|---|
| 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 | |
|---|
| 219 | if (data->apdu) { |
|---|
| 220 | data->apdu->sw1 = apdu.sw1; |
|---|
| 221 | data->apdu->sw2 = apdu.sw2; |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | return 0; |
|---|
| 225 | } |
|---|