/src/opensc/src/libopensc/card-nqApplet.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Support for the JCOP4 Cards with NQ-Applet |
3 | | * |
4 | | * Copyright (C) 2021 jozsefd <jozsef.dojcsak@gmail.com> |
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "opensc.h" |
25 | | #include "asn1.h" |
26 | | #include "cardctl.h" |
27 | | #include "internal.h" |
28 | | #include "log.h" |
29 | | |
30 | 0 | #define APPLET_VERSION_LEN 2 |
31 | 0 | #define APPLET_MEMTYPE_LEN 1 |
32 | 0 | #define APPLET_SERIALNR_LEN 8 |
33 | | |
34 | | /* card constants */ |
35 | | static const struct sc_atr_table nqapplet_atrs[] = { |
36 | | {"3b:d5:18:ff:81:91:fe:1f:c3:80:73:c8:21:10:0a", NULL, NULL, SC_CARD_TYPE_NQ_APPLET, 0, NULL}, |
37 | | {NULL, NULL, NULL, 0, 0, NULL}}; |
38 | | |
39 | | static const u8 nqapplet_aid[] = {0xd2, 0x76, 0x00, 0x01, 0x80, 0xBA, 0x01, 0x44, 0x02, 0x01, 0x00}; |
40 | | |
41 | | static struct sc_card_operations nqapplet_operations; |
42 | | static struct sc_card_operations *iso_operations = NULL; |
43 | | |
44 | 0 | #define KEY_REFERENCE_NO_KEY 0x00 |
45 | 0 | #define KEY_REFERENCE_AUTH_KEY 0x01 |
46 | 0 | #define KEY_REFERENCE_ENCR_KEY 0x02 |
47 | | |
48 | | struct nqapplet_driver_data { |
49 | | u8 version_minor; |
50 | | u8 version_major; |
51 | | u8 key_reference; |
52 | | }; |
53 | | typedef struct nqapplet_driver_data *nqapplet_driver_data_ptr; |
54 | | |
55 | | static struct sc_card_driver nqapplet_driver = { |
56 | | "NQ-Applet", // name |
57 | | "nqapplet", // short name |
58 | | &nqapplet_operations, // operations |
59 | | NULL, // atr table |
60 | | 0, // nr of atr |
61 | | NULL // dll? |
62 | | }; |
63 | | |
64 | | static const struct sc_card_error nqapplet_errors[] = { |
65 | | {0x6700, SC_ERROR_WRONG_LENGTH, "Invalid LC or LE"}, |
66 | | {0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied"}, // TODO MK/DK?? |
67 | | {0x6985, SC_ERROR_NOT_ALLOWED, "Invalid PIN or key"}, |
68 | | {0x6986, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied"}, |
69 | | {0x6A80, SC_ERROR_INVALID_ARGUMENTS, "Invalid parameters"}, |
70 | | {0x6A82, SC_ERROR_OBJECT_NOT_FOUND, "Data object not found"}, |
71 | | {0x6A84, SC_ERROR_NOT_ENOUGH_MEMORY, "Not enough memory"}, |
72 | | {0x6A86, SC_ERROR_INCORRECT_PARAMETERS, "Invalid P1 or P2"}, |
73 | | {0x6A88, SC_ERROR_INVALID_ARGUMENTS, "Wrong key ID"}, |
74 | | {0x6D00, SC_ERROR_FILE_NOT_FOUND, "Applet not found"}}; |
75 | | |
76 | | /* convenience functions */ |
77 | | |
78 | | static int init_driver_data(sc_card_t *card, u8 version_major, u8 version_minor) |
79 | 0 | { |
80 | 0 | nqapplet_driver_data_ptr data = calloc(1, sizeof(struct nqapplet_driver_data)); |
81 | 0 | if (data == NULL) { |
82 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
83 | 0 | } |
84 | | |
85 | 0 | data->version_major = version_major; |
86 | 0 | data->version_minor = version_minor; |
87 | 0 | data->key_reference = KEY_REFERENCE_NO_KEY; |
88 | 0 | card->drv_data = (void *)data; |
89 | 0 | return SC_SUCCESS; |
90 | 0 | } |
91 | | |
92 | | /** |
93 | | * SELECT NQ-Applet, on success it returns the applet version and card serial nr. |
94 | | * |
95 | | * @param[in] card |
96 | | * @param[out,opt] version_major Version major of the applet |
97 | | * @param[out,opt] version_minor Version minor of the applet |
98 | | * @param[out,opt] serial_nr Buffer to receive serial number octets |
99 | | * @param[in] cb_serial_nr Size of buffer in octets |
100 | | * @param[out,opt] serial_nr_len The actual number of octet copied into serial_nr buffer |
101 | | * |
102 | | * @return SC_SUCCESS: The applet is present and selected. |
103 | | * |
104 | | */ |
105 | | static int select_nqapplet(sc_card_t *card, u8 *version_major, u8 *version_minor, u8 *serial_nr, |
106 | | size_t cb_serial_nr, size_t *serial_nr_len) |
107 | 0 | { |
108 | 0 | int rv; |
109 | 0 | sc_context_t *ctx = card->ctx; |
110 | 0 | u8 buffer[APPLET_VERSION_LEN + APPLET_MEMTYPE_LEN + APPLET_SERIALNR_LEN + 2]; |
111 | 0 | size_t cb_buffer = sizeof(buffer); |
112 | 0 | size_t cb_aid = sizeof(nqapplet_aid); |
113 | |
|
114 | 0 | LOG_FUNC_CALLED(card->ctx); |
115 | |
|
116 | 0 | rv = iso7816_select_aid(card, nqapplet_aid, cb_aid, buffer, &cb_buffer); |
117 | 0 | LOG_TEST_RET(card->ctx, rv, "Failed to select NQ-Applet."); |
118 | | |
119 | 0 | if (cb_buffer < APPLET_VERSION_LEN + APPLET_MEMTYPE_LEN + APPLET_SERIALNR_LEN) { |
120 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_WRONG_LENGTH); |
121 | 0 | } |
122 | | |
123 | 0 | if (version_major != NULL) { |
124 | 0 | *version_major = buffer[0]; |
125 | 0 | } |
126 | 0 | if (version_minor != NULL) { |
127 | 0 | *version_minor = buffer[1]; |
128 | 0 | } |
129 | 0 | if (serial_nr != NULL && cb_serial_nr > 0 && serial_nr_len != NULL) { |
130 | 0 | size_t cb = MIN(APPLET_SERIALNR_LEN, cb_serial_nr); |
131 | 0 | memcpy(serial_nr, buffer + 3, cb); |
132 | 0 | *serial_nr_len = cb; |
133 | 0 | } |
134 | |
|
135 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
136 | 0 | } |
137 | | |
138 | | /* driver operations API */ |
139 | | static int nqapplet_match_card(struct sc_card *card) |
140 | 2.28k | { |
141 | 2.28k | int rv = _sc_match_atr(card, nqapplet_atrs, &card->type); |
142 | 2.28k | return (rv >= 0); |
143 | 2.28k | } |
144 | | |
145 | | static int nqapplet_init(struct sc_card *card) |
146 | 0 | { |
147 | 0 | u8 version_major; |
148 | 0 | u8 version_minor; |
149 | 0 | u8 serial_nr[APPLET_SERIALNR_LEN]; |
150 | 0 | size_t cb_serial_nr = sizeof(serial_nr); |
151 | 0 | unsigned long rsa_flags = 0; |
152 | |
|
153 | 0 | LOG_FUNC_CALLED(card->ctx); |
154 | 0 | int rv = |
155 | 0 | select_nqapplet(card, &version_major, &version_minor, serial_nr, cb_serial_nr, &cb_serial_nr); |
156 | 0 | if (rv != SC_SUCCESS) { |
157 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "Cannot select NQ-Applet."); |
158 | 0 | } |
159 | | |
160 | 0 | rv = init_driver_data(card, version_major, version_minor); |
161 | 0 | LOG_TEST_RET(card->ctx, rv, "Failed to initialize driver data."); |
162 | | |
163 | 0 | card->max_send_size = 255; |
164 | 0 | card->max_recv_size = 256; |
165 | 0 | card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO; |
166 | 0 | rsa_flags |= SC_ALGORITHM_RSA_RAW; |
167 | 0 | _sc_card_add_rsa_alg(card, 3072, rsa_flags, 0); |
168 | |
|
169 | 0 | card->serialnr.len = MIN(sizeof(card->serialnr.value), cb_serial_nr); |
170 | 0 | memcpy(card->serialnr.value, serial_nr, card->serialnr.len); |
171 | |
|
172 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
173 | 0 | } |
174 | | |
175 | | static int nqapplet_finish(struct sc_card *card) |
176 | 0 | { |
177 | 0 | nqapplet_driver_data_ptr data = (nqapplet_driver_data_ptr)card->drv_data; |
178 | |
|
179 | 0 | LOG_FUNC_CALLED(card->ctx); |
180 | 0 | if (data != NULL) { |
181 | 0 | free(data); |
182 | 0 | card->drv_data = NULL; |
183 | 0 | } |
184 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
185 | 0 | } |
186 | | |
187 | | static int |
188 | | nqapplet_get_response(struct sc_card *card, size_t *cb_resp, u8 *resp) |
189 | 0 | { |
190 | 0 | struct sc_apdu apdu = {0}; |
191 | 0 | int rv; |
192 | 0 | size_t resplen; |
193 | |
|
194 | 0 | LOG_FUNC_CALLED(card->ctx); |
195 | 0 | resplen = MIN(sc_get_max_recv_size(card), *cb_resp); |
196 | |
|
197 | 0 | sc_format_apdu_ex(&apdu, 0x80, 0xC0, 0x00, 0x00, NULL, 0, resp, resplen); |
198 | 0 | apdu.flags |= SC_APDU_FLAGS_NO_GET_RESP; |
199 | |
|
200 | 0 | rv = sc_transmit_apdu(card, &apdu); |
201 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
202 | | |
203 | 0 | *cb_resp = apdu.resplen; |
204 | |
|
205 | 0 | if (apdu.resplen == 0) { |
206 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
207 | 0 | } |
208 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
209 | 0 | rv = SC_SUCCESS; |
210 | 0 | } else if (apdu.sw1 == 0x61) { |
211 | 0 | rv = apdu.sw2 == 0 ? 256 : apdu.sw2; |
212 | 0 | } else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x82) { |
213 | 0 | rv = sc_check_sw(card, apdu.sw1, apdu.sw2); |
214 | 0 | } |
215 | |
|
216 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
217 | 0 | } |
218 | | |
219 | | static int nqapplet_get_challenge(struct sc_card *card, u8 *buf, size_t count) |
220 | 0 | { |
221 | 0 | int r; |
222 | 0 | struct sc_apdu apdu; |
223 | |
|
224 | 0 | LOG_FUNC_CALLED(card->ctx); |
225 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x00); |
226 | 0 | apdu.le = count; |
227 | 0 | apdu.resp = buf; |
228 | 0 | apdu.resplen = count; |
229 | |
|
230 | 0 | r = sc_transmit_apdu(card, &apdu); |
231 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
232 | | |
233 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
234 | 0 | LOG_TEST_RET(card->ctx, r, "GET CHALLENGE failed"); |
235 | | |
236 | 0 | if (count < apdu.resplen) { |
237 | 0 | return (int)count; |
238 | 0 | } |
239 | | |
240 | 0 | return (int)apdu.resplen; |
241 | 0 | } |
242 | | |
243 | | static int nqapplet_logout(struct sc_card *card) |
244 | 0 | { |
245 | 0 | LOG_FUNC_CALLED(card->ctx); |
246 | | /* selecting NQ-Applet again will reset the applet status and unauthorize PINs */ |
247 | 0 | int rv = select_nqapplet(card, NULL, NULL, NULL, 0, NULL); |
248 | 0 | if (rv != SC_SUCCESS) { |
249 | 0 | LOG_TEST_RET(card->ctx, rv, "Failed to logout"); |
250 | 0 | } |
251 | | |
252 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
253 | 0 | } |
254 | | |
255 | | int nqapplet_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num) |
256 | 0 | { |
257 | | /* Note: the NQ-Applet does not have APDU for SET SECURITY ENV, |
258 | | this function checks the intended parameters and sets card_data.key_reference */ |
259 | 0 | nqapplet_driver_data_ptr data; |
260 | 0 | u8 key_reference = KEY_REFERENCE_NO_KEY; |
261 | |
|
262 | 0 | LOG_FUNC_CALLED(card->ctx); |
263 | |
|
264 | 0 | data = (nqapplet_driver_data_ptr)card->drv_data; |
265 | 0 | data->key_reference = KEY_REFERENCE_NO_KEY; |
266 | |
|
267 | 0 | if (se_num != 0) { |
268 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, |
269 | 0 | "Storing of security environment is not supported"); |
270 | 0 | } |
271 | 0 | if (env->key_ref_len == 1) { |
272 | 0 | key_reference = env->key_ref[0]; |
273 | 0 | } |
274 | |
|
275 | 0 | switch (env->operation) { |
276 | 0 | case SC_SEC_OPERATION_DECIPHER: |
277 | 0 | if (key_reference != KEY_REFERENCE_AUTH_KEY && key_reference != KEY_REFERENCE_ENCR_KEY) { |
278 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, |
279 | 0 | "Decipher operation is only supported with AUTH and ENCR keys."); |
280 | 0 | } |
281 | 0 | data->key_reference = key_reference; |
282 | 0 | break; |
283 | 0 | case SC_SEC_OPERATION_SIGN: |
284 | 0 | if (key_reference != KEY_REFERENCE_AUTH_KEY) { |
285 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, |
286 | 0 | "Sign operation is only supported with AUTH key."); |
287 | 0 | } |
288 | 0 | data->key_reference = key_reference; |
289 | 0 | break; |
290 | 0 | default: |
291 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported sec. operation."); |
292 | 0 | } |
293 | | |
294 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
295 | 0 | } |
296 | | |
297 | | static int nqapplet_decipher(struct sc_card *card, const u8 *data, size_t cb_data, u8 *out, size_t outlen) |
298 | 0 | { |
299 | 0 | int rv; |
300 | 0 | struct sc_apdu apdu; |
301 | 0 | u8 p1 = 0x80; |
302 | 0 | u8 p2 = 0x86; |
303 | 0 | nqapplet_driver_data_ptr drv_data; |
304 | |
|
305 | 0 | LOG_FUNC_CALLED(card->ctx); |
306 | |
|
307 | 0 | drv_data = (nqapplet_driver_data_ptr)card->drv_data; |
308 | |
|
309 | 0 | if (drv_data->key_reference == KEY_REFERENCE_AUTH_KEY) { |
310 | 0 | p1 = 0x9E; |
311 | 0 | p2 = 0x9A; |
312 | 0 | } else if (drv_data->key_reference != KEY_REFERENCE_ENCR_KEY) { |
313 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, |
314 | 0 | "Decipher operation is only supported with AUTH and ENCR keys."); |
315 | 0 | } |
316 | | |
317 | | /* the applet supports only 3072 RAW RSA, input buffer size must be 384 octets, |
318 | | output buffer size must be at least 384 octets */ |
319 | 0 | sc_format_apdu_ex(&apdu, 0x80, 0x2A, p1, p2, data, cb_data, out, outlen); |
320 | 0 | apdu.le = 256; |
321 | 0 | apdu.flags |= SC_APDU_FLAGS_CHAINING; |
322 | 0 | rv = sc_transmit_apdu(card, &apdu); |
323 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
324 | | |
325 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
326 | 0 | rv = (int)apdu.resplen; |
327 | 0 | } else if (apdu.sw1 == 0x61) { |
328 | 0 | rv = apdu.sw2 == 0 ? 256 : apdu.sw2; |
329 | 0 | } else { |
330 | 0 | rv = sc_check_sw(card, apdu.sw1, apdu.sw2); |
331 | 0 | } |
332 | |
|
333 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
334 | 0 | } |
335 | | |
336 | | static int nqapplet_compute_signature(struct sc_card *card, const u8 *data, size_t cb_data, u8 *out, |
337 | | size_t outlen) |
338 | 0 | { |
339 | 0 | int rv; |
340 | 0 | struct sc_apdu apdu; |
341 | 0 | nqapplet_driver_data_ptr drv_data; |
342 | |
|
343 | 0 | LOG_FUNC_CALLED(card->ctx); |
344 | 0 | drv_data = (nqapplet_driver_data_ptr)card->drv_data; |
345 | |
|
346 | 0 | if (drv_data->key_reference != KEY_REFERENCE_AUTH_KEY) { |
347 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, |
348 | 0 | "Sign operation is only supported with AUTH key."); |
349 | 0 | } |
350 | | |
351 | | /* the applet supports only 3072 RAW RSA, input buffer size must be 384 octets, |
352 | | output buffer size must be at least 384 octets */ |
353 | 0 | sc_format_apdu_ex(&apdu, 0x80, 0x2A, 0x9E, 0x9A, data, cb_data, out, outlen); |
354 | 0 | apdu.le = 256; |
355 | 0 | apdu.flags |= SC_APDU_FLAGS_CHAINING; |
356 | 0 | rv = sc_transmit_apdu(card, &apdu); |
357 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
358 | | |
359 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
360 | 0 | rv = (int)apdu.resplen; |
361 | 0 | } else if (apdu.sw1 == 0x61) { |
362 | 0 | rv = apdu.sw2 == 0 ? 256 : apdu.sw2; |
363 | 0 | } else { |
364 | 0 | rv = sc_check_sw(card, apdu.sw1, apdu.sw2); |
365 | 0 | } |
366 | |
|
367 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
368 | 0 | } |
369 | | |
370 | | static int nqapplet_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2) |
371 | 0 | { |
372 | 0 | const int nqapplet_error_count = sizeof(nqapplet_errors) / sizeof(struct sc_card_error); |
373 | 0 | int i; |
374 | |
|
375 | 0 | LOG_FUNC_CALLED(card->ctx); |
376 | 0 | sc_log(card->ctx, "Checking sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2); |
377 | |
|
378 | 0 | for (i = 0; i < nqapplet_error_count; i++) { |
379 | 0 | if (nqapplet_errors[i].SWs == ((sw1 << 8) | sw2)) { |
380 | 0 | LOG_TEST_RET(card->ctx, nqapplet_errors[i].errorno, nqapplet_errors[i].errorstr); |
381 | 0 | } |
382 | 0 | } |
383 | | |
384 | 0 | return iso_operations->check_sw(card, sw1, sw2); |
385 | 0 | } |
386 | | |
387 | | static int nqapplet_get_data(struct sc_card *card, unsigned int id, u8 *resp, size_t cb_resp) |
388 | 0 | { |
389 | 0 | struct sc_apdu apdu; |
390 | 0 | int rv; |
391 | |
|
392 | 0 | LOG_FUNC_CALLED(card->ctx); |
393 | |
|
394 | 0 | sc_format_apdu_ex(&apdu, 0x80, 0xB0, 0x00, (u8)id, NULL, 0, resp, cb_resp); |
395 | 0 | apdu.le = 256; |
396 | |
|
397 | 0 | rv = sc_transmit_apdu(card, &apdu); |
398 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
399 | | |
400 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
401 | 0 | rv = (int)apdu.resplen; |
402 | 0 | } else if (apdu.sw1 == 0x61) { |
403 | 0 | rv = apdu.sw2 == 0 ? 256 : apdu.sw2; |
404 | 0 | } else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x82) { |
405 | 0 | rv = sc_check_sw(card, apdu.sw1, apdu.sw2); |
406 | 0 | } |
407 | |
|
408 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
409 | 0 | } |
410 | | |
411 | | static int nqapplet_select_file(struct sc_card *card, const struct sc_path *in_path, |
412 | | struct sc_file **file_out) |
413 | 0 | { |
414 | 0 | LOG_FUNC_CALLED(card->ctx); |
415 | | |
416 | | /* the applet does not support SELECT EF/DF except for SELECT APPLET. |
417 | | In order to enable opensc-explorer add support for virtually selecting MF only */ |
418 | 0 | if (in_path->type == SC_PATH_TYPE_PATH && in_path->len == 2 && |
419 | 0 | memcmp(in_path->value, "\x3F\x00", 2) == 0) { |
420 | 0 | if (file_out != NULL) { |
421 | 0 | struct sc_file *file = sc_file_new(); |
422 | 0 | if (file == NULL) { |
423 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
424 | 0 | } |
425 | 0 | file->path = *in_path; |
426 | 0 | *file_out = file; |
427 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
428 | 0 | } |
429 | 0 | } |
430 | | // TODO allow selecting Applet AID |
431 | | |
432 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
433 | 0 | } |
434 | | |
435 | | static int nqapplet_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) |
436 | 0 | { |
437 | 0 | switch (cmd) { |
438 | 0 | case SC_CARDCTL_GET_SERIALNR: |
439 | 0 | if (card->serialnr.len) { |
440 | 0 | sc_serial_number_t *serial = (sc_serial_number_t *)ptr; |
441 | 0 | memcpy(serial->value, card->serialnr.value, card->serialnr.len); |
442 | 0 | serial->len = card->serialnr.len; |
443 | 0 | return SC_SUCCESS; |
444 | 0 | } |
445 | 0 | break; |
446 | 0 | } |
447 | 0 | return SC_ERROR_NOT_SUPPORTED; |
448 | 0 | } |
449 | | |
450 | | struct sc_card_driver *sc_get_nqApplet_driver(void) |
451 | 13.8k | { |
452 | 13.8k | sc_card_driver_t *iso_driver = sc_get_iso7816_driver(); |
453 | | |
454 | 13.8k | if (iso_operations == NULL) { |
455 | 1 | iso_operations = iso_driver->ops; |
456 | 1 | } |
457 | | |
458 | 13.8k | nqapplet_operations = *iso_driver->ops; |
459 | | |
460 | | /* supported operations */ |
461 | 13.8k | nqapplet_operations.match_card = nqapplet_match_card; |
462 | 13.8k | nqapplet_operations.init = nqapplet_init; |
463 | 13.8k | nqapplet_operations.finish = nqapplet_finish; |
464 | 13.8k | nqapplet_operations.get_response = nqapplet_get_response; |
465 | 13.8k | nqapplet_operations.get_challenge = nqapplet_get_challenge; |
466 | 13.8k | nqapplet_operations.logout = nqapplet_logout; |
467 | 13.8k | nqapplet_operations.set_security_env = nqapplet_set_security_env; |
468 | 13.8k | nqapplet_operations.decipher = nqapplet_decipher; |
469 | 13.8k | nqapplet_operations.compute_signature = nqapplet_compute_signature; |
470 | 13.8k | nqapplet_operations.check_sw = nqapplet_check_sw; |
471 | 13.8k | nqapplet_operations.get_data = nqapplet_get_data; |
472 | 13.8k | nqapplet_operations.select_file = nqapplet_select_file; |
473 | 13.8k | nqapplet_operations.card_ctl = nqapplet_card_ctl; |
474 | | |
475 | | /* unsupported operations */ |
476 | 13.8k | nqapplet_operations.read_binary = NULL; |
477 | 13.8k | nqapplet_operations.write_binary = NULL; |
478 | 13.8k | nqapplet_operations.update_binary = NULL; |
479 | 13.8k | nqapplet_operations.erase_binary = NULL; |
480 | 13.8k | nqapplet_operations.read_record = NULL; |
481 | 13.8k | nqapplet_operations.write_record = NULL; |
482 | 13.8k | nqapplet_operations.append_record = NULL; |
483 | 13.8k | nqapplet_operations.update_record = NULL; |
484 | | |
485 | 13.8k | nqapplet_operations.verify = NULL; |
486 | 13.8k | nqapplet_operations.restore_security_env = NULL; |
487 | 13.8k | nqapplet_operations.change_reference_data = NULL; |
488 | 13.8k | nqapplet_operations.reset_retry_counter = NULL; |
489 | 13.8k | nqapplet_operations.create_file = NULL; |
490 | 13.8k | nqapplet_operations.delete_file = NULL; |
491 | 13.8k | nqapplet_operations.list_files = NULL; |
492 | 13.8k | nqapplet_operations.process_fci = NULL; |
493 | 13.8k | nqapplet_operations.construct_fci = NULL; |
494 | 13.8k | nqapplet_operations.put_data = NULL; |
495 | 13.8k | nqapplet_operations.delete_record = NULL; |
496 | 13.8k | nqapplet_operations.read_public_key = NULL; |
497 | | |
498 | | /* let iso driver handle these operations |
499 | | nqapplet_operations.pin_cmd; |
500 | | nqapplet_operations.card_reader_lock_obtained; |
501 | | nqapplet_operations.wrap; |
502 | | nqapplet_operations.unwrap; |
503 | | */ |
504 | | |
505 | 13.8k | return &nqapplet_driver; |
506 | 13.8k | } |