/src/opensc/src/libopensc/iasecc-sdo.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * iasecc-sdo.c: library to manipulate the Security Data Objects (SDO) |
3 | | * used by IAS/ECC card support. |
4 | | * |
5 | | * Copyright (C) 2010 Viktor Tarasov <vtarasov@opentrust.com> |
6 | | * OpenTrust <www.opentrust.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 | | #ifdef ENABLE_OPENSSL /* empty file without openssl */ |
28 | | |
29 | | #include <string.h> |
30 | | #include <stdlib.h> |
31 | | |
32 | | #include "internal.h" |
33 | | #include "asn1.h" |
34 | | #include "cardctl.h" |
35 | | |
36 | | #include "iasecc.h" |
37 | | #include "iasecc-sdo.h" |
38 | | |
39 | | static int iasecc_parse_size(unsigned char *data, size_t data_len, size_t *out); |
40 | | |
41 | | |
42 | | static int |
43 | | iasecc_parse_acls(struct sc_card *card, struct iasecc_sdo_docp *docp, int flags) |
44 | 6 | { |
45 | 6 | struct sc_context *ctx = card->ctx; |
46 | 6 | struct iasecc_extended_tlv *acls = &docp->acls_contact; |
47 | 6 | int ii; |
48 | 6 | size_t offs; |
49 | 6 | unsigned char mask = 0x40; |
50 | | |
51 | 6 | if (flags) |
52 | 0 | acls = &docp->acls_contactless; |
53 | | |
54 | 6 | if (!acls->size) |
55 | 6 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
56 | | |
57 | 5 | docp->amb = *(acls->value + 0); |
58 | 5 | memset(docp->scbs, 0xFF, sizeof(docp->scbs)); |
59 | 40 | for (ii=0, offs = 1; ii<7; ii++, mask >>= 1) |
60 | 35 | if (mask & docp->amb) { |
61 | 23 | if (offs >= acls->size) { |
62 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
63 | 0 | } |
64 | 23 | docp->scbs[ii] = *(acls->value + offs++); |
65 | 23 | } |
66 | | |
67 | 5 | sc_log(ctx, "iasecc_parse_docp() SCBs %02X:%02X:%02X:%02X:%02X:%02X:%02X", |
68 | 5 | docp->scbs[0],docp->scbs[1],docp->scbs[2],docp->scbs[3], |
69 | 5 | docp->scbs[4],docp->scbs[5],docp->scbs[6]); |
70 | 5 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
71 | 5 | } |
72 | | |
73 | | |
74 | | int |
75 | | iasecc_sdo_convert_acl(struct sc_card *card, struct iasecc_sdo *sdo, |
76 | | unsigned char op, unsigned *out_method, unsigned *out_ref) |
77 | 0 | { |
78 | 0 | struct sc_context *ctx = card->ctx; |
79 | 0 | struct acl_op { |
80 | 0 | unsigned char op; |
81 | 0 | unsigned char mask; |
82 | 0 | } ops[] = { |
83 | 0 | {SC_AC_OP_PSO_COMPUTE_SIGNATURE,IASECC_ACL_PSO_SIGNATURE}, |
84 | 0 | {SC_AC_OP_INTERNAL_AUTHENTICATE,IASECC_ACL_INTERNAL_AUTHENTICATE}, |
85 | 0 | {SC_AC_OP_PSO_DECRYPT, IASECC_ACL_PSO_DECIPHER}, |
86 | 0 | {SC_AC_OP_GENERATE, IASECC_ACL_GENERATE_KEY}, |
87 | 0 | {SC_AC_OP_UPDATE, IASECC_ACL_PUT_DATA}, |
88 | 0 | {SC_AC_OP_READ, IASECC_ACL_GET_DATA}, |
89 | 0 | {0x00, 0x00} |
90 | 0 | }; |
91 | 0 | unsigned char mask = 0x80, op_mask = 0; |
92 | 0 | int ii; |
93 | |
|
94 | 0 | LOG_FUNC_CALLED(ctx); |
95 | |
|
96 | 0 | for (ii=0; ops[ii].mask; ii++) { |
97 | 0 | if (op == ops[ii].op) { |
98 | 0 | op_mask = ops[ii].mask; |
99 | 0 | break; |
100 | 0 | } |
101 | 0 | } |
102 | 0 | if (op_mask == 0) |
103 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
104 | | |
105 | 0 | sc_log(ctx, "OP:%i, mask:0x%X", op, op_mask); |
106 | 0 | sc_log(ctx, "AMB:%X, scbs:%s", sdo->docp.amb, sc_dump_hex(sdo->docp.scbs, IASECC_MAX_SCBS)); |
107 | 0 | sc_log(ctx, "docp.acls_contact:%s", sc_dump_hex(sdo->docp.acls_contact.value, sdo->docp.acls_contact.size)); |
108 | |
|
109 | 0 | if (!sdo->docp.amb && sdo->docp.acls_contact.size) { |
110 | 0 | int rv = iasecc_parse_acls(card, &sdo->docp, 0); |
111 | 0 | LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP"); |
112 | 0 | } |
113 | | |
114 | 0 | *out_method = SC_AC_NEVER; |
115 | 0 | *out_ref = SC_AC_NEVER; |
116 | |
|
117 | 0 | for (ii=0; ii<7; ii++) { |
118 | 0 | mask >>= 1; |
119 | 0 | if (sdo->docp.amb & mask) { |
120 | 0 | if (op_mask == mask) { |
121 | 0 | unsigned char scb = sdo->docp.scbs[ii]; |
122 | 0 | sc_log(ctx, "ii:%i, scb:0x%X", ii, scb); |
123 | |
|
124 | 0 | *out_ref = scb & 0x0F; |
125 | 0 | if (scb == 0) |
126 | 0 | *out_method = SC_AC_NONE; |
127 | 0 | else if (scb == 0xFF) |
128 | 0 | *out_method = SC_AC_NEVER; |
129 | 0 | else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_USER_AUTH) |
130 | 0 | *out_method = SC_AC_SEN; |
131 | 0 | else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_EXT_AUTH) |
132 | 0 | *out_method = SC_AC_AUT; |
133 | 0 | else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_SM) |
134 | 0 | *out_method = SC_AC_PRO; |
135 | 0 | else |
136 | 0 | *out_method = SC_AC_SCB, *out_ref = scb; |
137 | |
|
138 | 0 | break; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | |
|
143 | 0 | sc_log(ctx, "returns method %X; ref %X", *out_method, *out_ref); |
144 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
145 | 0 | } |
146 | | |
147 | | |
148 | | void |
149 | | iasecc_sdo_free_fields(struct sc_card *card, struct iasecc_sdo *sdo) |
150 | 69 | { |
151 | 69 | free(sdo->docp.tries_maximum.value); |
152 | 69 | free(sdo->docp.tries_remaining.value); |
153 | 69 | free(sdo->docp.usage_remaining.value); |
154 | 69 | free(sdo->docp.non_repudiation.value); |
155 | 69 | free(sdo->docp.acls_contact.value); |
156 | 69 | free(sdo->docp.acls_contactless.value); |
157 | 69 | free(sdo->docp.size.value); |
158 | 69 | free(sdo->docp.name.value); |
159 | 69 | free(sdo->docp.issuer_data.value); |
160 | | |
161 | 69 | if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PUBLIC) { |
162 | 1 | free(sdo->data.pub_key.n.value); |
163 | 1 | free(sdo->data.pub_key.e.value); |
164 | 1 | free(sdo->data.pub_key.compulsory.value); |
165 | 1 | free(sdo->data.pub_key.chr.value); |
166 | 1 | free(sdo->data.pub_key.cha.value); |
167 | 1 | } |
168 | 68 | else if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PRIVATE) { |
169 | 11 | free(sdo->data.prv_key.p.value); |
170 | 11 | free(sdo->data.prv_key.q.value); |
171 | 11 | free(sdo->data.prv_key.iqmp.value); |
172 | 11 | free(sdo->data.prv_key.dmp1.value); |
173 | 11 | free(sdo->data.prv_key.dmq1.value); |
174 | 11 | free(sdo->data.prv_key.compulsory.value); |
175 | 11 | } |
176 | 57 | else if (sdo->sdo_class == IASECC_SDO_CLASS_CHV) { |
177 | 43 | free(sdo->data.chv.size_max.value); |
178 | 43 | free(sdo->data.chv.size_min.value); |
179 | 43 | free(sdo->data.chv.value.value); |
180 | 43 | } |
181 | | /* invalidate all the other members too */ |
182 | 69 | memset(sdo, 0, sizeof(struct iasecc_sdo)); |
183 | 69 | } |
184 | | |
185 | | |
186 | | void |
187 | | iasecc_sdo_free(struct sc_card *card, struct iasecc_sdo *sdo) |
188 | 12 | { |
189 | 12 | iasecc_sdo_free_fields(card, sdo); |
190 | 12 | free(sdo); |
191 | 12 | } |
192 | | |
193 | | |
194 | | static int |
195 | | iasecc_crt_parse(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_se_info *se) |
196 | 1.13k | { |
197 | 1.13k | struct sc_context *ctx = card->ctx; |
198 | 1.13k | struct sc_crt crt; |
199 | 1.13k | int ii, offs, len, parsed_len = -1; |
200 | | |
201 | 1.13k | sc_log(ctx, "iasecc_crt_parse(0x%X) called", *data); |
202 | | |
203 | 1.13k | if (data_len < 2) |
204 | 1.13k | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
205 | | |
206 | 1.13k | memset(&crt, 0, sizeof(crt)); |
207 | 1.13k | crt.tag = *(data + 0); |
208 | 1.13k | len = *(data + 1); |
209 | | |
210 | 1.27k | for(offs = 2; offs < len + 2; offs += 3) { |
211 | 175 | if ((size_t) offs + 2 >= data_len) |
212 | 175 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
213 | 174 | sc_log(ctx, "iasecc_crt_parse(0x%X) CRT %X -> %X", *data, *(data + offs), *(data + offs + 2)); |
214 | 174 | if (*(data + offs) == IASECC_CRT_TAG_USAGE) { |
215 | 36 | crt.usage = *(data + offs + 2); |
216 | 36 | } |
217 | 138 | else if (*(data + offs) == IASECC_CRT_TAG_REFERENCE) { |
218 | 42 | int nn_refs = sizeof(crt.refs) / sizeof(crt.refs[0]); |
219 | | |
220 | 132 | for (ii=0; ii<nn_refs && crt.refs[ii]; ii++) |
221 | 90 | ; |
222 | 42 | if (ii == nn_refs) |
223 | 42 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
224 | | |
225 | 41 | crt.refs[ii] = *(data + offs + 2); |
226 | 41 | } |
227 | 96 | else if (*(data + offs) == IASECC_CRT_TAG_ALGO) { |
228 | 65 | crt.algo = *(data + offs + 2); |
229 | 65 | } |
230 | 31 | else { |
231 | 31 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
232 | 31 | } |
233 | 174 | } |
234 | | |
235 | 3.57k | for (ii=0; ii<SC_MAX_CRTS_IN_SE; ii++) |
236 | 3.57k | if (!se->crts[ii].tag) |
237 | 1.10k | break; |
238 | | |
239 | 1.10k | if (ii==SC_MAX_CRTS_IN_SE) |
240 | 1.10k | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_crt_parse() error: too much CRTs in SE"); |
241 | | |
242 | 1.10k | memcpy(&se->crts[ii], &crt, sizeof(crt)); |
243 | 1.10k | parsed_len = len + 2; |
244 | 1.10k | LOG_FUNC_RETURN(ctx, parsed_len); |
245 | 1.10k | } |
246 | | |
247 | | |
248 | | int |
249 | | iasecc_se_get_crt(struct sc_card *card, struct iasecc_se_info *se, struct sc_crt *crt) |
250 | 10 | { |
251 | 10 | struct sc_context *ctx = card->ctx; |
252 | 10 | int ii; |
253 | | |
254 | 10 | LOG_FUNC_CALLED(ctx); |
255 | 10 | if (!se || !crt) |
256 | 10 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
257 | 10 | sc_log(ctx, "CRT search template: %X:%X:%X, refs %X:%X:...", |
258 | 10 | crt->tag, crt->algo, crt->usage, crt->refs[0], crt->refs[1]); |
259 | | |
260 | 61 | for (ii=0; ii<SC_MAX_CRTS_IN_SE && se->crts[ii].tag; ii++) { |
261 | 51 | if (crt->tag != se->crts[ii].tag) |
262 | 35 | continue; |
263 | 16 | if (crt->algo && crt->algo != se->crts[ii].algo) |
264 | 0 | continue; |
265 | 16 | if (crt->usage && crt->usage != se->crts[ii].usage) |
266 | 16 | continue; |
267 | 0 | if (crt->refs[0] && crt->refs[0] != se->crts[ii].refs[0]) |
268 | 0 | continue; |
269 | | |
270 | 0 | memcpy(crt, &se->crts[ii], sizeof(*crt)); |
271 | |
|
272 | 0 | sc_log(ctx, "iasecc_se_get_crt() found CRT with refs %X:%X:...", |
273 | 0 | se->crts[ii].refs[0], se->crts[ii].refs[1]); |
274 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
275 | 0 | } |
276 | | |
277 | 10 | sc_log(ctx, "iasecc_se_get_crt() CRT is not found"); |
278 | 10 | return SC_ERROR_DATA_OBJECT_NOT_FOUND; |
279 | 10 | } |
280 | | |
281 | | |
282 | | int |
283 | | iasecc_se_get_crt_by_usage(struct sc_card *card, struct iasecc_se_info *se, unsigned char tag, |
284 | | unsigned char usage, struct sc_crt *crt) |
285 | 0 | { |
286 | 0 | struct sc_context *ctx = card->ctx; |
287 | 0 | int ii; |
288 | |
|
289 | 0 | LOG_FUNC_CALLED(ctx); |
290 | 0 | if (!se || !crt || !tag || !usage) |
291 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
292 | 0 | sc_log(ctx, "CRT search template with TAG:0x%X and UQB:0x%X", tag, usage); |
293 | |
|
294 | 0 | for (ii=0; ii<SC_MAX_CRTS_IN_SE && se->crts[ii].tag; ii++) { |
295 | 0 | if (tag != se->crts[ii].tag) |
296 | 0 | continue; |
297 | 0 | if (usage != se->crts[ii].usage) |
298 | 0 | continue; |
299 | | |
300 | 0 | memcpy(crt, &se->crts[ii], sizeof(*crt)); |
301 | |
|
302 | 0 | sc_log(ctx, "iasecc_se_get_crt() found CRT with refs %X:%X:...", crt->refs[0], crt->refs[1]); |
303 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
304 | 0 | } |
305 | | |
306 | 0 | sc_log(ctx, "iasecc_se_get_crt() CRT is not found"); |
307 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_DATA_OBJECT_NOT_FOUND); |
308 | 0 | } |
309 | | |
310 | | |
311 | | int |
312 | | iasecc_se_parse(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_se_info *se) |
313 | 63 | { |
314 | 63 | struct sc_context *ctx = card->ctx; |
315 | 63 | size_t size, offs; |
316 | 63 | int size_size; |
317 | 63 | int rv; |
318 | | |
319 | 63 | LOG_FUNC_CALLED(ctx); |
320 | | |
321 | 63 | if (data_len < 1) |
322 | 63 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
323 | | |
324 | 62 | if (*data == IASECC_SDO_TEMPLATE_TAG) { |
325 | 6 | size_size = iasecc_parse_size(data + 1, data_len - 1, &size); |
326 | 6 | LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE"); |
327 | | |
328 | 5 | if (data_len - 1 < size) |
329 | 5 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
330 | | |
331 | 4 | data += size_size + 1; |
332 | 4 | data_len = size; |
333 | 4 | sc_log(ctx, |
334 | 4 | "IASECC_SDO_TEMPLATE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %d", |
335 | 4 | size, size_size); |
336 | | |
337 | 4 | if (data_len < 3) |
338 | 4 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
339 | | |
340 | 3 | if (*data != IASECC_SDO_TAG_HEADER) |
341 | 3 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
342 | | |
343 | 0 | if ((*(data + 1) & 0x7F) != IASECC_SDO_CLASS_SE) |
344 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
345 | | |
346 | 0 | size_size = iasecc_parse_size(data + 3, data_len - 3, &size); |
347 | 0 | LOG_TEST_RET(ctx, size_size, "parse error: invalid SDO SE data size"); |
348 | | |
349 | 0 | if (data_len != size + size_size + 3) |
350 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO SE data size"); |
351 | | |
352 | 0 | data += 3 + size_size; |
353 | 0 | data_len = size; |
354 | 0 | sc_log(ctx, |
355 | 0 | "IASECC_SDO_TEMPLATE SE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %d", |
356 | 0 | size, size_size); |
357 | 0 | } |
358 | | |
359 | 56 | if (*data != IASECC_SDO_CLASS_SE) { |
360 | 4 | sc_log(ctx, |
361 | 4 | "Invalid SE tag 0x%X; data length %"SC_FORMAT_LEN_SIZE_T"u", |
362 | 4 | *data, data_len); |
363 | 4 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
364 | 4 | } |
365 | | |
366 | 52 | size_size = iasecc_parse_size(data + 1, data_len - 1, &size); |
367 | 52 | LOG_TEST_RET(ctx, size_size, "parse error: invalid size data"); |
368 | | |
369 | 51 | if (data_len != size + size_size + 1) |
370 | 51 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SE data size"); |
371 | | |
372 | 45 | offs = 1 + size_size; |
373 | 1.14k | for (; offs < data_len;) { |
374 | 1.13k | rv = iasecc_crt_parse(card, data + offs, data_len - offs, se); |
375 | 1.13k | LOG_TEST_RET(ctx, rv, "parse error: invalid SE data"); |
376 | | |
377 | 1.10k | offs += rv; |
378 | 1.10k | } |
379 | | |
380 | 10 | if (offs != data_len) |
381 | 10 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed"); |
382 | | |
383 | 10 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
384 | 10 | } |
385 | | |
386 | | |
387 | | static int |
388 | | iasecc_parse_size(unsigned char *data, size_t data_len, size_t *out) |
389 | 244 | { |
390 | 244 | if (data_len > 0 && *data < 0x80) { |
391 | 219 | *out = *data; |
392 | 219 | return 1; |
393 | 219 | } |
394 | 25 | else if (data_len > 1 && *data == 0x81) { |
395 | 5 | *out = *(data + 1); |
396 | 5 | return 2; |
397 | 5 | } |
398 | 20 | else if (data_len > 2 && *data == 0x82) { |
399 | 4 | *out = *(data + 1) * 0x100 + *(data + 2); |
400 | 4 | return 3; |
401 | 4 | } |
402 | | |
403 | 16 | return SC_ERROR_INVALID_DATA; |
404 | 244 | } |
405 | | |
406 | | |
407 | | static int |
408 | | iasecc_parse_get_tlv(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_extended_tlv *tlv) |
409 | 121 | { |
410 | 121 | struct sc_context *ctx = card->ctx; |
411 | 121 | int size_len, tag_len; |
412 | | |
413 | 121 | memset(tlv, 0, sizeof(*tlv)); |
414 | 121 | sc_log(ctx, "iasecc_parse_get_tlv() called for tag 0x%X", *data); |
415 | 121 | if (data_len < 1) |
416 | 121 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
417 | 121 | if ((*data == 0x7F) || (*data == 0x5F)) { |
418 | 7 | if (data_len < 2) |
419 | 7 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
420 | 7 | tlv->tag = *data * 0x100 + *(data + 1); |
421 | 7 | tag_len = 2; |
422 | 7 | } |
423 | 114 | else { |
424 | 114 | tlv->tag = *data; |
425 | 114 | tag_len = 1; |
426 | 114 | } |
427 | | |
428 | 121 | sc_log(ctx, "iasecc_parse_get_tlv() tlv->tag 0x%X", tlv->tag); |
429 | 121 | size_len = iasecc_parse_size(data + tag_len, data_len - tag_len, &tlv->size); |
430 | 121 | LOG_TEST_RET(ctx, size_len, "parse error: invalid size data"); |
431 | 111 | if (tag_len + size_len + tlv->size > data_len) { |
432 | 4 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
433 | 4 | } |
434 | | |
435 | 107 | tlv->value = calloc(1, tlv->size); |
436 | 107 | if (!tlv->value) |
437 | 107 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
438 | 107 | memcpy(tlv->value, data + size_len + tag_len, tlv->size); |
439 | | |
440 | 107 | tlv->on_card = 1; |
441 | | |
442 | 107 | sc_log(ctx, |
443 | 107 | "iasecc_parse_get_tlv() parsed %"SC_FORMAT_LEN_SIZE_T"u bytes", |
444 | 107 | tag_len + size_len + tlv->size); |
445 | 107 | return (int)(tag_len + size_len + tlv->size); |
446 | 107 | } |
447 | | |
448 | | |
449 | | static int |
450 | | iasecc_parse_chv(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_chv *chv) |
451 | 3 | { |
452 | 3 | struct sc_context *ctx = card->ctx; |
453 | 3 | size_t offs = 0; |
454 | 3 | int rv; |
455 | | |
456 | 3 | LOG_FUNC_CALLED(ctx); |
457 | 3 | while(offs < data_len) { |
458 | 2 | struct iasecc_extended_tlv tlv; |
459 | | |
460 | 2 | rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv); |
461 | 2 | LOG_TEST_RET(ctx, rv, "iasecc_parse_chv() get and parse TLV error"); |
462 | | |
463 | 1 | sc_log(ctx, |
464 | 1 | "iasecc_parse_chv() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", |
465 | 1 | rv, tlv.tag, tlv.size); |
466 | | |
467 | 1 | if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MAX) { |
468 | 0 | free(chv->size_max.value); |
469 | 0 | chv->size_max = tlv; |
470 | 1 | } else if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MIN) { |
471 | 0 | free(chv->size_min.value); |
472 | 0 | chv->size_min = tlv; |
473 | 1 | } else if (tlv.tag == IASECC_SDO_CHV_TAG_VALUE) { |
474 | 0 | free(chv->value.value); |
475 | 0 | chv->value = tlv; |
476 | 1 | } else { |
477 | 1 | free(tlv.value); |
478 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non CHV SDO tag"); |
479 | 1 | } |
480 | | |
481 | 0 | offs += rv; |
482 | 0 | } |
483 | | |
484 | 1 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
485 | 1 | } |
486 | | |
487 | | |
488 | | static int |
489 | | iasecc_parse_prvkey(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_prvkey *prvkey) |
490 | 0 | { |
491 | 0 | struct sc_context *ctx = card->ctx; |
492 | 0 | size_t offs = 0; |
493 | 0 | int rv; |
494 | |
|
495 | 0 | LOG_FUNC_CALLED(ctx); |
496 | 0 | while(offs < data_len) { |
497 | 0 | struct iasecc_extended_tlv tlv; |
498 | |
|
499 | 0 | rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv); |
500 | 0 | LOG_TEST_RET(ctx, rv, "iasecc_parse_prvkey() get and parse TLV error"); |
501 | | |
502 | 0 | sc_log(ctx, |
503 | 0 | "iasecc_parse_prvkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", |
504 | 0 | rv, tlv.tag, tlv.size); |
505 | |
|
506 | 0 | if (tlv.tag == IASECC_SDO_PRVKEY_TAG_COMPULSORY) { |
507 | 0 | free(prvkey->compulsory.value); |
508 | 0 | prvkey->compulsory = tlv; |
509 | 0 | } else { |
510 | 0 | free(tlv.value); |
511 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non PrvKey SDO tag"); |
512 | 0 | } |
513 | | |
514 | 0 | offs += rv; |
515 | 0 | } |
516 | | |
517 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
518 | 0 | } |
519 | | |
520 | | |
521 | | static int |
522 | | iasecc_parse_pubkey(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_pubkey *pubkey) |
523 | 0 | { |
524 | 0 | struct sc_context *ctx = card->ctx; |
525 | 0 | size_t offs = 0; |
526 | 0 | int rv; |
527 | |
|
528 | 0 | LOG_FUNC_CALLED(ctx); |
529 | 0 | while(offs < data_len) { |
530 | 0 | struct iasecc_extended_tlv tlv; |
531 | |
|
532 | 0 | rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv); |
533 | 0 | LOG_TEST_RET(ctx, rv, "iasecc_parse_pubkey() get and parse TLV error"); |
534 | | |
535 | 0 | sc_log(ctx, |
536 | 0 | "iasecc_parse_pubkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", |
537 | 0 | rv, tlv.tag, tlv.size); |
538 | |
|
539 | 0 | if (tlv.tag == IASECC_SDO_PUBKEY_TAG_N) { |
540 | 0 | free(pubkey->n.value); |
541 | 0 | pubkey->n = tlv; |
542 | 0 | } else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_E) { |
543 | 0 | free(pubkey->e.value); |
544 | 0 | pubkey->e = tlv; |
545 | 0 | } else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHR) { |
546 | 0 | free(pubkey->chr.value); |
547 | 0 | pubkey->chr = tlv; |
548 | 0 | } else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHA) { |
549 | 0 | free(pubkey->cha.value); |
550 | 0 | pubkey->cha = tlv; |
551 | 0 | } else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_COMPULSORY) { |
552 | 0 | free(pubkey->compulsory.value); |
553 | 0 | pubkey->compulsory = tlv; |
554 | 0 | } else { |
555 | 0 | free(tlv.value); |
556 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non PubKey SDO tag"); |
557 | 0 | } |
558 | | |
559 | 0 | offs += rv; |
560 | 0 | } |
561 | | |
562 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
563 | 0 | } |
564 | | |
565 | | |
566 | | static int |
567 | | iasecc_parse_keyset(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_keyset *keyset) |
568 | 0 | { |
569 | 0 | struct sc_context *ctx = card->ctx; |
570 | 0 | size_t offs = 0; |
571 | 0 | int rv; |
572 | |
|
573 | 0 | LOG_FUNC_CALLED(ctx); |
574 | 0 | while(offs < data_len) { |
575 | 0 | struct iasecc_extended_tlv tlv; |
576 | |
|
577 | 0 | rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv); |
578 | 0 | LOG_TEST_RET(ctx, rv, "iasecc_parse_keyset() get and parse TLV error"); |
579 | | |
580 | 0 | sc_log(ctx, |
581 | 0 | "iasecc_parse_prvkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", |
582 | 0 | rv, tlv.tag, tlv.size); |
583 | |
|
584 | 0 | if (tlv.tag == IASECC_SDO_KEYSET_TAG_COMPULSORY) { |
585 | 0 | free(keyset->compulsory.value); |
586 | 0 | keyset->compulsory = tlv; |
587 | 0 | } else { |
588 | 0 | free(tlv.value); |
589 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non KeySet SDO tag"); |
590 | 0 | } |
591 | | |
592 | 0 | offs += rv; |
593 | 0 | } |
594 | | |
595 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
596 | 0 | } |
597 | | |
598 | | |
599 | | static int |
600 | | iasecc_parse_docp(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo) |
601 | 26 | { |
602 | 26 | struct sc_context *ctx = card->ctx; |
603 | 26 | size_t offs = 0; |
604 | 26 | int rv; |
605 | | |
606 | 26 | LOG_FUNC_CALLED(ctx); |
607 | 68 | while(offs < data_len) { |
608 | 62 | struct iasecc_extended_tlv tlv; |
609 | | |
610 | 62 | rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv); |
611 | 62 | LOG_TEST_RET(ctx, rv, "iasecc_parse_get_tlv() get and parse TLV error"); |
612 | | |
613 | 53 | sc_log(ctx, |
614 | 53 | "iasecc_parse_docp() parse_get_tlv returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", |
615 | 53 | rv, tlv.tag, tlv.size); |
616 | | |
617 | 53 | if (tlv.tag == IASECC_DOCP_TAG_ACLS) { |
618 | 3 | int _rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo); |
619 | 3 | free(tlv.value); |
620 | 3 | LOG_TEST_RET(ctx, _rv, "parse error: cannot parse DOCP"); |
621 | 3 | } |
622 | 50 | else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACT) { |
623 | 5 | free(sdo->docp.acls_contact.value); |
624 | 5 | sdo->docp.acls_contact = tlv; |
625 | 5 | } |
626 | 45 | else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACTLESS) { |
627 | 1 | free(sdo->docp.acls_contactless.value); |
628 | 1 | sdo->docp.acls_contactless = tlv; |
629 | 1 | } |
630 | 44 | else if (tlv.tag == IASECC_DOCP_TAG_SIZE) { |
631 | 9 | free(sdo->docp.size.value); |
632 | 9 | sdo->docp.size = tlv; |
633 | 9 | } |
634 | 35 | else if (tlv.tag == IASECC_DOCP_TAG_NAME) { |
635 | 12 | free(sdo->docp.name.value); |
636 | 12 | sdo->docp.name = tlv; |
637 | 12 | } |
638 | 23 | else if (tlv.tag == IASECC_DOCP_TAG_ISSUER_DATA) { |
639 | 4 | free(sdo->docp.issuer_data.value); |
640 | 4 | sdo->docp.issuer_data = tlv; |
641 | 4 | } |
642 | 19 | else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION) { |
643 | 3 | free(sdo->docp.non_repudiation.value); |
644 | 3 | sdo->docp.non_repudiation = tlv; |
645 | 3 | } |
646 | 16 | else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING) { |
647 | 4 | free(sdo->docp.usage_remaining.value); |
648 | 4 | sdo->docp.usage_remaining = tlv; |
649 | 4 | } |
650 | 12 | else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM) { |
651 | 1 | free(sdo->docp.tries_maximum.value); |
652 | 1 | sdo->docp.tries_maximum = tlv; |
653 | 1 | } |
654 | 11 | else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING) { |
655 | 3 | free(sdo->docp.tries_remaining.value); |
656 | 3 | sdo->docp.tries_remaining = tlv; |
657 | 3 | } |
658 | 8 | else { |
659 | 8 | free(tlv.value); |
660 | 8 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_parse_get_tlv() parse error: non DOCP tag"); |
661 | 8 | } |
662 | | |
663 | 42 | offs += rv; |
664 | 42 | } |
665 | | |
666 | 6 | rv = iasecc_parse_acls(card, &sdo->docp, 0); |
667 | 6 | LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP"); |
668 | | |
669 | 5 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
670 | 5 | } |
671 | | |
672 | | |
673 | | static int |
674 | | iasecc_sdo_parse_data(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo) |
675 | 57 | { |
676 | 57 | struct sc_context *ctx = card->ctx; |
677 | 57 | struct iasecc_extended_tlv tlv; |
678 | 57 | int tlv_size, rv; |
679 | | |
680 | 57 | LOG_FUNC_CALLED(ctx); |
681 | 57 | sc_log(ctx, "iasecc_sdo_parse_data() class %X; ref %X", sdo->sdo_class, sdo->sdo_ref); |
682 | | |
683 | 57 | tlv_size = iasecc_parse_get_tlv(card, data, data_len, &tlv); |
684 | 57 | LOG_TEST_RET(ctx, tlv_size, "parse error: get TLV"); |
685 | | |
686 | 53 | sc_log(ctx, "iasecc_sdo_parse_data() tlv.tag 0x%X", tlv.tag); |
687 | 53 | if (tlv.tag == IASECC_DOCP_TAG) { |
688 | 23 | sc_log(ctx, |
689 | 23 | "iasecc_sdo_parse_data() parse IASECC_DOCP_TAG: 0x%X; size %"SC_FORMAT_LEN_SIZE_T"u", |
690 | 23 | tlv.tag, tlv.size); |
691 | 23 | rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo); |
692 | 23 | sc_log(ctx, "iasecc_sdo_parse_data() parsed IASECC_DOCP_TAG rv %i", rv); |
693 | 23 | free(tlv.value); |
694 | 23 | LOG_TEST_RET(ctx, rv, "parse error: cannot parse DOCP"); |
695 | 23 | } |
696 | 30 | else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION) { |
697 | 1 | free(sdo->docp.non_repudiation.value); |
698 | 1 | sdo->docp.non_repudiation = tlv; |
699 | 1 | } |
700 | 29 | else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING) { |
701 | 1 | free(sdo->docp.usage_remaining.value); |
702 | 1 | sdo->docp.usage_remaining = tlv; |
703 | 1 | } |
704 | 28 | else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM) { |
705 | 1 | free(sdo->docp.tries_maximum.value); |
706 | 1 | sdo->docp.tries_maximum = tlv; |
707 | 1 | } |
708 | 27 | else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING) { |
709 | 5 | free(sdo->docp.tries_remaining.value); |
710 | 5 | sdo->docp.tries_remaining = tlv; |
711 | 5 | } |
712 | 22 | else if (tlv.tag == IASECC_SDO_CHV_TAG) { |
713 | 3 | if (sdo->sdo_class != IASECC_SDO_CLASS_CHV) { |
714 | 0 | free(tlv.value); |
715 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: IASECC_SDO_CHV_TAG tag in non User CHV SDO"); |
716 | 0 | } |
717 | | |
718 | 3 | rv = iasecc_parse_chv(card, tlv.value, tlv.size, &sdo->data.chv); |
719 | 3 | free(tlv.value); |
720 | 3 | LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO CHV data"); |
721 | 3 | } |
722 | 19 | else if (tlv.tag == IASECC_SDO_PUBKEY_TAG) { |
723 | 0 | if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PUBLIC) { |
724 | 0 | free(tlv.value); |
725 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PUBLIC_KEY tag in non PUBLIC_KEY SDO"); |
726 | 0 | } |
727 | | |
728 | 0 | rv = iasecc_parse_pubkey(card, tlv.value, tlv.size, &sdo->data.pub_key); |
729 | 0 | free(tlv.value); |
730 | 0 | LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PUBLIC KEY data"); |
731 | 0 | } |
732 | 19 | else if (tlv.tag == IASECC_SDO_PRVKEY_TAG) { |
733 | 0 | if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PRIVATE) { |
734 | 0 | free(tlv.value); |
735 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PRIVATE_KEY tag in non PRIVATE_KEY SDO"); |
736 | 0 | } |
737 | | |
738 | 0 | rv = iasecc_parse_prvkey(card, tlv.value, tlv.size, &sdo->data.prv_key); |
739 | 0 | free(tlv.value); |
740 | 0 | LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PRIVATE KEY data"); |
741 | 0 | } |
742 | 19 | else if (tlv.tag == IASECC_SDO_KEYSET_TAG) { |
743 | 1 | if (sdo->sdo_class != IASECC_SDO_CLASS_KEYSET) { |
744 | 1 | free(tlv.value); |
745 | 1 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_KEYSET tag in non KEYSET SDO"); |
746 | 1 | } |
747 | | |
748 | 0 | rv = iasecc_parse_keyset(card, tlv.value, tlv.size, &sdo->data.keyset); |
749 | 0 | free(tlv.value); |
750 | 0 | LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO KEYSET data"); |
751 | 0 | } |
752 | 18 | else { |
753 | 18 | sc_log(ctx, "iasecc_sdo_parse_data() non supported tag 0x%X", tlv.tag); |
754 | 18 | free(tlv.value); |
755 | 18 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
756 | 18 | } |
757 | | |
758 | 14 | return tlv_size; |
759 | 53 | } |
760 | | |
761 | | |
762 | | int |
763 | | iasecc_sdo_parse(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo) |
764 | 95 | { |
765 | 95 | struct sc_context *ctx = card->ctx; |
766 | 95 | size_t size, offs; |
767 | 95 | int size_size; |
768 | 95 | int rv; |
769 | | |
770 | 95 | LOG_FUNC_CALLED(ctx); |
771 | | |
772 | 95 | if (data == NULL || data_len < 2) |
773 | 95 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
774 | | |
775 | 78 | if (*data == IASECC_SDO_TEMPLATE_TAG) { |
776 | 5 | size_size = iasecc_parse_size(data + 1, data_len - 1, &size); |
777 | 5 | LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE"); |
778 | | |
779 | 2 | data += size_size + 1; |
780 | 2 | data_len = size; |
781 | 2 | sc_log(ctx, |
782 | 2 | "IASECC_SDO_TEMPLATE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %d", |
783 | 2 | size, size_size); |
784 | 2 | } |
785 | | |
786 | 75 | if (*data != IASECC_SDO_TAG_HEADER) |
787 | 75 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
788 | | |
789 | 65 | if (sdo->sdo_class != (*(data + 1) & 0x7F)) |
790 | 65 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
791 | | |
792 | 64 | if (sdo->sdo_ref != (*(data + 2) & 0x3F)) |
793 | 64 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
794 | | |
795 | 60 | size_size = iasecc_parse_size(data + 3, data_len - 3, &size); |
796 | 60 | LOG_TEST_RET(ctx, size_size, "parse error: invalid size data"); |
797 | | |
798 | 59 | if (data_len != size + size_size + 3) |
799 | 59 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size"); |
800 | | |
801 | 44 | sc_log(ctx, |
802 | 44 | "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %d", |
803 | 44 | size, size_size); |
804 | | |
805 | 44 | offs = 3 + size_size; |
806 | 58 | for (; offs < data_len;) { |
807 | 57 | rv = iasecc_sdo_parse_data(card, data + offs, data_len - offs, sdo); |
808 | 57 | if (rv != SC_SUCCESS) { |
809 | 57 | iasecc_sdo_free_fields(card, sdo); |
810 | 57 | LOG_TEST_RET(ctx, rv, "parse error: invalid SDO data"); |
811 | 57 | } |
812 | | |
813 | 14 | offs += rv; |
814 | 14 | } |
815 | | |
816 | 1 | if (offs != data_len) |
817 | 1 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed"); |
818 | | |
819 | 1 | sc_log(ctx, |
820 | 1 | "docp.acls_contact.size %"SC_FORMAT_LEN_SIZE_T"u, docp.size.size %"SC_FORMAT_LEN_SIZE_T"u", |
821 | 1 | sdo->docp.acls_contact.size, sdo->docp.size.size); |
822 | | |
823 | 1 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
824 | 1 | } |
825 | | |
826 | | |
827 | | int |
828 | | iasecc_sdo_allocate_and_parse(struct sc_card *card, unsigned char *data, size_t data_len, |
829 | | struct iasecc_sdo **out) |
830 | 11 | { |
831 | 11 | struct sc_context *ctx = card->ctx; |
832 | 11 | struct iasecc_sdo *sdo = NULL; |
833 | 11 | size_t size, offs; |
834 | 11 | int size_size; |
835 | 11 | int rv; |
836 | | |
837 | 11 | LOG_FUNC_CALLED(ctx); |
838 | | |
839 | 11 | if (*data != IASECC_SDO_TAG_HEADER) |
840 | 11 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
841 | | |
842 | 11 | if (data_len < 3) |
843 | 11 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
844 | | |
845 | 11 | sdo = calloc(1, sizeof(struct iasecc_sdo)); |
846 | 11 | if (!sdo) |
847 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
848 | 11 | *out = sdo; |
849 | | |
850 | 11 | sdo->sdo_class = *(data + 1) & 0x7F; |
851 | 11 | sdo->sdo_ref = *(data + 2) & 0x3F; |
852 | | |
853 | 11 | sc_log(ctx, "sdo_class 0x%X, sdo_ref 0x%X", sdo->sdo_class, sdo->sdo_ref); |
854 | 11 | if (data_len == 3) |
855 | 11 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
856 | | |
857 | 0 | size_size = iasecc_parse_size(data + 3, data_len - 3, &size); |
858 | 0 | LOG_TEST_RET(ctx, size_size, "parse error: invalid size data"); |
859 | | |
860 | 0 | if (data_len != size + size_size + 3) |
861 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size"); |
862 | | |
863 | 0 | sc_log(ctx, |
864 | 0 | "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %d", |
865 | 0 | size, size_size); |
866 | |
|
867 | 0 | offs = 3 + size_size; |
868 | 0 | for (; offs < data_len;) { |
869 | 0 | rv = iasecc_sdo_parse_data(card, data + offs, data_len - offs, sdo); |
870 | 0 | LOG_TEST_RET(ctx, rv, "parse error: invalid SDO data"); |
871 | | |
872 | 0 | offs += rv; |
873 | 0 | } |
874 | | |
875 | 0 | if (offs != data_len) |
876 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed"); |
877 | | |
878 | 0 | sc_log(ctx, |
879 | 0 | "docp.acls_contact.size %"SC_FORMAT_LEN_SIZE_T"u; docp.size.size %"SC_FORMAT_LEN_SIZE_T"u", |
880 | 0 | sdo->docp.acls_contact.size, sdo->docp.size.size); |
881 | |
|
882 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
883 | 0 | } |
884 | | |
885 | | |
886 | | static int |
887 | | iasecc_update_blob(struct sc_context *ctx, struct iasecc_extended_tlv *tlv, |
888 | | unsigned char **blob, size_t *blob_size) |
889 | 0 | { |
890 | 0 | unsigned char *pp = NULL; |
891 | 0 | size_t offs = 0, sz; |
892 | |
|
893 | 0 | if (tlv->size == 0) |
894 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
895 | | |
896 | 0 | sz = tlv->size + 2; |
897 | |
|
898 | 0 | if (tlv->tag > 0xFF) |
899 | 0 | sz += 1; |
900 | |
|
901 | 0 | if (tlv->size > 0x7F && tlv->size < 0x100) |
902 | 0 | sz += 1; |
903 | 0 | else if (tlv->size >= 0x100) |
904 | 0 | sz += 2; |
905 | |
|
906 | 0 | pp = realloc(*blob, *blob_size + sz); |
907 | 0 | if (!pp) |
908 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
909 | | |
910 | 0 | if (tlv->tag > 0xFF) |
911 | 0 | *(pp + *blob_size + offs++) = (tlv->tag >> 8) & 0xFF; |
912 | 0 | *(pp + *blob_size + offs++) = tlv->tag & 0xFF; |
913 | |
|
914 | 0 | if (tlv->size >= 0x100) { |
915 | 0 | *(pp + *blob_size + offs++) = 0x82; |
916 | 0 | *(pp + *blob_size + offs++) = (tlv->size >> 8) & 0xFF; |
917 | 0 | } |
918 | 0 | else if (tlv->size > 0x7F) { |
919 | 0 | *(pp + *blob_size + offs++) = 0x81; |
920 | 0 | } |
921 | 0 | *(pp + *blob_size + offs++) = tlv->size & 0xFF; |
922 | |
|
923 | 0 | memcpy(pp + *blob_size + offs, tlv->value, tlv->size); |
924 | |
|
925 | 0 | *blob_size += sz; |
926 | 0 | *blob = pp; |
927 | |
|
928 | 0 | return 0; |
929 | 0 | } |
930 | | |
931 | | |
932 | | static int |
933 | | iasecc_encode_docp(struct sc_context *ctx, struct iasecc_sdo_docp *docp, unsigned char **out, size_t *out_len) |
934 | 0 | { |
935 | 0 | struct iasecc_extended_tlv tlv, tlv_st; |
936 | 0 | unsigned char *st_blob = NULL, *tmp_blob = NULL, *docp_blob = NULL; |
937 | 0 | size_t blob_size; |
938 | 0 | int rv; |
939 | |
|
940 | 0 | LOG_FUNC_CALLED(ctx); |
941 | 0 | if (!docp->acls_contact.size || (docp->size.size != 2)) |
942 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
943 | | |
944 | 0 | memset(&tlv, 0, sizeof(tlv)); |
945 | 0 | memset(&tlv_st, 0, sizeof(tlv_st)); |
946 | |
|
947 | 0 | blob_size = 0; |
948 | 0 | rv = iasecc_update_blob(ctx, &docp->acls_contact, &st_blob, &blob_size); |
949 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add contact ACLs to blob"); |
950 | | |
951 | 0 | rv = iasecc_update_blob(ctx, &docp->acls_contactless, &st_blob, &blob_size); |
952 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add contactless ACLs to blob"); |
953 | | |
954 | 0 | tlv.tag = IASECC_DOCP_TAG_ACLS; |
955 | 0 | tlv.size = blob_size; |
956 | 0 | tlv.value = st_blob; |
957 | |
|
958 | 0 | blob_size = 0; |
959 | 0 | rv = iasecc_update_blob(ctx, &tlv, &tmp_blob, &blob_size); |
960 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add ACLs template to blob"); |
961 | | |
962 | 0 | rv = iasecc_update_blob(ctx, &docp->name, &tmp_blob, &blob_size); |
963 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add NAME to blob"); |
964 | | |
965 | 0 | rv = iasecc_update_blob(ctx, &docp->tries_maximum, &tmp_blob, &blob_size); |
966 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add TRIES MAXIMUM to blob"); |
967 | | |
968 | 0 | rv = iasecc_update_blob(ctx, &docp->tries_remaining, &tmp_blob, &blob_size); |
969 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add TRIES REMAINING to blob"); |
970 | | |
971 | 0 | rv = iasecc_update_blob(ctx, &docp->usage_maximum, &tmp_blob, &blob_size); |
972 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add USAGE MAXIMUM to blob"); |
973 | | |
974 | 0 | rv = iasecc_update_blob(ctx, &docp->usage_remaining, &tmp_blob, &blob_size); |
975 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add USAGE REMAINING to blob"); |
976 | | |
977 | 0 | rv = iasecc_update_blob(ctx, &docp->non_repudiation, &tmp_blob, &blob_size); |
978 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add NON REPUDIATION to blob"); |
979 | | |
980 | 0 | rv = iasecc_update_blob(ctx, &docp->size, &tmp_blob, &blob_size); |
981 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add SIZE to blob"); |
982 | | |
983 | 0 | rv = iasecc_update_blob(ctx, &docp->issuer_data, &tmp_blob, &blob_size); |
984 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add IDATA to blob"); |
985 | | |
986 | 0 | tlv.tag = IASECC_DOCP_TAG; |
987 | 0 | tlv.size = blob_size; |
988 | 0 | tlv.value = tmp_blob; |
989 | |
|
990 | 0 | blob_size = 0; |
991 | 0 | rv = iasecc_update_blob(ctx, &tlv, &docp_blob, &blob_size); |
992 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add ACLs to blob"); |
993 | | |
994 | 0 | if (out && out_len) { |
995 | 0 | *out = docp_blob; |
996 | 0 | *out_len = blob_size; |
997 | 0 | docp_blob = NULL; |
998 | 0 | } |
999 | |
|
1000 | 0 | err: |
1001 | 0 | free(docp_blob); |
1002 | 0 | free(tmp_blob); |
1003 | 0 | free(st_blob); |
1004 | |
|
1005 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1006 | 0 | } |
1007 | | |
1008 | | |
1009 | | static unsigned |
1010 | | iasecc_sdo_encode_asn1_tag(unsigned in_tag) |
1011 | 0 | { |
1012 | 0 | unsigned short_tag; |
1013 | 0 | unsigned out_tag; |
1014 | |
|
1015 | 0 | for (short_tag = in_tag; short_tag > 0xFF; short_tag >>= 8) |
1016 | 0 | ; |
1017 | 0 | out_tag = in_tag; |
1018 | 0 | switch (short_tag & SC_ASN1_TAG_CLASS) { |
1019 | 0 | case SC_ASN1_TAG_APPLICATION: |
1020 | 0 | out_tag |= SC_ASN1_APP; |
1021 | 0 | break; |
1022 | 0 | case SC_ASN1_TAG_CONTEXT: |
1023 | 0 | out_tag |= SC_ASN1_CTX; |
1024 | 0 | break; |
1025 | 0 | case SC_ASN1_TAG_PRIVATE: |
1026 | 0 | out_tag |= SC_ASN1_PRV; |
1027 | 0 | break; |
1028 | 0 | } |
1029 | 0 | return out_tag; |
1030 | 0 | } |
1031 | | |
1032 | | |
1033 | | int |
1034 | | iasecc_sdo_encode_create(struct sc_context *ctx, struct iasecc_sdo *sdo, unsigned char **out) |
1035 | 0 | { |
1036 | 0 | struct sc_asn1_entry c_asn1_docp_data[2] = { |
1037 | 0 | { "docpData", SC_ASN1_OCTET_STRING, 0, SC_ASN1_ALLOC, NULL, NULL }, |
1038 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
1039 | 0 | }; |
1040 | 0 | struct sc_asn1_entry c_asn1_create_data[2] = { |
1041 | 0 | { "createData", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_APP | SC_ASN1_CONS, 0, NULL, NULL }, |
1042 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
1043 | 0 | }; |
1044 | 0 | struct sc_asn1_entry asn1_docp_data[2], asn1_create_data[2]; |
1045 | 0 | unsigned char *blob = NULL; |
1046 | 0 | size_t len, out_len; |
1047 | 0 | unsigned sdo_full_ref; |
1048 | 0 | int rv; |
1049 | |
|
1050 | 0 | LOG_FUNC_CALLED(ctx); |
1051 | 0 | sc_log(ctx, "ecc_sdo_encode_create() sdo->sdo_class %X", sdo->sdo_class); |
1052 | 0 | sc_log(ctx, "id %02X%02X%02X", IASECC_SDO_TAG_HEADER, sdo->sdo_class | 0x80, sdo->sdo_ref); |
1053 | |
|
1054 | 0 | if (out) |
1055 | 0 | *out = NULL; |
1056 | |
|
1057 | 0 | rv = iasecc_encode_docp(ctx, &sdo->docp, &blob, &len); |
1058 | 0 | LOG_TEST_RET(ctx, rv, "ECC encode DOCP error"); |
1059 | | |
1060 | 0 | sdo_full_ref = (sdo->sdo_ref&0x3F) + 0x100*(sdo->sdo_class | IASECC_OBJECT_REF_LOCAL) + 0x10000*IASECC_SDO_TAG_HEADER; |
1061 | 0 | c_asn1_docp_data[0].tag = iasecc_sdo_encode_asn1_tag(sdo_full_ref) | SC_ASN1_CONS; |
1062 | |
|
1063 | 0 | sc_copy_asn1_entry(c_asn1_docp_data, asn1_docp_data); |
1064 | 0 | sc_copy_asn1_entry(c_asn1_create_data, asn1_create_data); |
1065 | |
|
1066 | 0 | sc_format_asn1_entry(asn1_docp_data + 0, blob, &len, 1); |
1067 | 0 | sc_format_asn1_entry(asn1_create_data + 0, asn1_docp_data, NULL, 1); |
1068 | |
|
1069 | 0 | rv = sc_asn1_encode(ctx, asn1_create_data, out, &out_len); |
1070 | 0 | LOG_TEST_RET(ctx, rv, "Encode create data error"); |
1071 | 0 | if (out) |
1072 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Create data: %s", sc_dump_hex(*out, out_len)); |
1073 | |
|
1074 | 0 | LOG_FUNC_RETURN(ctx, (int)out_len); |
1075 | 0 | } |
1076 | | |
1077 | | |
1078 | | int |
1079 | | iasecc_sdo_encode_update_field(struct sc_context *ctx, unsigned char sdo_class, unsigned char sdo_ref, |
1080 | | struct iasecc_extended_tlv *tlv, unsigned char **out) |
1081 | 0 | { |
1082 | 0 | unsigned sdo_full_ref; |
1083 | 0 | size_t out_len; |
1084 | 0 | int rv; |
1085 | |
|
1086 | 0 | struct sc_asn1_entry c_asn1_field_value[2] = { |
1087 | 0 | { "fieldValue", SC_ASN1_OCTET_STRING, 0, SC_ASN1_ALLOC, NULL, NULL }, |
1088 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
1089 | 0 | }; |
1090 | 0 | struct sc_asn1_entry c_asn1_sdo_field[2] = { |
1091 | 0 | { "sdoField", SC_ASN1_STRUCT, 0, 0, NULL, NULL }, |
1092 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
1093 | 0 | }; |
1094 | 0 | struct sc_asn1_entry c_asn1_class_data[2] = { |
1095 | 0 | { "classData", SC_ASN1_STRUCT, 0, 0, NULL, NULL }, |
1096 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
1097 | 0 | }; |
1098 | 0 | struct sc_asn1_entry c_asn1_update_data[2] = { |
1099 | 0 | { "updateData", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_APP | SC_ASN1_CONS, 0, NULL, NULL }, |
1100 | 0 | { NULL, 0, 0, 0, NULL, NULL } |
1101 | 0 | }; |
1102 | 0 | struct sc_asn1_entry asn1_field_value[4], asn1_sdo_field[2], asn1_class_data[2], asn1_update_data[2]; |
1103 | |
|
1104 | 0 | LOG_FUNC_CALLED(ctx); |
1105 | |
|
1106 | 0 | c_asn1_field_value[0].tag = iasecc_sdo_encode_asn1_tag(tlv->tag); |
1107 | 0 | c_asn1_sdo_field[0].tag = iasecc_sdo_encode_asn1_tag(tlv->parent_tag) | SC_ASN1_CONS; |
1108 | |
|
1109 | 0 | sdo_full_ref = (sdo_ref&0x3F) + 0x100*(sdo_class | IASECC_OBJECT_REF_LOCAL) + 0x10000*IASECC_SDO_TAG_HEADER; |
1110 | 0 | c_asn1_class_data[0].tag = iasecc_sdo_encode_asn1_tag(sdo_full_ref) | SC_ASN1_CONS; |
1111 | |
|
1112 | 0 | sc_copy_asn1_entry(c_asn1_field_value, asn1_field_value); |
1113 | 0 | sc_copy_asn1_entry(c_asn1_sdo_field, asn1_sdo_field); |
1114 | 0 | sc_copy_asn1_entry(c_asn1_class_data, asn1_class_data); |
1115 | 0 | sc_copy_asn1_entry(c_asn1_update_data, asn1_update_data); |
1116 | |
|
1117 | 0 | sc_format_asn1_entry(asn1_field_value + 0, tlv->value, &tlv->size, 1); |
1118 | 0 | sc_format_asn1_entry(asn1_sdo_field + 0, asn1_field_value, NULL, 1); |
1119 | 0 | sc_format_asn1_entry(asn1_class_data + 0, asn1_sdo_field, NULL, 1); |
1120 | 0 | sc_format_asn1_entry(asn1_update_data + 0, asn1_class_data, NULL, 1); |
1121 | |
|
1122 | 0 | rv = sc_asn1_encode(ctx, asn1_update_data, out, &out_len); |
1123 | 0 | LOG_TEST_RET(ctx, rv, "Encode update data error"); |
1124 | | |
1125 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Data: %s", sc_dump_hex(tlv->value, tlv->size)); |
1126 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Encoded: %s", sc_dump_hex(*out, out_len)); |
1127 | 0 | LOG_FUNC_RETURN(ctx, (int)out_len); |
1128 | 0 | } |
1129 | | |
1130 | | |
1131 | | int |
1132 | | iasecc_sdo_encode_rsa_update(struct sc_context *ctx, struct iasecc_sdo *sdo, struct sc_pkcs15_prkey_rsa *rsa, |
1133 | | struct iasecc_sdo_update *sdo_update) |
1134 | 0 | { |
1135 | 0 | LOG_FUNC_CALLED(ctx); |
1136 | |
|
1137 | 0 | sc_log(ctx, "iasecc_sdo_encode_rsa_update() SDO class %X", sdo->sdo_class); |
1138 | 0 | memset(sdo_update, 0, sizeof(*sdo_update)); |
1139 | 0 | if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PRIVATE) { |
1140 | 0 | int index = 0; |
1141 | |
|
1142 | 0 | sc_log(ctx, "iasecc_sdo_encode_rsa_update(IASECC_SDO_CLASS_RSA_PRIVATE)"); |
1143 | 0 | if (!rsa->p.len || !rsa->q.len || !rsa->iqmp.len || !rsa->dmp1.len || !rsa->dmq1.len) |
1144 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "need all private RSA key components"); |
1145 | | |
1146 | 0 | sdo_update->magic = SC_CARDCTL_IASECC_SDO_MAGIC_PUT_DATA; |
1147 | 0 | sdo_update->sdo_ref = sdo->sdo_ref; |
1148 | |
|
1149 | 0 | sdo_update->sdo_class = IASECC_SDO_CLASS_RSA_PRIVATE; |
1150 | |
|
1151 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PRVKEY_TAG; |
1152 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PRVKEY_TAG_P; |
1153 | 0 | sdo_update->fields[index].value = rsa->p.data; |
1154 | 0 | sdo_update->fields[index].size = rsa->p.len; |
1155 | 0 | index++; |
1156 | |
|
1157 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PRVKEY_TAG; |
1158 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PRVKEY_TAG_Q; |
1159 | 0 | sdo_update->fields[index].value = rsa->q.data; |
1160 | 0 | sdo_update->fields[index].size = rsa->q.len; |
1161 | 0 | index++; |
1162 | |
|
1163 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PRVKEY_TAG; |
1164 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PRVKEY_TAG_IQMP; |
1165 | 0 | sdo_update->fields[index].value = rsa->iqmp.data; |
1166 | 0 | sdo_update->fields[index].size = rsa->iqmp.len; |
1167 | 0 | index++; |
1168 | |
|
1169 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PRVKEY_TAG; |
1170 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PRVKEY_TAG_DMP1; |
1171 | 0 | sdo_update->fields[index].value = rsa->dmp1.data; |
1172 | 0 | sdo_update->fields[index].size = rsa->dmp1.len; |
1173 | 0 | index++; |
1174 | |
|
1175 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PRVKEY_TAG; |
1176 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PRVKEY_TAG_DMQ1; |
1177 | 0 | sdo_update->fields[index].value = rsa->dmq1.data; |
1178 | 0 | sdo_update->fields[index].size = rsa->dmq1.len; |
1179 | 0 | index++; |
1180 | |
|
1181 | 0 | sc_log(ctx, "prv_key.compulsory.on_card %i", sdo->data.prv_key.compulsory.on_card); |
1182 | 0 | if (!sdo->data.prv_key.compulsory.on_card) { |
1183 | 0 | if (sdo->data.prv_key.compulsory.value) { |
1184 | 0 | sc_log(ctx, |
1185 | 0 | "sdo_prvkey->data.prv_key.compulsory.size %"SC_FORMAT_LEN_SIZE_T"u", |
1186 | 0 | sdo->data.prv_key.compulsory.size); |
1187 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PRVKEY_TAG; |
1188 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PRVKEY_TAG_COMPULSORY; |
1189 | 0 | sdo_update->fields[index].value = sdo->data.prv_key.compulsory.value; |
1190 | 0 | sdo_update->fields[index].size = sdo->data.prv_key.compulsory.size; |
1191 | 0 | index++; |
1192 | 0 | } |
1193 | 0 | } |
1194 | 0 | } |
1195 | 0 | else if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PUBLIC) { |
1196 | 0 | int index = 0; |
1197 | 0 | sc_log(ctx, "iasecc_sdo_encode_rsa_update(IASECC_SDO_CLASS_RSA_PUBLIC)"); |
1198 | |
|
1199 | 0 | sdo_update->magic = SC_CARDCTL_IASECC_SDO_MAGIC_PUT_DATA; |
1200 | 0 | sdo_update->sdo_ref = sdo->sdo_ref; |
1201 | 0 | sdo_update->sdo_class = sdo->sdo_class; |
1202 | |
|
1203 | 0 | if (rsa->exponent.len) { |
1204 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PUBKEY_TAG; |
1205 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PUBKEY_TAG_E; |
1206 | 0 | sdo_update->fields[index].value = rsa->exponent.data; |
1207 | 0 | sdo_update->fields[index].size = rsa->exponent.len; |
1208 | 0 | index++; |
1209 | 0 | } |
1210 | |
|
1211 | 0 | if (rsa->modulus.len) { |
1212 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PUBKEY_TAG; |
1213 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PUBKEY_TAG_N; |
1214 | 0 | sdo_update->fields[index].value = rsa->modulus.data; |
1215 | 0 | sdo_update->fields[index].size = rsa->modulus.len; |
1216 | 0 | index++; |
1217 | 0 | } |
1218 | |
|
1219 | 0 | if (sdo->data.pub_key.cha.value) { |
1220 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PUBKEY_TAG; |
1221 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PUBKEY_TAG_CHA; |
1222 | 0 | sdo_update->fields[index].value = sdo->data.pub_key.cha.value; |
1223 | 0 | sdo_update->fields[index].size = sdo->data.pub_key.cha.size; |
1224 | 0 | index++; |
1225 | 0 | } |
1226 | |
|
1227 | 0 | if (sdo->data.pub_key.chr.value) { |
1228 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PUBKEY_TAG; |
1229 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PUBKEY_TAG_CHR; |
1230 | 0 | sdo_update->fields[index].value = sdo->data.pub_key.chr.value; |
1231 | 0 | sdo_update->fields[index].size = sdo->data.pub_key.chr.size; |
1232 | 0 | index++; |
1233 | 0 | } |
1234 | | |
1235 | | /* For ECC card 'compulsory' flag should be already here */ |
1236 | 0 | if (!sdo->data.pub_key.compulsory.on_card) { |
1237 | 0 | if (sdo->data.pub_key.compulsory.value) { |
1238 | 0 | sdo_update->fields[index].parent_tag = IASECC_SDO_PUBKEY_TAG; |
1239 | 0 | sdo_update->fields[index].tag = IASECC_SDO_PUBKEY_TAG_COMPULSORY; |
1240 | 0 | sdo_update->fields[index].value = sdo->data.pub_key.compulsory.value; |
1241 | 0 | sdo_update->fields[index].size = sdo->data.pub_key.compulsory.size; |
1242 | 0 | index++; |
1243 | 0 | } |
1244 | 0 | } |
1245 | 0 | } |
1246 | 0 | else { |
1247 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
1248 | 0 | } |
1249 | | |
1250 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1251 | 0 | } |
1252 | | |
1253 | | |
1254 | | int |
1255 | | iasecc_sdo_parse_card_answer(struct sc_context *ctx, unsigned char *data, size_t data_len, |
1256 | | struct iasecc_sm_card_answer *out) |
1257 | 0 | { |
1258 | 0 | int have_mac = 0, have_status = 0; |
1259 | 0 | size_t size = 0, size_size, offs; |
1260 | |
|
1261 | 0 | LOG_FUNC_CALLED(ctx); |
1262 | 0 | if (!data || !data_len || !out) |
1263 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1264 | | |
1265 | 0 | memset(out, 0, sizeof(*out)); |
1266 | 0 | for (offs=0; offs<data_len; ) { |
1267 | 0 | size_size = iasecc_parse_size(data + 1, data_len - 1, &size); |
1268 | |
|
1269 | 0 | if (*(data + offs) == IASECC_CARD_ANSWER_TAG_DATA ) { |
1270 | 0 | if (size > sizeof(out->data)) |
1271 | 0 | LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "iasecc_sm_decode_answer() unbelievable !!!"); |
1272 | | |
1273 | 0 | memcpy(out->data, data + offs + size_size + 1, size); |
1274 | 0 | out->data_len = size; |
1275 | 0 | offs += 1 + size_size + size; |
1276 | 0 | } |
1277 | 0 | else if (*(data + offs) == IASECC_CARD_ANSWER_TAG_SW ) { |
1278 | 0 | if (*(data + offs + 1) != 2) |
1279 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() SW length not 2"); |
1280 | 0 | out->sw = *(data + offs + 2) * 0x100 + *(data + offs + 3); |
1281 | |
|
1282 | 0 | memcpy(out->ticket, data + offs, 4); |
1283 | |
|
1284 | 0 | offs += 4; |
1285 | 0 | have_status = 1; |
1286 | 0 | } |
1287 | 0 | else if (*(data + offs) == IASECC_CARD_ANSWER_TAG_MAC ) { |
1288 | 0 | if (*(data + offs + 1) != 8) |
1289 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() MAC length not 8"); |
1290 | 0 | memcpy(out->mac, data + offs + 2, 8); |
1291 | |
|
1292 | 0 | memcpy(out->ticket + 4, data + offs, 10); |
1293 | |
|
1294 | 0 | offs += 10; |
1295 | 0 | have_mac = 1; |
1296 | 0 | } |
1297 | 0 | else { |
1298 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() invalid card answer tag"); |
1299 | 0 | } |
1300 | 0 | } |
1301 | | |
1302 | 0 | if (!have_mac || !have_status) |
1303 | 0 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() absent MAC or SW "); |
1304 | | |
1305 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1306 | 0 | } |
1307 | | |
1308 | | |
1309 | | static int |
1310 | | iasecc_tlv_copy(struct sc_context *ctx, struct iasecc_extended_tlv *in, struct iasecc_extended_tlv *out) |
1311 | 90 | { |
1312 | 90 | if (!in || !out) |
1313 | 90 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1314 | | |
1315 | 90 | memset(out, 0, sizeof(struct iasecc_extended_tlv)); |
1316 | 90 | out->tag = in->tag; |
1317 | 90 | out->parent_tag = in->parent_tag; |
1318 | 90 | out->on_card = in->on_card; |
1319 | 90 | if (in->value && in->size) { |
1320 | 0 | out->value = calloc(1, in->size); |
1321 | 0 | if (!out->value) |
1322 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1323 | | |
1324 | 0 | memcpy(out->value, in->value, in->size); |
1325 | 0 | out->size = in->size; |
1326 | 0 | } |
1327 | | |
1328 | 90 | return SC_SUCCESS; |
1329 | 90 | } |
1330 | | |
1331 | | |
1332 | | int |
1333 | | iasecc_docp_copy(struct sc_context *ctx, struct iasecc_sdo_docp *in, struct iasecc_sdo_docp *out) |
1334 | 10 | { |
1335 | 10 | int rv; |
1336 | | |
1337 | 10 | LOG_FUNC_CALLED(ctx); |
1338 | 10 | if (!in || !out) |
1339 | 10 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1340 | | |
1341 | 10 | memset(out, 0, sizeof(struct iasecc_sdo_docp)); |
1342 | | |
1343 | 10 | rv = iasecc_tlv_copy(ctx, &in->name, &out->name); |
1344 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1345 | | |
1346 | 10 | rv = iasecc_tlv_copy(ctx, &in->tries_maximum, &out->tries_maximum); |
1347 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1348 | | |
1349 | 10 | rv = iasecc_tlv_copy(ctx, &in->tries_remaining, &out->tries_remaining); |
1350 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1351 | | |
1352 | 10 | rv = iasecc_tlv_copy(ctx, &in->usage_maximum, &out->usage_maximum); |
1353 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1354 | | |
1355 | 10 | rv = iasecc_tlv_copy(ctx, &in->usage_remaining, &out->usage_remaining); |
1356 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1357 | | |
1358 | 10 | rv = iasecc_tlv_copy(ctx, &in->non_repudiation, &out->non_repudiation); |
1359 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1360 | | |
1361 | 10 | rv = iasecc_tlv_copy(ctx, &in->size, &out->size); |
1362 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1363 | | |
1364 | 10 | rv = iasecc_tlv_copy(ctx, &in->acls_contact, &out->acls_contact); |
1365 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1366 | | |
1367 | 10 | rv = iasecc_tlv_copy(ctx, &in->acls_contactless, &out->acls_contactless); |
1368 | 10 | LOG_TEST_RET(ctx, rv, "TLV copy error"); |
1369 | | |
1370 | 10 | out->amb = in->amb; |
1371 | 10 | memcpy(out->scbs, in->scbs, sizeof(out->scbs)); |
1372 | | |
1373 | 10 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1374 | 10 | } |
1375 | | |
1376 | | #else |
1377 | | |
1378 | | /* we need to define the functions below to export them */ |
1379 | | #include "errors.h" |
1380 | | |
1381 | | int |
1382 | | iasecc_sdo_encode_update_field() |
1383 | | { |
1384 | | return SC_ERROR_NOT_SUPPORTED; |
1385 | | } |
1386 | | |
1387 | | int |
1388 | | iasecc_se_get_crt() |
1389 | | { |
1390 | | return SC_ERROR_NOT_SUPPORTED; |
1391 | | } |
1392 | | |
1393 | | #endif /* ENABLE_OPENSSL */ |