/src/opensc/src/libopensc/card-masktech.c
Line | Count | Source |
1 | | /* |
2 | | * card-masktech.c: Support for Masktech smart cards using the MTCOS operating system. |
3 | | * |
4 | | * Copyright (C) 2011-2015 MaskTech GmbH Fischerstrasse 19, 87435 Kempten, Germany |
5 | | * Copyright (C) 2011 Andrey Uvarov (X-Infotech) <andrejs.uvarovs@x-infotech.com> |
6 | | * Copyright (C) 2015 Vincent Le Toux (My Smart Logon) <vincent.letoux@mysmartlogon.com> |
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | #ifdef HAVE_CONFIG_H |
24 | | #include "config.h" |
25 | | #endif |
26 | | |
27 | | #include <stdlib.h> |
28 | | #include <string.h> |
29 | | |
30 | | #include "internal.h" |
31 | | #include "cardctl.h" |
32 | | #include "iso7816.h" |
33 | | |
34 | | static struct sc_atr_table masktech_atrs[] = { |
35 | | {"3B:89:80:01:4D:54:43:4F:53:70:02:00:04:31", |
36 | | "FF:FF:FF:FF:FF:FF:FF:FF:FF:FC:FF:FC:F4:F5" , NULL, |
37 | | SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, |
38 | | {"3B:88:80:01:00:00:00:00:77:81:80:00:6E", "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:EE:FF:EE", NULL, |
39 | | SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, |
40 | | {"3B:9D:13:81:31:60:35:80:31:C0:69:4D:54:43:4F:53:73:02:00:00:40", |
41 | | "FF:FF:FF:FF:FF:FF:FD:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FC:F0:F0", NULL, |
42 | | SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL}, |
43 | | {NULL, NULL, NULL, 0, 0, NULL} |
44 | | }; |
45 | | |
46 | | static struct sc_card_operations *iso_ops; |
47 | | static struct sc_card_operations masktech_ops; |
48 | | static struct sc_card_driver masktech_drv = { |
49 | | "MaskTech Smart Card", |
50 | | "MaskTech", |
51 | | &masktech_ops, |
52 | | masktech_atrs, 0, NULL |
53 | | }; |
54 | | |
55 | | struct masktech_private_data { |
56 | | /* save the key reference set at set_masktech_set_security_env to recover it as the signature step */ |
57 | | int rsa_key_ref; |
58 | | |
59 | | }; |
60 | | |
61 | | static int masktech_match_card(sc_card_t * card) |
62 | 7.98k | { |
63 | | /* check if the ATR is in the known ATR */ |
64 | 7.98k | if (_sc_match_atr(card, masktech_atrs, &card->type) < 0) |
65 | 7.96k | return 0; |
66 | | |
67 | 21 | return 1; |
68 | 7.98k | } |
69 | | |
70 | | static int masktech_init(sc_card_t * card) |
71 | 21 | { |
72 | 21 | unsigned long flags; |
73 | 21 | struct masktech_private_data *data; |
74 | | |
75 | 21 | sc_log(card->ctx, "masktech_init()\n"); |
76 | | |
77 | | /* private data kept during the live of the driver */ |
78 | 21 | if (!(data = (struct masktech_private_data *) malloc(sizeof(*data)))) |
79 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
80 | 21 | card->drv_data = data; |
81 | | |
82 | | /* supported RSA keys and how padding is done */ |
83 | 21 | flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; |
84 | 21 | _sc_card_add_rsa_alg(card, 1024, flags, 0); |
85 | 21 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
86 | 21 | _sc_card_add_rsa_alg(card, 3072, flags, 0); |
87 | 21 | card->caps |= SC_CARD_CAP_APDU_EXT; |
88 | 21 | return SC_SUCCESS; |
89 | 21 | } |
90 | | |
91 | | |
92 | | static int masktech_finish(sc_card_t *card) |
93 | 21 | { |
94 | | /* free the private data */ |
95 | 21 | if (card->drv_data) { |
96 | 21 | free(card->drv_data); |
97 | 21 | card->drv_data = NULL; |
98 | 21 | } |
99 | 21 | return 0; |
100 | 21 | } |
101 | | |
102 | | static int masktech_set_security_env(sc_card_t *card, |
103 | | const sc_security_env_t *env, |
104 | | int se_num) |
105 | 0 | { |
106 | 0 | struct masktech_private_data *private_data; |
107 | 0 | sc_log(card->ctx, "masktech_set_security_env(), keyRef = 0x%0x, algo = 0x%0lx\n", |
108 | 0 | *env->key_ref, env->algorithm_flags); |
109 | |
|
110 | 0 | private_data = (struct masktech_private_data *) card->drv_data; |
111 | 0 | if (!private_data) |
112 | 0 | return SC_ERROR_INTERNAL; |
113 | | |
114 | | /* save the key reference */ |
115 | 0 | if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { |
116 | 0 | if (env->key_ref_len != 1) { |
117 | 0 | sc_log(card->ctx, "Invalid key reference supplied.\n"); |
118 | 0 | return SC_ERROR_NOT_SUPPORTED; |
119 | 0 | } |
120 | 0 | private_data->rsa_key_ref = env->key_ref[0]; |
121 | 0 | } |
122 | | |
123 | 0 | return iso_ops->set_security_env(card, env, se_num); |
124 | 0 | } |
125 | | |
126 | | static int masktech_compute_signature(sc_card_t *card, |
127 | | const u8 * data, |
128 | | size_t datalen, |
129 | | u8 * out, |
130 | | size_t outlen) |
131 | 0 | { |
132 | |
|
133 | 0 | struct masktech_private_data *private_data; |
134 | 0 | u8 sha256hash[32]; |
135 | 0 | static const u8 hdr_sha256[] = { |
136 | 0 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, |
137 | 0 | 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 |
138 | 0 | }; |
139 | 0 | assert(card != NULL && data != NULL && out != NULL); |
140 | 0 | sc_log(card->ctx, "masktech_compute_signature()\n"); |
141 | | |
142 | | /* retrieve the key reference */ |
143 | 0 | private_data = (struct masktech_private_data *) card->drv_data; |
144 | 0 | if (!private_data) |
145 | 0 | return SC_ERROR_INTERNAL; |
146 | | |
147 | 0 | if (private_data->rsa_key_ref == 0x88) |
148 | 0 | { |
149 | | /* for this key reference, the card supports only SHA256 hash and the hash is computed using a digest info */ |
150 | | /* check that it is a SHA256 with digest info*/ |
151 | 0 | if ((datalen != sizeof(hdr_sha256) + 32) || (memcmp(hdr_sha256, data, sizeof(hdr_sha256)) != 0)) |
152 | 0 | { |
153 | 0 | sc_log(card->ctx, "It is not a SHA256 with digestinfo\n"); |
154 | 0 | return SC_ERROR_NOT_SUPPORTED; |
155 | 0 | } |
156 | | /* extract the SHA-256 hash */ |
157 | 0 | memcpy(sha256hash, (u8 *)(data+(datalen-32)), 32);//only last 32 byte => sha256 |
158 | | /* default ISO 7816 functions */ |
159 | 0 | return iso_ops->compute_signature(card, sha256hash, 32, out, outlen); |
160 | 0 | } |
161 | 0 | else |
162 | 0 | { |
163 | | /* default ISO 7816 functions */ |
164 | 0 | return iso_ops->compute_signature(card, data, datalen, out, outlen); |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | | static int masktech_decipher(sc_card_t *card, |
169 | | const u8 * crgram, |
170 | | size_t crgram_len, |
171 | | u8 * out, |
172 | | size_t outlen) |
173 | 0 | { |
174 | 0 | int r; |
175 | 0 | sc_apdu_t apdu; |
176 | 0 | u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; |
177 | |
|
178 | 0 | assert(card != NULL && crgram != NULL && out != NULL); |
179 | 0 | sc_log(card->ctx, "masktech_decipher()\n"); |
180 | |
|
181 | 0 | if (crgram_len > SC_MAX_EXT_APDU_BUFFER_SIZE) { |
182 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
183 | 0 | } |
184 | | |
185 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); |
186 | 0 | apdu.resp = rbuf; |
187 | 0 | apdu.resplen = sizeof(rbuf); |
188 | | /* the card doesn't support anything else here (+1 / -1 is not working) */ |
189 | 0 | apdu.le = 65536; |
190 | |
|
191 | 0 | apdu.data = crgram; |
192 | 0 | apdu.lc = crgram_len; |
193 | 0 | apdu.datalen = crgram_len; |
194 | |
|
195 | 0 | r = sc_transmit_apdu(card, &apdu); |
196 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
197 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
198 | 0 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
199 | |
|
200 | 0 | memcpy(out, apdu.resp, len); |
201 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len); |
202 | 0 | } |
203 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
204 | 0 | } |
205 | | |
206 | | /* unblock pin cmd */ |
207 | | static int masktech_pin_unblock(sc_card_t *card, |
208 | | struct sc_pin_cmd_data *data, |
209 | | int *tries_left) |
210 | 0 | { |
211 | 0 | int rv = 0; |
212 | 0 | struct sc_pin_cmd_data verify_data; |
213 | 0 | struct sc_pin_cmd_data reset_data; |
214 | | |
215 | | /* Build a SC_PIN_CMD_VERIFY APDU on PUK */ |
216 | 0 | memset(&verify_data, 0, sizeof(verify_data)); |
217 | 0 | verify_data.cmd = SC_PIN_CMD_VERIFY; |
218 | 0 | verify_data.pin_type = 1; |
219 | 0 | verify_data.pin_reference = 0x83; |
220 | 0 | verify_data.pin1 = data->pin1; |
221 | 0 | verify_data.flags = data->flags; |
222 | 0 | verify_data.pin1.prompt = data->pin1.prompt; |
223 | |
|
224 | 0 | rv = iso_ops->pin_cmd(card, &verify_data, tries_left); |
225 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed - verify unblock PIN"); |
226 | | |
227 | | /* Build a SC_PIN_CMD_UNBLOCK APDU */ |
228 | 0 | memset(&reset_data, 0, sizeof(reset_data)); |
229 | 0 | reset_data.cmd = SC_PIN_CMD_UNBLOCK; |
230 | 0 | reset_data.pin_type = 1; |
231 | 0 | reset_data.pin_reference = 0x91; |
232 | | /* pin1 is set to null on purpose and flag set to implicit change |
233 | | => if there is a pinpad reader, do not ask for pin1 */ |
234 | 0 | reset_data.pin2 = data->pin2; |
235 | 0 | reset_data.flags = data->flags | SC_PIN_CMD_IMPLICIT_CHANGE; |
236 | 0 | reset_data.pin2.prompt = data->pin2.prompt; |
237 | |
|
238 | 0 | rv = iso_ops->pin_cmd(card, &reset_data, tries_left); |
239 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed - reset unblock PIN"); |
240 | | |
241 | 0 | return 0; |
242 | 0 | } |
243 | | |
244 | | static int masktech_pin_change(sc_card_t *card, |
245 | | struct sc_pin_cmd_data *data, |
246 | | int *tries_left) |
247 | 0 | { |
248 | 0 | int rv = 0; |
249 | 0 | struct sc_pin_cmd_data verify_data; |
250 | 0 | struct sc_pin_cmd_data change_data; |
251 | | |
252 | | /* Build a SC_PIN_CMD_VERIFY APDU */ |
253 | 0 | memset(&verify_data, 0, sizeof(verify_data)); |
254 | 0 | verify_data.cmd = SC_PIN_CMD_VERIFY; |
255 | 0 | verify_data.pin_type = 1; |
256 | 0 | verify_data.pin_reference = data->pin_reference; |
257 | 0 | verify_data.pin1 = data->pin1; |
258 | 0 | verify_data.flags = data->flags; |
259 | 0 | verify_data.pin1.prompt = data->pin1.prompt; |
260 | |
|
261 | 0 | rv = iso_ops->pin_cmd(card, &verify_data, tries_left); |
262 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed - verify change PIN"); |
263 | | |
264 | | /* Build a SC_PIN_CMD_CHANGE APDU */ |
265 | 0 | memset(&change_data, 0, sizeof(change_data)); |
266 | 0 | change_data.cmd = SC_PIN_CMD_CHANGE; |
267 | 0 | change_data.pin_type = 1; |
268 | 0 | change_data.pin_reference = data->pin_reference; |
269 | | /* pin1 is set to null on purpose and flag set to implicit change |
270 | | => if there is a pinpad reader, do not ask for pin1 */ |
271 | 0 | change_data.pin2 = data->pin2; |
272 | 0 | change_data.flags = data->flags | SC_PIN_CMD_IMPLICIT_CHANGE; |
273 | 0 | change_data.pin2.prompt = data->pin2.prompt; |
274 | |
|
275 | 0 | rv = iso_ops->pin_cmd(card, &change_data, tries_left); |
276 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed - change PIN"); |
277 | | |
278 | 0 | return 0; |
279 | 0 | } |
280 | | |
281 | | static int masktech_pin_cmd(sc_card_t *card, |
282 | | struct sc_pin_cmd_data *data, |
283 | | int *tries_left) |
284 | 19 | { |
285 | 19 | int rv; |
286 | 19 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
287 | | |
288 | 19 | switch(data->cmd) |
289 | 19 | { |
290 | 0 | case SC_PIN_CMD_UNBLOCK: |
291 | 0 | rv = masktech_pin_unblock(card, data, tries_left); |
292 | 0 | break; |
293 | 0 | case SC_PIN_CMD_CHANGE: |
294 | 0 | rv = masktech_pin_change(card, data, tries_left); |
295 | 0 | break; |
296 | 19 | default: |
297 | 19 | rv = iso_ops->pin_cmd(card, data, tries_left); |
298 | 19 | break; |
299 | 19 | } |
300 | 19 | return rv; |
301 | | |
302 | | |
303 | 19 | } |
304 | | |
305 | | static int masktech_get_serialnr(sc_card_t * card, sc_serial_number_t * serial) |
306 | 19 | { |
307 | 19 | struct sc_apdu apdu; |
308 | 19 | unsigned char apdu_resp[SC_MAX_APDU_BUFFER_SIZE-2]; |
309 | 19 | int rv; |
310 | | |
311 | 19 | if (!serial) |
312 | 19 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
313 | | |
314 | | /* Get smart card serial number */ |
315 | 19 | card->cla = 0x80; |
316 | 19 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x08, 0x00, 0x00); |
317 | 19 | apdu.resplen = sizeof(apdu_resp); |
318 | 19 | apdu.resp = apdu_resp; |
319 | | |
320 | 19 | rv = sc_transmit_apdu(card, &apdu); |
321 | 19 | card->cla = 0x00; |
322 | | |
323 | 19 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
324 | | |
325 | 18 | if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) |
326 | 11 | return SC_ERROR_INTERNAL; |
327 | | |
328 | 7 | if (SC_MAX_SERIALNR < apdu.resplen) |
329 | 1 | { |
330 | 1 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
331 | 1 | } |
332 | | /* cache serial number */ |
333 | 6 | card->serialnr.len = apdu.resplen; |
334 | 6 | memcpy(card->serialnr.value, apdu.resp, card->serialnr.len); |
335 | | |
336 | | /* copy and return serial number */ |
337 | 6 | if (serial) |
338 | 6 | memcpy(serial, &card->serialnr, sizeof(*serial)); |
339 | | |
340 | 6 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
341 | 6 | } |
342 | | |
343 | | |
344 | | static int masktech_card_ctl(sc_card_t * card, unsigned long cmd, void *ptr) |
345 | 19 | { |
346 | 19 | sc_log(card->ctx, "masktech_card_ctl()\n"); |
347 | 19 | switch (cmd) { |
348 | 19 | case SC_CARDCTL_GET_SERIALNR: |
349 | 19 | return masktech_get_serialnr(card, (sc_serial_number_t *) ptr); |
350 | 0 | default: |
351 | 0 | return SC_ERROR_NOT_SUPPORTED; |
352 | 19 | } |
353 | 19 | } |
354 | | |
355 | | static struct sc_card_driver *sc_get_driver(void) |
356 | 16.0k | { |
357 | | |
358 | 16.0k | if (iso_ops == NULL) |
359 | 1 | iso_ops = sc_get_iso7816_driver()->ops; |
360 | | |
361 | 16.0k | masktech_ops = *iso_ops; |
362 | | |
363 | 16.0k | masktech_ops.match_card = masktech_match_card; |
364 | 16.0k | masktech_ops.init = masktech_init; |
365 | 16.0k | masktech_ops.finish = masktech_finish; |
366 | 16.0k | masktech_ops.set_security_env = masktech_set_security_env; |
367 | 16.0k | masktech_ops.compute_signature = masktech_compute_signature; |
368 | 16.0k | masktech_ops.decipher = masktech_decipher; |
369 | 16.0k | masktech_ops.pin_cmd = masktech_pin_cmd; |
370 | 16.0k | masktech_ops.card_ctl = masktech_card_ctl; |
371 | 16.0k | return &masktech_drv; |
372 | 16.0k | } |
373 | | |
374 | | struct sc_card_driver *sc_get_masktech_driver(void) |
375 | 16.0k | { |
376 | 16.0k | return sc_get_driver(); |
377 | 16.0k | } |