/src/opensc/src/libopensc/card-jpki.c
Line | Count | Source |
1 | | /* |
2 | | * card-jpki.c: Support for JPKI(Japanese Individual Number Cards). |
3 | | * |
4 | | * Copyright (C) 2016, HAMANO Tsukasa <hamano@osstech.co.jp> |
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 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <string.h> |
26 | | #include <stdlib.h> |
27 | | |
28 | | #include "internal.h" |
29 | | #include "jpki.h" |
30 | | |
31 | | static const struct sc_atr_table jpki_atrs[] = { |
32 | | {"3b:e0:00:ff:81:31:fe:45:14", NULL, NULL, |
33 | | SC_CARD_TYPE_JPKI_BASE, 0, NULL}, |
34 | | {NULL, NULL, NULL, 0, 0, NULL} |
35 | | }; |
36 | | |
37 | | static struct sc_card_operations jpki_ops; |
38 | | static struct sc_card_driver jpki_drv = { |
39 | | "JPKI(Japanese Individual Number Cards)", |
40 | | "jpki", |
41 | | &jpki_ops, |
42 | | NULL, 0, NULL |
43 | | }; |
44 | | |
45 | | int jpki_select_ap(struct sc_card *card) |
46 | 2.42k | { |
47 | 2.42k | int rc; |
48 | 2.42k | sc_path_t path; |
49 | | |
50 | 2.42k | LOG_FUNC_CALLED(card->ctx); |
51 | | |
52 | | /* Select JPKI application */ |
53 | 2.42k | sc_format_path(AID_JPKI, &path); |
54 | 2.42k | path.type = SC_PATH_TYPE_DF_NAME; |
55 | 2.42k | rc = sc_select_file(card, &path, NULL); |
56 | 2.42k | LOG_TEST_RET(card->ctx, rc, "select JPKI AP failed"); |
57 | | |
58 | 70 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
59 | 70 | } |
60 | | |
61 | | static int |
62 | | jpki_match_card(struct sc_card *card) |
63 | 2.38k | { |
64 | 2.38k | int i, rc; |
65 | | |
66 | 2.38k | i = _sc_match_atr(card, jpki_atrs, &card->type); |
67 | 2.38k | if (i >= 0) { |
68 | 3 | return 1; |
69 | 3 | } |
70 | | |
71 | 2.38k | rc = jpki_select_ap(card); |
72 | 2.38k | if (rc == SC_SUCCESS) { |
73 | 40 | card->type = SC_CARD_TYPE_JPKI_BASE; |
74 | 40 | return 1; |
75 | 40 | } |
76 | 2.34k | return 0; |
77 | 2.38k | } |
78 | | |
79 | | static int |
80 | | jpki_finish(sc_card_t * card) |
81 | 43 | { |
82 | 43 | struct jpki_private_data *drvdata = JPKI_DRVDATA(card); |
83 | | |
84 | 43 | LOG_FUNC_CALLED(card->ctx); |
85 | 43 | if (drvdata) { |
86 | 43 | if (drvdata->mf) { |
87 | 43 | free(drvdata->mf); |
88 | 43 | } |
89 | 43 | free(drvdata); |
90 | 43 | card->drv_data = NULL; |
91 | 43 | } |
92 | 43 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
93 | 43 | } |
94 | | |
95 | | static int |
96 | | jpki_init(struct sc_card *card) |
97 | 43 | { |
98 | 43 | struct jpki_private_data *drvdata; |
99 | 43 | sc_file_t *mf; |
100 | 43 | int flags; |
101 | | |
102 | 43 | LOG_FUNC_CALLED(card->ctx); |
103 | | |
104 | 43 | drvdata = malloc(sizeof (struct jpki_private_data)); |
105 | 43 | if (!drvdata) |
106 | 43 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
107 | | |
108 | 43 | memset(drvdata, 0, sizeof (struct jpki_private_data)); |
109 | | |
110 | | /* create virtual MF */ |
111 | 43 | mf = sc_file_new(); |
112 | 43 | if (!mf) { |
113 | 0 | free(drvdata); |
114 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
115 | 0 | } |
116 | 43 | sc_format_path("3f00", &mf->path); |
117 | 43 | mf->type = SC_FILE_TYPE_DF; |
118 | 43 | mf->shareable = 0; |
119 | 43 | mf->ef_structure = SC_FILE_EF_UNKNOWN; |
120 | 43 | mf->size = 0; |
121 | 43 | mf->id = 0x3f00; |
122 | 43 | mf->status = SC_FILE_STATUS_ACTIVATED; |
123 | 43 | sc_file_add_acl_entry(mf, SC_AC_OP_SELECT, SC_AC_NONE, 0); |
124 | 43 | sc_file_add_acl_entry(mf, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0); |
125 | 43 | sc_file_add_acl_entry(mf, SC_AC_OP_LOCK, SC_AC_NEVER, 0); |
126 | 43 | sc_file_add_acl_entry(mf, SC_AC_OP_DELETE, SC_AC_NEVER, 0); |
127 | 43 | sc_file_add_acl_entry(mf, SC_AC_OP_CREATE, SC_AC_NEVER, 0); |
128 | 43 | drvdata->mf = mf; |
129 | 43 | drvdata->selected = SELECT_MF; |
130 | | |
131 | 43 | card->name = "jpki"; |
132 | 43 | card->drv_data = drvdata; |
133 | | |
134 | 43 | flags = SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1; |
135 | 43 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
136 | | |
137 | 43 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
138 | 43 | } |
139 | | |
140 | | static int |
141 | | jpki_select_file(struct sc_card *card, |
142 | | const struct sc_path *path, struct sc_file **file_out) |
143 | 2.67k | { |
144 | 2.67k | struct jpki_private_data *drvdata = JPKI_DRVDATA(card); |
145 | 2.67k | int rc; |
146 | 2.67k | sc_apdu_t apdu; |
147 | 2.67k | struct sc_file *file = NULL; |
148 | | |
149 | 2.67k | LOG_FUNC_CALLED(card->ctx); |
150 | 2.67k | sc_log(card->ctx, |
151 | 2.67k | "jpki_select_file: path=%s, len=%"SC_FORMAT_LEN_SIZE_T"u", |
152 | 2.67k | sc_print_path(path), path->len); |
153 | 2.67k | if (path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0) { |
154 | 0 | drvdata->selected = SELECT_MF; |
155 | 0 | if (file_out) { |
156 | 0 | sc_file_dup(file_out, drvdata->mf); |
157 | 0 | if (*file_out == NULL) { |
158 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
159 | 0 | } |
160 | 0 | } |
161 | 0 | return 0; |
162 | 0 | } |
163 | | |
164 | 2.67k | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0); |
165 | 2.67k | switch (path->type) { |
166 | 72 | case SC_PATH_TYPE_FILE_ID: |
167 | 72 | apdu.p1 = 2; |
168 | 72 | break; |
169 | 2.47k | case SC_PATH_TYPE_DF_NAME: |
170 | 2.47k | apdu.p1 = 4; |
171 | 2.47k | break; |
172 | 129 | default: |
173 | 129 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
174 | 2.67k | } |
175 | 2.54k | apdu.p2 = 0x0C; |
176 | 2.54k | apdu.data = path->value; |
177 | 2.54k | apdu.datalen = path->len; |
178 | 2.54k | apdu.lc = path->len; |
179 | | |
180 | 2.54k | rc = sc_transmit_apdu(card, &apdu); |
181 | 2.54k | LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); |
182 | 2.53k | rc = sc_check_sw(card, apdu.sw1, apdu.sw2); |
183 | 2.53k | LOG_TEST_RET(card->ctx, rc, "SW Check failed"); |
184 | 149 | if (!file_out) { |
185 | 149 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
186 | 149 | } |
187 | | |
188 | | /* read certificate file size */ |
189 | 0 | if (path->len == 2 && ( |
190 | 0 | memcmp(path->value, "\x00\x0A", 2) == 0 || |
191 | 0 | memcmp(path->value, "\x00\x01", 2) == 0 || |
192 | 0 | memcmp(path->value, "\x00\x0B", 2) == 0 || |
193 | 0 | memcmp(path->value, "\x00\x02", 2) == 0 ) |
194 | 0 | ) { |
195 | 0 | u8 buf[4]; |
196 | 0 | rc = sc_read_binary(card, 0, buf, 4, 0); |
197 | 0 | LOG_TEST_RET(card->ctx, rc, "SW Check failed"); |
198 | 0 | if (rc < 4) |
199 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Received data too short"); |
200 | 0 | file = sc_file_new(); |
201 | 0 | if (!file) { |
202 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
203 | 0 | } |
204 | 0 | file->path = *path; |
205 | 0 | file->size = (buf[2] << 8 | buf[3]) + 4; |
206 | 0 | *file_out = file; |
207 | 0 | } |
208 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
209 | 0 | } |
210 | | |
211 | | static int |
212 | | jpki_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) |
213 | 63 | { |
214 | 63 | int rc; |
215 | 63 | sc_path_t path; |
216 | 63 | sc_apdu_t apdu; |
217 | 63 | struct jpki_private_data *priv = JPKI_DRVDATA(card); |
218 | 63 | int max_tries = 0; |
219 | | |
220 | 63 | LOG_FUNC_CALLED(card->ctx); |
221 | | |
222 | 63 | if (tries_left) { |
223 | 56 | *tries_left = -1; |
224 | 56 | } |
225 | | |
226 | 63 | switch (data->pin_reference) { |
227 | 40 | case 1: |
228 | 40 | sc_format_path(JPKI_AUTH_PIN, &path); |
229 | 40 | path.type = SC_PATH_TYPE_FILE_ID; |
230 | 40 | rc = sc_select_file(card, &path, NULL); |
231 | 40 | max_tries = JPKI_AUTH_PIN_MAX_TRIES; |
232 | 40 | break; |
233 | 23 | case 2: |
234 | 23 | sc_format_path(JPKI_SIGN_PIN, &path); |
235 | 23 | path.type = SC_PATH_TYPE_FILE_ID; |
236 | 23 | rc = sc_select_file(card, &path, NULL); |
237 | 23 | max_tries = JPKI_SIGN_PIN_MAX_TRIES; |
238 | 23 | break; |
239 | 0 | default: |
240 | 0 | sc_log(card->ctx, "Unknown PIN reference: %d", data->pin_reference); |
241 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
242 | 63 | } |
243 | 63 | LOG_TEST_RET(card->ctx, rc, "SELECT_FILE error"); |
244 | | |
245 | 52 | switch (data->cmd) { |
246 | 10 | case SC_PIN_CMD_VERIFY: |
247 | | /* detect overloaded APDU with SC_PIN_CMD_GET_INFO */ |
248 | 10 | if (data->pin1.len == 0 && !(data->flags & SC_PIN_CMD_USE_PINPAD)) |
249 | 10 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_PIN_LENGTH); |
250 | 10 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0x20, 0x00, 0x80); |
251 | 10 | apdu.data = data->pin1.data; |
252 | 10 | apdu.datalen = data->pin1.len; |
253 | 10 | apdu.lc = data->pin1.len; |
254 | 10 | rc = sc_transmit_apdu(card, &apdu); |
255 | 10 | LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); |
256 | 9 | rc = sc_check_sw(card, apdu.sw1, apdu.sw2); |
257 | 9 | if (rc == SC_SUCCESS) { |
258 | 7 | data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN; |
259 | 7 | data->pin1.tries_left = max_tries; |
260 | 7 | } else { |
261 | 2 | data->pin1.logged_in = SC_PIN_STATE_LOGGED_OUT; |
262 | 2 | data->pin1.tries_left = apdu.sw2 & 0xF; |
263 | 2 | } |
264 | 9 | priv->logged_in = data->pin1.logged_in; |
265 | 9 | LOG_TEST_RET(card->ctx, rc, "VERIFY failed"); |
266 | 7 | break; |
267 | 42 | case SC_PIN_CMD_GET_INFO: |
268 | 42 | sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x80); |
269 | 42 | rc = sc_transmit_apdu(card, &apdu); |
270 | 42 | LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); |
271 | 39 | if (apdu.sw1 != 0x63) { |
272 | 9 | sc_log(card->ctx, "VERIFY GET_INFO error"); |
273 | 9 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED); |
274 | 9 | } |
275 | 30 | data->pin1.logged_in = priv->logged_in; |
276 | 30 | data->pin1.tries_left = apdu.sw2 & 0xF; |
277 | 30 | if (tries_left) { |
278 | 29 | *tries_left = data->pin1.tries_left; |
279 | 29 | } |
280 | 30 | break; |
281 | 0 | default: |
282 | 0 | sc_log(card->ctx, "Card does not support PIN command: %d", data->cmd); |
283 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
284 | 52 | } |
285 | | |
286 | 37 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
287 | 37 | } |
288 | | |
289 | | static int |
290 | | jpki_set_security_env(sc_card_t * card, |
291 | | const sc_security_env_t * env, int se_num) |
292 | 9 | { |
293 | 9 | int rc; |
294 | 9 | sc_path_t path; |
295 | | |
296 | 9 | LOG_FUNC_CALLED(card->ctx); |
297 | 9 | sc_log(card->ctx, |
298 | 9 | "flags=%08lx op=%d alg=%lu algf=%08lx algr=%08lx kr0=%02x, krfl=%"SC_FORMAT_LEN_SIZE_T"u", |
299 | 9 | env->flags, env->operation, env->algorithm, |
300 | 9 | env->algorithm_flags, env->algorithm_ref, env->key_ref[0], |
301 | 9 | env->key_ref_len); |
302 | | |
303 | 9 | switch (env->operation) { |
304 | 9 | case SC_SEC_OPERATION_SIGN: |
305 | 9 | break; |
306 | 0 | default: |
307 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
308 | 9 | } |
309 | | |
310 | 9 | switch (env->key_ref[0]) { |
311 | 9 | case 1: |
312 | 9 | sc_format_path(JPKI_AUTH_KEY, &path); |
313 | 9 | break; |
314 | 0 | case 2: |
315 | 0 | sc_format_path(JPKI_SIGN_KEY, &path); |
316 | 0 | break; |
317 | 0 | default: |
318 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
319 | 9 | } |
320 | 9 | path.type = SC_PATH_TYPE_FILE_ID; |
321 | 9 | rc = sc_select_file(card, &path, NULL); |
322 | 9 | LOG_TEST_RET(card->ctx, rc, "select key failed"); |
323 | | |
324 | 5 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
325 | 5 | } |
326 | | |
327 | | static int |
328 | | jpki_compute_signature(sc_card_t * card, |
329 | | const u8 * data, size_t datalen, u8 * out, size_t outlen) |
330 | 5 | { |
331 | 5 | int rc; |
332 | 5 | sc_apdu_t apdu; |
333 | 5 | unsigned char resp[SC_MAX_APDU_BUFFER_SIZE]; |
334 | | |
335 | 5 | LOG_FUNC_CALLED(card->ctx); |
336 | | |
337 | 5 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x00, 0x80); |
338 | 5 | apdu.cla = 0x80; |
339 | 5 | apdu.data = data; |
340 | 5 | apdu.datalen = datalen; |
341 | 5 | apdu.lc = datalen; |
342 | 5 | apdu.resp = resp; |
343 | 5 | apdu.resplen = sizeof(resp); |
344 | 5 | apdu.le = 0; |
345 | 5 | rc = sc_transmit_apdu(card, &apdu); |
346 | 5 | LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); |
347 | 4 | rc = sc_check_sw(card, apdu.sw1, apdu.sw2); |
348 | 4 | LOG_TEST_RET(card->ctx, rc, "SW Check failed"); |
349 | 4 | if (apdu.resplen > outlen) { |
350 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
351 | 0 | } |
352 | 4 | memcpy(out, resp, apdu.resplen); |
353 | 4 | LOG_FUNC_RETURN(card->ctx, (int)apdu.resplen); |
354 | 4 | } |
355 | | |
356 | | static int jpki_card_reader_lock_obtained(sc_card_t *card, int was_reset) |
357 | 2.43k | { |
358 | 2.43k | int r = SC_SUCCESS; |
359 | | |
360 | 2.43k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
361 | | |
362 | 2.43k | if (was_reset > 0) { |
363 | 0 | r = jpki_select_ap(card); |
364 | 0 | } |
365 | | |
366 | 2.43k | LOG_FUNC_RETURN(card->ctx, r); |
367 | 2.43k | } |
368 | | |
369 | | static int jpki_logout(sc_card_t *card) |
370 | 0 | { |
371 | 0 | return jpki_select_ap(card); |
372 | 0 | } |
373 | | |
374 | | static struct sc_card_driver * |
375 | | sc_get_driver(void) |
376 | 13.2k | { |
377 | 13.2k | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
378 | | |
379 | 13.2k | jpki_ops = *iso_drv->ops; |
380 | 13.2k | jpki_ops.match_card = jpki_match_card; |
381 | 13.2k | jpki_ops.init = jpki_init; |
382 | 13.2k | jpki_ops.finish = jpki_finish; |
383 | 13.2k | jpki_ops.select_file = jpki_select_file; |
384 | 13.2k | jpki_ops.pin_cmd = jpki_pin_cmd; |
385 | 13.2k | jpki_ops.set_security_env = jpki_set_security_env; |
386 | 13.2k | jpki_ops.compute_signature = jpki_compute_signature; |
387 | 13.2k | jpki_ops.card_reader_lock_obtained = jpki_card_reader_lock_obtained; |
388 | 13.2k | jpki_ops.logout = jpki_logout; |
389 | | |
390 | 13.2k | return &jpki_drv; |
391 | 13.2k | } |
392 | | |
393 | | struct sc_card_driver * |
394 | | sc_get_jpki_driver(void) |
395 | 13.2k | { |
396 | 13.2k | return sc_get_driver(); |
397 | 13.2k | } |