/src/opensc/src/sm/sm-iso.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2011-2015 Frank Morgner |
3 | | * |
4 | | * This file is part of OpenSC. |
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 | | #ifdef HAVE_CONFIG_H |
21 | | #include "config.h" |
22 | | #endif |
23 | | |
24 | | #include "sm-iso-internal.h" |
25 | | #include "libopensc/asn1.h" |
26 | | #include "libopensc/log.h" |
27 | | #include "sm/sm-iso.h" |
28 | | #include <stdlib.h> |
29 | | #include <string.h> |
30 | | |
31 | | #ifdef ENABLE_SM |
32 | | |
33 | | static const struct sc_asn1_entry c_sm_capdu[] = { |
34 | | { "Cryptogram", |
35 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x05, SC_ASN1_OPTIONAL, NULL, NULL }, |
36 | | { "Padding-content indicator followed by cryptogram", |
37 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL, NULL, NULL }, |
38 | | { "Protected Le", |
39 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x17, SC_ASN1_OPTIONAL, NULL, NULL }, |
40 | | { "Cryptographic Checksum", |
41 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x0E, SC_ASN1_OPTIONAL, NULL, NULL }, |
42 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
43 | | }; |
44 | | |
45 | | static const struct sc_asn1_entry c_sm_rapdu[] = { |
46 | | { "Cryptogram", |
47 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x05, SC_ASN1_OPTIONAL, NULL, NULL }, |
48 | | { "Padding-content indicator followed by cryptogram" , |
49 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL, NULL, NULL }, |
50 | | { "Processing Status", |
51 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x19, 0 , NULL, NULL }, |
52 | | { "Cryptographic Checksum", |
53 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x0E, SC_ASN1_OPTIONAL, NULL, NULL }, |
54 | | { NULL, 0, 0, 0, NULL, NULL } |
55 | | }; |
56 | | |
57 | | static int |
58 | | add_iso_pad(const u8 *data, size_t datalen, size_t block_size, u8 **padded) |
59 | 0 | { |
60 | 0 | u8 *p; |
61 | 0 | int p_len; |
62 | |
|
63 | 0 | if (!padded) |
64 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
65 | | |
66 | | /* calculate length of padded message */ |
67 | 0 | p_len = (int)((datalen / block_size) * block_size + block_size); |
68 | |
|
69 | 0 | p = realloc(*padded, p_len); |
70 | 0 | if (!p) |
71 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
72 | | |
73 | 0 | if (*padded != data) |
74 | 0 | memcpy(p, data, datalen); |
75 | |
|
76 | 0 | *padded = p; |
77 | | |
78 | | /* now add iso padding */ |
79 | 0 | memset(p + datalen, 0x80, 1); |
80 | 0 | memset(p + datalen + 1, 0, p_len - datalen - 1); |
81 | |
|
82 | 0 | return p_len; |
83 | 0 | } |
84 | | |
85 | | static int |
86 | | add_padding(const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen, |
87 | | u8 **padded) |
88 | 0 | { |
89 | 0 | u8 *p; |
90 | |
|
91 | 0 | switch (ctx->padding_indicator) { |
92 | 0 | case SM_NO_PADDING: |
93 | 0 | if (*padded != data) { |
94 | 0 | if (datalen != 0) { |
95 | 0 | p = realloc(*padded, datalen); |
96 | 0 | if (!p) |
97 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
98 | 0 | *padded = p; |
99 | 0 | memcpy(*padded, data, datalen); |
100 | 0 | } else { |
101 | 0 | *padded = NULL; |
102 | 0 | } |
103 | 0 | } |
104 | 0 | return (int)datalen; |
105 | 0 | case SM_ISO_PADDING: |
106 | 0 | return add_iso_pad(data, datalen, ctx->block_length, padded); |
107 | 0 | default: |
108 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | static int |
113 | | rm_padding(u8 padding_indicator, const u8 *data, size_t datalen) |
114 | 0 | { |
115 | 0 | size_t len; |
116 | |
|
117 | 0 | if (!datalen || !data) |
118 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
119 | | |
120 | 0 | switch (padding_indicator) { |
121 | 0 | case SM_NO_PADDING: |
122 | 0 | len = datalen; |
123 | 0 | break; |
124 | | |
125 | 0 | case SM_ISO_PADDING: |
126 | 0 | len = datalen; |
127 | |
|
128 | 0 | while (len) { |
129 | 0 | len--; |
130 | 0 | if (data[len]) |
131 | 0 | break; |
132 | 0 | } |
133 | |
|
134 | 0 | if (data[len] != 0x80) |
135 | 0 | return SC_ERROR_INVALID_DATA; |
136 | | |
137 | 0 | break; |
138 | | |
139 | 0 | default: |
140 | 0 | return SC_ERROR_NOT_SUPPORTED; |
141 | 0 | } |
142 | | |
143 | 0 | return (int)len; |
144 | 0 | } |
145 | | |
146 | | static int format_le(size_t le, struct sc_asn1_entry *le_entry, |
147 | | u8 **lebuf, size_t *le_len) |
148 | 0 | { |
149 | 0 | u8 *p; |
150 | |
|
151 | 0 | if (!lebuf || !le_len || !*le_len) |
152 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
153 | | |
154 | 0 | p = realloc(*lebuf, *le_len); |
155 | 0 | if (!p) |
156 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
157 | 0 | *lebuf = p; |
158 | |
|
159 | 0 | switch (*le_len) { |
160 | 0 | case 1: |
161 | 0 | p[0] = le & 0xff; |
162 | 0 | break; |
163 | 0 | case 2: |
164 | 0 | p[0] = (le >> 8) & 0xff; |
165 | 0 | p[1] = le & 0xff; |
166 | 0 | break; |
167 | 0 | case 3: |
168 | 0 | p[0] = 0x00; |
169 | 0 | p[1] = (le >> 8) & 0xff; |
170 | 0 | p[2] = le & 0xff; |
171 | 0 | break; |
172 | 0 | default: |
173 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
174 | 0 | } |
175 | | |
176 | 0 | sc_format_asn1_entry(le_entry, *lebuf, le_len, SC_ASN1_PRESENT); |
177 | |
|
178 | 0 | return SC_SUCCESS; |
179 | 0 | } |
180 | | |
181 | | static int prefix_buf(u8 prefix, u8 *buf, size_t buflen, u8 **cat) |
182 | 0 | { |
183 | 0 | u8 *p = NULL; |
184 | 0 | int ptr_same = *cat == buf; |
185 | |
|
186 | 0 | p = realloc(*cat, buflen + 1); |
187 | 0 | if (!p) |
188 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
189 | | |
190 | 0 | if (ptr_same) { |
191 | 0 | memmove(p + 1, p, buflen); |
192 | 0 | } else { |
193 | 0 | memcpy(p + 1, buf, buflen); |
194 | 0 | } |
195 | 0 | p[0] = prefix; |
196 | |
|
197 | 0 | *cat = p; |
198 | |
|
199 | 0 | return (int)buflen + 1; |
200 | 0 | } |
201 | | |
202 | | static int format_data(sc_card_t *card, const struct iso_sm_ctx *ctx, |
203 | | int prepend_padding_indicator, const u8 *data, size_t datalen, |
204 | | struct sc_asn1_entry *formatted_encrypted_data_entry, |
205 | | u8 **formatted_data, size_t *formatted_data_len) |
206 | 0 | { |
207 | 0 | int r; |
208 | 0 | u8 *pad_data = NULL; |
209 | 0 | size_t pad_data_len = 0; |
210 | |
|
211 | 0 | if (!ctx || !formatted_data || !formatted_data_len) { |
212 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
213 | 0 | goto err; |
214 | 0 | } |
215 | | |
216 | 0 | r = add_padding(ctx, data, datalen, &pad_data); |
217 | 0 | if (r < 0) { |
218 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not add padding to data: %s", |
219 | 0 | sc_strerror(r)); |
220 | 0 | goto err; |
221 | 0 | } |
222 | 0 | pad_data_len = r; |
223 | |
|
224 | 0 | sc_log_hex(card->ctx, "Data to encrypt", pad_data, pad_data_len); |
225 | 0 | r = ctx->encrypt(card, ctx, pad_data, pad_data_len, formatted_data); |
226 | 0 | if (r < 0) { |
227 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not encrypt the data"); |
228 | 0 | goto err; |
229 | 0 | } |
230 | 0 | sc_log_hex(card->ctx, "Cryptogram", *formatted_data, r); |
231 | |
|
232 | 0 | if (prepend_padding_indicator) { |
233 | 0 | r = prefix_buf(ctx->padding_indicator, *formatted_data, r, formatted_data); |
234 | 0 | if (r < 0) { |
235 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not prepend padding indicator to formatted " |
236 | 0 | "data: %s", sc_strerror(r)); |
237 | 0 | goto err; |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | 0 | *formatted_data_len = r; |
242 | 0 | sc_format_asn1_entry(formatted_encrypted_data_entry, |
243 | 0 | *formatted_data, formatted_data_len, SC_ASN1_PRESENT); |
244 | |
|
245 | 0 | r = SC_SUCCESS; |
246 | |
|
247 | 0 | err: |
248 | 0 | if (pad_data) { |
249 | 0 | sc_mem_clear(pad_data, pad_data_len); |
250 | 0 | free(pad_data); |
251 | 0 | } |
252 | |
|
253 | 0 | return r; |
254 | 0 | } |
255 | | |
256 | | static int format_head(const struct iso_sm_ctx *ctx, const sc_apdu_t *apdu, |
257 | | u8 **formatted_head) |
258 | 0 | { |
259 | 0 | u8 *p; |
260 | |
|
261 | 0 | if (!apdu || !formatted_head) |
262 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
263 | | |
264 | 0 | p = realloc(*formatted_head, 4); |
265 | 0 | if (!p) |
266 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
267 | | |
268 | 0 | p[0] = apdu->cla; |
269 | 0 | p[1] = apdu->ins; |
270 | 0 | p[2] = apdu->p1; |
271 | 0 | p[3] = apdu->p2; |
272 | 0 | *formatted_head = p; |
273 | |
|
274 | 0 | return add_padding(ctx, *formatted_head, 4, formatted_head); |
275 | 0 | } |
276 | | |
277 | | static int sm_encrypt(const struct iso_sm_ctx *ctx, sc_card_t *card, |
278 | | const sc_apdu_t *apdu, sc_apdu_t **psm_apdu) |
279 | 0 | { |
280 | 0 | struct sc_asn1_entry sm_capdu[5]; |
281 | 0 | u8 *p, *le = NULL, *sm_data = NULL, *fdata = NULL, *mac_data = NULL, |
282 | 0 | *asn1 = NULL, *mac = NULL, *resp_data = NULL; |
283 | 0 | size_t sm_data_len, fdata_len, mac_data_len, asn1_len, mac_len, le_len; |
284 | 0 | int r; |
285 | 0 | sc_apdu_t *sm_apdu = NULL; |
286 | |
|
287 | 0 | if (!apdu || !ctx || !card || !card->reader || !psm_apdu) { |
288 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
289 | 0 | goto err; |
290 | 0 | } |
291 | | |
292 | 0 | if ((apdu->cla & 0x0C) == 0x0C) { |
293 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
294 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Given APDU is already protected with some secure messaging"); |
295 | 0 | goto err; |
296 | 0 | } |
297 | | |
298 | 0 | sc_copy_asn1_entry(c_sm_capdu, sm_capdu); |
299 | |
|
300 | 0 | sm_apdu = malloc(sizeof(sc_apdu_t)); |
301 | 0 | if (!sm_apdu) { |
302 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
303 | 0 | goto err; |
304 | 0 | } |
305 | 0 | sm_apdu->control = apdu->control; |
306 | 0 | sm_apdu->flags = apdu->flags; |
307 | 0 | sm_apdu->cla = apdu->cla|0x0C; |
308 | 0 | sm_apdu->ins = apdu->ins; |
309 | 0 | sm_apdu->p1 = apdu->p1; |
310 | 0 | sm_apdu->p2 = apdu->p2; |
311 | 0 | r = format_head(ctx, sm_apdu, &mac_data); |
312 | 0 | if (r < 0) { |
313 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format header of SM apdu"); |
314 | 0 | goto err; |
315 | 0 | } |
316 | 0 | mac_data_len = r; |
317 | |
|
318 | 0 | switch (apdu->cse) { |
319 | 0 | case SC_APDU_CASE_1: |
320 | 0 | break; |
321 | 0 | case SC_APDU_CASE_2_SHORT: |
322 | 0 | le_len = 1; |
323 | 0 | r = format_le(apdu->le, sm_capdu + 2, &le, &le_len); |
324 | 0 | if (r < 0) { |
325 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); |
326 | 0 | goto err; |
327 | 0 | } |
328 | 0 | sc_log_hex(card->ctx, "Protected Le (plain)", le, le_len); |
329 | 0 | break; |
330 | 0 | case SC_APDU_CASE_2_EXT: |
331 | 0 | if (card->reader->active_protocol == SC_PROTO_T0) { |
332 | | /* T0 extended APDUs look just like short APDUs */ |
333 | 0 | le_len = 1; |
334 | 0 | r = format_le(apdu->le, sm_capdu + 2, &le, &le_len); |
335 | 0 | if (r < 0) { |
336 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); |
337 | 0 | goto err; |
338 | 0 | } |
339 | 0 | } else { |
340 | | /* in case of T1 always use 2 bytes for length */ |
341 | 0 | le_len = 2; |
342 | 0 | r = format_le(apdu->le, sm_capdu + 2, &le, &le_len); |
343 | 0 | if (r < 0) { |
344 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); |
345 | 0 | goto err; |
346 | 0 | } |
347 | 0 | } |
348 | 0 | sc_log_hex(card->ctx, "Protected Le (plain)", le, le_len); |
349 | 0 | break; |
350 | 0 | case SC_APDU_CASE_3_SHORT: |
351 | 0 | case SC_APDU_CASE_3_EXT: |
352 | 0 | if (apdu->ins & 1) { |
353 | 0 | r = format_data(card, ctx, 0, apdu->data, apdu->datalen, |
354 | 0 | sm_capdu + 0, &fdata, &fdata_len); |
355 | 0 | } else { |
356 | 0 | r = format_data(card, ctx, 1, apdu->data, apdu->datalen, |
357 | 0 | sm_capdu + 1, &fdata, &fdata_len); |
358 | 0 | } |
359 | 0 | if (r < 0) { |
360 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu"); |
361 | 0 | goto err; |
362 | 0 | } |
363 | 0 | sc_log_hex(card->ctx, "Padding-content indicator followed by cryptogram (plain)", |
364 | 0 | fdata, fdata_len); |
365 | 0 | break; |
366 | 0 | case SC_APDU_CASE_4_SHORT: |
367 | | /* in case of T0 no Le byte is added */ |
368 | 0 | if (card->reader->active_protocol != SC_PROTO_T0) { |
369 | 0 | le_len = 1; |
370 | 0 | r = format_le(apdu->le, sm_capdu + 2, &le, &le_len); |
371 | 0 | if (r < 0) { |
372 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); |
373 | 0 | goto err; |
374 | 0 | } |
375 | 0 | sc_log_hex(card->ctx, "Protected Le (plain)", le, le_len); |
376 | 0 | } |
377 | | |
378 | 0 | if (apdu->ins & 1) { |
379 | 0 | r = format_data(card, ctx, 0, apdu->data, apdu->datalen, |
380 | 0 | sm_capdu + 0, &fdata, &fdata_len); |
381 | 0 | } else { |
382 | 0 | r = format_data(card, ctx, 1, apdu->data, apdu->datalen, |
383 | 0 | sm_capdu + 1, &fdata, &fdata_len); |
384 | 0 | } |
385 | 0 | if (r < 0) { |
386 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu"); |
387 | 0 | goto err; |
388 | 0 | } |
389 | 0 | sc_log_hex(card->ctx, "Padding-content indicator followed by cryptogram (plain)", |
390 | 0 | fdata, fdata_len); |
391 | 0 | break; |
392 | 0 | case SC_APDU_CASE_4_EXT: |
393 | 0 | if (card->reader->active_protocol == SC_PROTO_T0) { |
394 | | /* again a T0 extended case 4 APDU looks just |
395 | | * like a short APDU, the additional data is |
396 | | * transferred using ENVELOPE and GET RESPONSE */ |
397 | 0 | } else { |
398 | | /* only 2 bytes are use to specify the length of the |
399 | | * expected data */ |
400 | 0 | le_len = 2; |
401 | 0 | r = format_le(apdu->le, sm_capdu + 2, &le, &le_len); |
402 | 0 | if (r < 0) { |
403 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); |
404 | 0 | goto err; |
405 | 0 | } |
406 | 0 | sc_log_hex(card->ctx, "Protected Le (plain)", le, le_len); |
407 | 0 | } |
408 | | |
409 | 0 | if (apdu->ins & 1) { |
410 | 0 | r = format_data(card, ctx, 0, apdu->data, apdu->datalen, |
411 | 0 | sm_capdu + 0, &fdata, &fdata_len); |
412 | 0 | } else { |
413 | 0 | r = format_data(card, ctx, 1, apdu->data, apdu->datalen, |
414 | 0 | sm_capdu + 1, &fdata, &fdata_len); |
415 | 0 | } |
416 | 0 | if (r < 0) { |
417 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu"); |
418 | 0 | goto err; |
419 | 0 | } |
420 | 0 | sc_log_hex(card->ctx, "Padding-content indicator followed by cryptogram (plain)", |
421 | 0 | fdata, fdata_len); |
422 | 0 | break; |
423 | 0 | default: |
424 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Unhandled apdu case"); |
425 | 0 | r = SC_ERROR_INVALID_DATA; |
426 | 0 | goto err; |
427 | 0 | } |
428 | | |
429 | | |
430 | 0 | r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &asn1, &asn1_len); |
431 | 0 | if (r < 0) { |
432 | 0 | goto err; |
433 | 0 | } |
434 | 0 | if (asn1_len) { |
435 | 0 | p = realloc(mac_data, mac_data_len + asn1_len); |
436 | 0 | if (!p) { |
437 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
438 | 0 | goto err; |
439 | 0 | } |
440 | 0 | mac_data = p; |
441 | 0 | memcpy(mac_data + mac_data_len, asn1, asn1_len); |
442 | 0 | mac_data_len += asn1_len; |
443 | 0 | r = add_padding(ctx, mac_data, mac_data_len, &mac_data); |
444 | 0 | if (r < 0) { |
445 | 0 | goto err; |
446 | 0 | } |
447 | 0 | mac_data_len = r; |
448 | 0 | } |
449 | 0 | sc_log_hex(card->ctx, "Data to authenticate", mac_data, mac_data_len); |
450 | |
|
451 | 0 | r = ctx->authenticate(card, ctx, mac_data, mac_data_len, |
452 | 0 | &mac); |
453 | 0 | if (r < 0) { |
454 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get authentication code"); |
455 | 0 | goto err; |
456 | 0 | } |
457 | 0 | mac_len = r; |
458 | 0 | sc_log_hex(card->ctx, "Cryptographic Checksum (plain)", mac, mac_len); |
459 | | |
460 | | |
461 | | /* format SM apdu */ |
462 | 0 | sc_format_asn1_entry(sm_capdu + 3, mac, &mac_len, SC_ASN1_PRESENT); |
463 | 0 | r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &sm_data, &sm_data_len); |
464 | 0 | if (r < 0) |
465 | 0 | goto err; |
466 | 0 | sm_apdu->data = sm_data; |
467 | 0 | sm_apdu->datalen = sm_data_len; |
468 | 0 | sm_apdu->lc = sm_data_len; |
469 | 0 | sm_apdu->le = 0; |
470 | | /* for encrypted APDUs we usually get authenticated status bytes (4B), a |
471 | | * MAC (2B without data) and a cryptogram with padding indicator (2B tag |
472 | | * and indicator, max. 2B/3B ASN.1 length, without data). The cryptogram is |
473 | | * always padded to the block size. */ |
474 | 0 | if (apdu->cse & SC_APDU_EXT) { |
475 | 0 | sm_apdu->cse = SC_APDU_CASE_4_EXT; |
476 | 0 | sm_apdu->resplen = 4 + 2 + mac_len + 2 + 3 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length; |
477 | 0 | if (sm_apdu->resplen > SC_MAX_EXT_APDU_RESP_SIZE) |
478 | 0 | sm_apdu->resplen = SC_MAX_EXT_APDU_RESP_SIZE; |
479 | 0 | } else { |
480 | 0 | sm_apdu->cse = SC_APDU_CASE_4_SHORT; |
481 | 0 | sm_apdu->resplen = 4 + 2 + mac_len + 2 + 2 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length; |
482 | 0 | if (sm_apdu->resplen > SC_MAX_APDU_RESP_SIZE) |
483 | 0 | sm_apdu->resplen = SC_MAX_APDU_RESP_SIZE; |
484 | 0 | } |
485 | 0 | resp_data = calloc(1, sm_apdu->resplen); |
486 | 0 | if (!resp_data) { |
487 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
488 | 0 | goto err; |
489 | 0 | } |
490 | 0 | sm_apdu->resp = resp_data; |
491 | 0 | sc_log_hex(card->ctx, "ASN.1 encoded encrypted APDU data", sm_apdu->data, sm_apdu->datalen); |
492 | |
|
493 | 0 | *psm_apdu = sm_apdu; |
494 | |
|
495 | 0 | err: |
496 | 0 | free(fdata); |
497 | 0 | free(asn1); |
498 | 0 | free(mac_data); |
499 | 0 | free(mac); |
500 | 0 | free(le); |
501 | 0 | if (r < 0) { |
502 | 0 | free(resp_data); |
503 | 0 | free(sm_apdu); |
504 | 0 | free(sm_data); |
505 | 0 | } |
506 | |
|
507 | 0 | return r; |
508 | 0 | } |
509 | | |
510 | | static int sm_decrypt(const struct iso_sm_ctx *ctx, sc_card_t *card, |
511 | | const sc_apdu_t *sm_apdu, sc_apdu_t *apdu) |
512 | 0 | { |
513 | 0 | int r; |
514 | 0 | struct sc_asn1_entry sm_rapdu[5]; |
515 | 0 | struct sc_asn1_entry my_sm_rapdu[5]; |
516 | 0 | u8 sw[2], mac[8], fdata[SC_MAX_EXT_APDU_BUFFER_SIZE]; |
517 | 0 | size_t sw_len = sizeof sw, mac_len = sizeof mac, fdata_len = sizeof fdata, |
518 | 0 | buf_len, asn1_len, fdata_offset = 0; |
519 | 0 | const u8 *buf; |
520 | 0 | u8 *data = NULL, *mac_data = NULL, *asn1 = NULL; |
521 | |
|
522 | 0 | sc_copy_asn1_entry(c_sm_rapdu, sm_rapdu); |
523 | 0 | sc_format_asn1_entry(sm_rapdu + 0, fdata, &fdata_len, 0); |
524 | 0 | sc_format_asn1_entry(sm_rapdu + 1, fdata, &fdata_len, 0); |
525 | 0 | sc_format_asn1_entry(sm_rapdu + 2, sw, &sw_len, 0); |
526 | 0 | sc_format_asn1_entry(sm_rapdu + 3, mac, &mac_len, 0); |
527 | |
|
528 | 0 | r = sc_asn1_decode(card->ctx, sm_rapdu, sm_apdu->resp, sm_apdu->resplen, |
529 | 0 | &buf, &buf_len); |
530 | 0 | if (r < 0) |
531 | 0 | goto err; |
532 | 0 | if (buf_len > 0) { |
533 | 0 | r = SC_ERROR_UNKNOWN_DATA_RECEIVED; |
534 | 0 | goto err; |
535 | 0 | } |
536 | | |
537 | | |
538 | 0 | if (sm_rapdu[3].flags & SC_ASN1_PRESENT) { |
539 | | /* copy from sm_apdu to my_sm_apdu, but leave mac at default */ |
540 | 0 | sc_copy_asn1_entry(sm_rapdu, my_sm_rapdu); |
541 | 0 | sc_copy_asn1_entry(&c_sm_rapdu[3], &my_sm_rapdu[3]); |
542 | |
|
543 | 0 | r = sc_asn1_encode(card->ctx, my_sm_rapdu, &asn1, &asn1_len); |
544 | 0 | if (r < 0) |
545 | 0 | goto err; |
546 | 0 | r = add_padding(ctx, asn1, asn1_len, &mac_data); |
547 | 0 | if (r < 0) { |
548 | 0 | goto err; |
549 | 0 | } |
550 | | |
551 | 0 | r = ctx->verify_authentication(card, ctx, mac, mac_len, |
552 | 0 | mac_data, r); |
553 | 0 | if (r < 0) |
554 | 0 | goto err; |
555 | 0 | } else { |
556 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Cryptographic Checksum missing"); |
557 | 0 | r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; |
558 | 0 | goto err; |
559 | 0 | } |
560 | | |
561 | | |
562 | 0 | if (sm_rapdu[1].flags & SC_ASN1_PRESENT) { |
563 | 0 | if (ctx->padding_indicator != fdata[0]) { |
564 | 0 | r = SC_ERROR_UNKNOWN_DATA_RECEIVED; |
565 | 0 | goto err; |
566 | 0 | } |
567 | 0 | fdata_offset = 1; |
568 | 0 | } |
569 | 0 | if (sm_rapdu[0].flags & SC_ASN1_PRESENT |
570 | 0 | || sm_rapdu[1].flags & SC_ASN1_PRESENT) { |
571 | 0 | r = ctx->decrypt(card, ctx, fdata + fdata_offset, |
572 | 0 | fdata_len - fdata_offset, &data); |
573 | 0 | if (r < 0) |
574 | 0 | goto err; |
575 | 0 | buf_len = r; |
576 | |
|
577 | 0 | r = rm_padding(ctx->padding_indicator, data, buf_len); |
578 | 0 | if (r < 0) { |
579 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not remove padding"); |
580 | 0 | goto err; |
581 | 0 | } |
582 | | |
583 | 0 | if (apdu->resplen < (size_t) r || (r && !apdu->resp)) { |
584 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, |
585 | 0 | "Response of SM APDU %"SC_FORMAT_LEN_SIZE_T"u byte%s too long", |
586 | 0 | r-apdu->resplen, |
587 | 0 | r-apdu->resplen < 2 ? "" : "s"); |
588 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
589 | 0 | goto err; |
590 | 0 | } |
591 | 0 | memcpy(apdu->resp, data, r); |
592 | 0 | apdu->resplen = r; |
593 | 0 | } else { |
594 | 0 | apdu->resplen = 0; |
595 | 0 | } |
596 | | |
597 | 0 | if (sm_rapdu[2].flags & SC_ASN1_PRESENT) { |
598 | 0 | if (sw_len != 2) { |
599 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Length of processing status bytes must be 2"); |
600 | 0 | r = SC_ERROR_ASN1_END_OF_CONTENTS; |
601 | 0 | goto err; |
602 | 0 | } |
603 | 0 | apdu->sw1 = sw[0]; |
604 | 0 | apdu->sw2 = sw[1]; |
605 | 0 | } else { |
606 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Authenticated status bytes are missing"); |
607 | 0 | r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; |
608 | 0 | goto err; |
609 | 0 | } |
610 | | |
611 | 0 | sc_log(card->ctx, "Decrypted APDU sw1=%02x sw2=%02x", |
612 | 0 | apdu->sw1, apdu->sw2); |
613 | 0 | sc_log_hex(card->ctx, "Decrypted APDU response data", |
614 | 0 | apdu->resp, apdu->resplen); |
615 | |
|
616 | 0 | r = SC_SUCCESS; |
617 | |
|
618 | 0 | err: |
619 | 0 | free(asn1); |
620 | 0 | free(mac_data); |
621 | 0 | if (data) { |
622 | 0 | sc_mem_clear(data, buf_len); |
623 | 0 | free(data); |
624 | 0 | } |
625 | |
|
626 | 0 | return r; |
627 | 0 | } |
628 | | |
629 | | static int iso_add_sm(struct iso_sm_ctx *sctx, sc_card_t *card, |
630 | | sc_apdu_t *apdu, sc_apdu_t **sm_apdu) |
631 | 0 | { |
632 | 0 | if (!card || !sctx) |
633 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
634 | | |
635 | 0 | if ((apdu->cla & 0x0C) == 0x0C) { |
636 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Given APDU is already protected with some secure messaging. Closing own SM context."); |
637 | 0 | LOG_TEST_RET(card->ctx, sc_sm_stop(card), |
638 | 0 | "Could not close ISO SM session"); |
639 | 0 | return SC_ERROR_SM_NOT_APPLIED; |
640 | 0 | } |
641 | | |
642 | 0 | if (sctx->pre_transmit) |
643 | 0 | LOG_TEST_RET(card->ctx, sctx->pre_transmit(card, sctx, apdu), |
644 | 0 | "Could not complete SM specific pre transmit routine"); |
645 | 0 | LOG_TEST_RET(card->ctx, sm_encrypt(sctx, card, apdu, sm_apdu), |
646 | 0 | "Could not encrypt APDU"); |
647 | | |
648 | 0 | return SC_SUCCESS; |
649 | 0 | } |
650 | | |
651 | | static int iso_rm_sm(struct iso_sm_ctx *sctx, sc_card_t *card, |
652 | | sc_apdu_t *sm_apdu, sc_apdu_t *apdu) |
653 | 0 | { |
654 | 0 | if (!sctx) |
655 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, |
656 | 0 | "Invalid SM context. No SM processing performed."); |
657 | | |
658 | 0 | if (sctx->post_transmit) |
659 | 0 | LOG_TEST_RET(card->ctx, sctx->post_transmit(card, sctx, sm_apdu), |
660 | 0 | "Could not complete SM specific post transmit routine"); |
661 | 0 | LOG_TEST_RET(card->ctx, sm_decrypt(sctx, card, sm_apdu, apdu), |
662 | 0 | "Could not decrypt APDU"); |
663 | 0 | if (sctx->finish) |
664 | 0 | LOG_TEST_RET(card->ctx, sctx->finish(card, sctx, apdu), |
665 | 0 | "Could not complete SM specific post transmit routine"); |
666 | | |
667 | 0 | return SC_SUCCESS; |
668 | 0 | } |
669 | | |
670 | | int iso_sm_close(struct sc_card *card) |
671 | 0 | { |
672 | 0 | if (card) { |
673 | 0 | iso_sm_ctx_clear_free(card->sm_ctx.info.cmd_data); |
674 | 0 | card->sm_ctx.info.cmd_data = NULL; |
675 | 0 | } |
676 | |
|
677 | 0 | return SC_SUCCESS; |
678 | 0 | } |
679 | | |
680 | | int iso_get_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu) |
681 | 0 | { |
682 | 0 | return iso_add_sm(card->sm_ctx.info.cmd_data, card, apdu, sm_apdu); |
683 | 0 | } |
684 | | |
685 | | int iso_free_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu) |
686 | 0 | { |
687 | 0 | struct sc_apdu *p; |
688 | 0 | int r; |
689 | |
|
690 | 0 | if (!sm_apdu) |
691 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
692 | | |
693 | 0 | p = *sm_apdu; |
694 | |
|
695 | 0 | r = iso_rm_sm(card->sm_ctx.info.cmd_data, card, p, apdu); |
696 | |
|
697 | 0 | if (p) { |
698 | 0 | free((unsigned char *) p->data); |
699 | 0 | free((unsigned char *) p->resp); |
700 | 0 | } |
701 | 0 | free(*sm_apdu); |
702 | 0 | *sm_apdu = NULL; |
703 | |
|
704 | 0 | return r; |
705 | 0 | } |
706 | | |
707 | | struct iso_sm_ctx *iso_sm_ctx_create(void) |
708 | 0 | { |
709 | 0 | struct iso_sm_ctx *sctx = malloc(sizeof *sctx); |
710 | 0 | if (!sctx) |
711 | 0 | return NULL; |
712 | | |
713 | 0 | sctx->priv_data = NULL; |
714 | 0 | sctx->padding_indicator = SM_ISO_PADDING; |
715 | 0 | sctx->block_length = 0; |
716 | 0 | sctx->authenticate = NULL; |
717 | 0 | sctx->verify_authentication = NULL; |
718 | 0 | sctx->encrypt = NULL; |
719 | 0 | sctx->decrypt = NULL; |
720 | 0 | sctx->pre_transmit = NULL; |
721 | 0 | sctx->post_transmit = NULL; |
722 | 0 | sctx->finish = NULL; |
723 | 0 | sctx->clear_free = NULL; |
724 | |
|
725 | 0 | return sctx; |
726 | 0 | } |
727 | | |
728 | | void iso_sm_ctx_clear_free(struct iso_sm_ctx *sctx) |
729 | 0 | { |
730 | 0 | if (sctx && sctx->clear_free) |
731 | 0 | sctx->clear_free(sctx); |
732 | 0 | free(sctx); |
733 | 0 | } |
734 | | |
735 | | int iso_sm_start(struct sc_card *card, struct iso_sm_ctx *sctx) |
736 | 0 | { |
737 | 0 | if (!card) |
738 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
739 | | |
740 | 0 | if (card->sm_ctx.ops.close) |
741 | 0 | card->sm_ctx.ops.close(card); |
742 | |
|
743 | 0 | card->sm_ctx.info.cmd_data = sctx; |
744 | 0 | card->sm_ctx.ops.close = iso_sm_close; |
745 | 0 | card->sm_ctx.ops.free_sm_apdu = iso_free_sm_apdu; |
746 | 0 | card->sm_ctx.ops.get_sm_apdu = iso_get_sm_apdu; |
747 | 0 | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
748 | |
|
749 | 0 | return SC_SUCCESS; |
750 | 0 | } |
751 | | |
752 | | #else |
753 | | |
754 | | int iso_sm_close(struct sc_card *card) |
755 | | { |
756 | | return SC_ERROR_NOT_SUPPORTED; |
757 | | } |
758 | | |
759 | | int iso_get_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu) |
760 | | { |
761 | | return SC_ERROR_NOT_SUPPORTED; |
762 | | } |
763 | | |
764 | | struct iso_sm_ctx *iso_sm_ctx_create(void) |
765 | | { |
766 | | return NULL; |
767 | | } |
768 | | |
769 | | void iso_sm_ctx_clear_free(struct iso_sm_ctx *sctx) |
770 | | { |
771 | | } |
772 | | |
773 | | int iso_sm_start(struct sc_card *card, struct iso_sm_ctx *sctx) |
774 | | { |
775 | | return SC_ERROR_NOT_SUPPORTED; |
776 | | } |
777 | | |
778 | | #endif |