/src/opensc/src/libopensc/cwa14890.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * cwa14890.c: Implementation of Secure Messaging according CWA-14890-1 and CWA-14890-2 standards. |
3 | | * |
4 | | * Copyright (C) 2010 Juan Antonio Martinez <jonsito@terra.es> |
5 | | * |
6 | | * This work is derived from many sources at OpenSC Project site, |
7 | | * (see references) and the information made public by Spanish |
8 | | * Direccion General de la Policia y de la Guardia Civil |
9 | | * |
10 | | * This library is free software; you can redistribute it and/or |
11 | | * modify it under the terms of the GNU Lesser General Public |
12 | | * License as published by the Free Software Foundation; either |
13 | | * version 2.1 of the License, or (at your option) any later version. |
14 | | * |
15 | | * This library is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | | * Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; if not, write to the Free Software |
22 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 | | */ |
24 | | |
25 | | #define __CWA14890_C__ |
26 | | #ifdef HAVE_CONFIG_H |
27 | | #include "config.h" |
28 | | #endif |
29 | | |
30 | | #if defined(ENABLE_OPENSSL) && defined(ENABLE_SM) /* empty file without openssl or sm */ |
31 | | |
32 | | #include <stdlib.h> |
33 | | #include <string.h> |
34 | | #include <ctype.h> |
35 | | |
36 | | #include "opensc.h" |
37 | | #include "cardctl.h" |
38 | | #include "internal.h" |
39 | | #include <openssl/rsa.h> |
40 | | #include <openssl/bn.h> |
41 | | #include <openssl/x509.h> |
42 | | #include <openssl/des.h> |
43 | | #include <openssl/rand.h> |
44 | | #include "cwa14890.h" |
45 | | #include "cwa-dnie.h" |
46 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
47 | | # include <openssl/core_names.h> |
48 | | # include <openssl/param_build.h> |
49 | | # include <openssl/provider.h> |
50 | | #endif |
51 | | |
52 | 0 | #define MAX_RESP_BUFFER_SIZE 2048 |
53 | | |
54 | | /** |
55 | | * Structure used to compose BER-TLV encoded data |
56 | | * according to iso7816-4 sect 5.2.2. |
57 | | * |
58 | | * Notice that current implementation does not handle properly |
59 | | * multibyte tag id. Just assume that tag is 1-byte length |
60 | | * Also, encodings for data length longer than 0x01000000 bytes |
61 | | * are not supported (tag 0x84) |
62 | | */ |
63 | | typedef struct cwa_tlv_st { |
64 | | u8 *buf; /** local copy of TLV byte array */ |
65 | | size_t buflen; /** length of buffer */ |
66 | | unsigned int tag; /** tag ID */ |
67 | | size_t len; /** length of data field */ |
68 | | u8 *data; /** pointer to start of data in buf buffer */ |
69 | | } cwa_tlv_t; |
70 | | |
71 | | /*********************** utility functions ************************/ |
72 | | |
73 | | /** |
74 | | * Dump an APDU before SM translation. |
75 | | * |
76 | | * This is mainly for debugging purposes. programmer should disable |
77 | | * this function in a production environment, as APDU will be shown |
78 | | * in text-plain on debug traces |
79 | | * |
80 | | * @param card Pointer to card driver data structure |
81 | | * @param apdu APDU to be encoded, or APDU response after decoded |
82 | | * @param flag 0: APDU is to be encoded: 1; APDU decoded response |
83 | | */ |
84 | | static void cwa_trace_apdu(sc_card_t * card, sc_apdu_t * apdu, int flag) |
85 | 0 | { |
86 | 0 | char buf[2048]; |
87 | 0 | if (!card || !card->ctx || !apdu || card->ctx->debug < SC_LOG_DEBUG_NORMAL) |
88 | 0 | return; |
89 | 0 | if (flag == 0) { /* apdu command */ |
90 | 0 | if (apdu->datalen > 0) { /* apdu data to show */ |
91 | 0 | sc_hex_dump(apdu->data, apdu->datalen, buf, sizeof(buf)); |
92 | 0 | sc_log(card->ctx, |
93 | 0 | "\nAPDU before encode: ==================================================\nCLA: %02X INS: %02X P1: %02X P2: %02X Lc: %02"SC_FORMAT_LEN_SIZE_T"X Le: %02"SC_FORMAT_LEN_SIZE_T"X DATA: [%5"SC_FORMAT_LEN_SIZE_T"u bytes]\n%s======================================================================\n", |
94 | 0 | apdu->cla, apdu->ins, apdu->p1, apdu->p2, |
95 | 0 | apdu->lc, apdu->le, apdu->datalen, buf); |
96 | 0 | } else { /* apdu data field is empty */ |
97 | 0 | sc_log(card->ctx, |
98 | 0 | "\nAPDU before encode: ==================================================\nCLA: %02X INS: %02X P1: %02X P2: %02X Lc: %02"SC_FORMAT_LEN_SIZE_T"X Le: %02"SC_FORMAT_LEN_SIZE_T"X (NO DATA)\n======================================================================\n", |
99 | 0 | apdu->cla, apdu->ins, apdu->p1, apdu->p2, |
100 | 0 | apdu->lc, apdu->le); |
101 | 0 | } |
102 | 0 | } else { /* apdu response */ |
103 | 0 | sc_hex_dump(apdu->resp, apdu->resplen, buf, sizeof(buf)); |
104 | 0 | sc_log(card->ctx, |
105 | 0 | "\nAPDU response after decode: ==========================================\nSW1: %02X SW2: %02X RESP: [%5"SC_FORMAT_LEN_SIZE_T"u bytes]\n%s======================================================================\n", |
106 | 0 | apdu->sw1, apdu->sw2, apdu->resplen, buf); |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | | /** |
111 | | * Increase send sequence counter SSC. |
112 | | * |
113 | | * @param card smart card info structure |
114 | | * @return SC_SUCCESS if ok; else error code |
115 | | * |
116 | | * TODO: to further study: what about using bignum arithmetic? |
117 | | */ |
118 | | static int cwa_increase_ssc(sc_card_t * card) |
119 | 0 | { |
120 | 0 | int n; |
121 | 0 | struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa; |
122 | | |
123 | | /* preliminary checks */ |
124 | 0 | if (!card || !card->ctx ) |
125 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
126 | 0 | LOG_FUNC_CALLED(card->ctx); |
127 | | /* u8 arithmetic; exit loop if no carry */ |
128 | 0 | sc_log(card->ctx, "Curr SSC: '%s'", sc_dump_hex(sm->ssc, 8)); |
129 | 0 | for (n = 7; n >= 0; n--) { |
130 | 0 | sm->ssc[n]++; |
131 | 0 | if ((sm->ssc[n]) != 0x00) |
132 | 0 | break; |
133 | 0 | } |
134 | 0 | sc_log(card->ctx, "Next SSC: '%s'", sc_dump_hex(sm->ssc, 8)); |
135 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
136 | 0 | } |
137 | | |
138 | | /** |
139 | | * ISO 7816 padding. |
140 | | * |
141 | | * Adds an 0x80 at the end of buffer and as many zeroes to get len |
142 | | * multiple of 8 |
143 | | * Buffer must be long enough to store additional bytes |
144 | | * |
145 | | * @param buffer where to compose data |
146 | | * @param len pointer to buffer length |
147 | | */ |
148 | | static void cwa_iso7816_padding(u8 * buf, size_t * buflen) |
149 | 0 | { |
150 | 0 | buf[*buflen] = 0x80; |
151 | 0 | (*buflen)++; |
152 | 0 | for (; *buflen & 0x07; (*buflen)++) |
153 | 0 | buf[*buflen] = 0x00; |
154 | 0 | } |
155 | | |
156 | | /** |
157 | | * compose a BER-TLV data in provided buffer. |
158 | | * |
159 | | * Multibyte tag id are not supported |
160 | | * Also multibyte id 0x84 is unhandled |
161 | | * |
162 | | * Notice that TLV is composed starting at offset length from |
163 | | * the buffer. Consecutive calls to cwa_add_tlv, appends a new |
164 | | * TLV at the end of the buffer |
165 | | * |
166 | | * @param card card info structure |
167 | | * @param tag tag id |
168 | | * @param len data length |
169 | | * @param value data buffer |
170 | | * @param out pointer to dest data |
171 | | * @param outlen length of composed tlv data |
172 | | * @return SC_SUCCESS if ok; else error |
173 | | */ |
174 | | static int cwa_compose_tlv(sc_card_t * card, |
175 | | u8 tag, |
176 | | size_t len, u8 * data, u8 ** out, size_t * outlen) |
177 | 0 | { |
178 | 0 | u8 *pt; |
179 | 0 | size_t size; |
180 | 0 | sc_context_t *ctx; |
181 | | /* preliminary checks */ |
182 | 0 | if (!card || !card->ctx || !out || !outlen) |
183 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
184 | | /* commodity vars */ |
185 | 0 | ctx = card->ctx; |
186 | |
|
187 | 0 | LOG_FUNC_CALLED(ctx); |
188 | 0 | pt = *out; |
189 | 0 | size = *outlen; |
190 | | |
191 | | /* assume tag id is not multibyte */ |
192 | 0 | *(pt + size++) = tag; |
193 | | /* evaluate tag length value according iso7816-4 sect 5.2.2 */ |
194 | 0 | if (len < 0x80) { |
195 | 0 | *(pt + size++) = len; |
196 | 0 | } else if (len < 0x00000100) { |
197 | 0 | *(pt + size++) = 0x81; |
198 | 0 | *(pt + size++) = 0xff & len; |
199 | 0 | } else if (len < 0x00010000) { |
200 | 0 | *(pt + size++) = 0x82; |
201 | 0 | *(pt + size++) = 0xff & (len >> 8); |
202 | 0 | *(pt + size++) = 0xff & len; |
203 | 0 | } else if (len < 0x01000000) { |
204 | 0 | *(pt + size++) = 0x83; |
205 | 0 | *(pt + size++) = 0xff & (len >> 16); |
206 | 0 | *(pt + size++) = 0xff & (len >> 8); |
207 | 0 | *(pt + size++) = 0xff & len; |
208 | 0 | } else { /* do not handle tag length 0x84 */ |
209 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
210 | 0 | } |
211 | | /* copy remaining data to buffer */ |
212 | 0 | if (len != 0) |
213 | 0 | memcpy(pt + size, data, len); |
214 | 0 | size += len; |
215 | 0 | *outlen = size; |
216 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
217 | 0 | } |
218 | | |
219 | | /** |
220 | | * Parse and APDU Response and extract specific BER-TLV data. |
221 | | * |
222 | | * NOTICE that iso7816 sect 5.2.2 states that Tag length may be 1 to n bytes |
223 | | * length. In this code we'll assume always tag length = 1 byte |
224 | | * |
225 | | * FIXME use `sc_asn1_read_tag` or similar instead |
226 | | * |
227 | | * @param card card info structure |
228 | | * @param data Buffer to look for tlv into |
229 | | * @param datalen Buffer len |
230 | | * @param tlv array of TLV structure to store results into |
231 | | * @return SC_SUCCESS if OK; else error code |
232 | | */ |
233 | | static int cwa_parse_tlv(sc_card_t * card, |
234 | | u8 * buffer, size_t datalen, |
235 | | cwa_tlv_t tlv_array[] |
236 | | ) |
237 | 0 | { |
238 | 0 | size_t n = 0; |
239 | 0 | size_t next = 0; |
240 | 0 | sc_context_t *ctx = NULL; |
241 | | |
242 | | /* preliminary checks */ |
243 | 0 | if (!card || !card->ctx) |
244 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
245 | | /* commodity vars */ |
246 | 0 | ctx = card->ctx; |
247 | |
|
248 | 0 | LOG_FUNC_CALLED(ctx); |
249 | 0 | if (!tlv_array) |
250 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
251 | | |
252 | 0 | for (n = 0; n < datalen; n += next) { |
253 | 0 | cwa_tlv_t *tlv = NULL; /* pointer to TLV structure to store info */ |
254 | 0 | size_t j = 2; /* TLV has at least two bytes */ |
255 | 0 | switch (*(buffer + n)) { |
256 | 0 | case CWA_SM_PLAIN_TAG: |
257 | 0 | tlv = &tlv_array[0]; |
258 | 0 | break; /* 0x81 Plain */ |
259 | 0 | case CWA_SM_CRYPTO_TAG: |
260 | 0 | tlv = &tlv_array[1]; |
261 | 0 | break; /* 0x87 Crypto */ |
262 | 0 | case CWA_SM_MAC_TAG: |
263 | 0 | tlv = &tlv_array[2]; |
264 | 0 | break; /* 0x8E MAC CC */ |
265 | 0 | case CWA_SM_STATUS_TAG: |
266 | 0 | tlv = &tlv_array[3]; |
267 | 0 | break; /* 0x99 Status */ |
268 | 0 | default: /* CWA_SM_LE_TAG (0x97) is not valid here */ |
269 | 0 | sc_log(ctx, "Invalid TLV Tag type: '0x%02X'", |
270 | 0 | *(buffer + n)); |
271 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
272 | 0 | } |
273 | 0 | tlv->buf = buffer + n; |
274 | 0 | tlv->tag = 0xff & *(buffer + n); |
275 | 0 | tlv->len = 0; /* temporary */ |
276 | | /* evaluate len and start of data */ |
277 | 0 | switch (0xff & *(buffer + n + 1)) { |
278 | 0 | case 0x84: |
279 | 0 | tlv->len = (0xff & *(buffer + n + j++)); |
280 | | /* fall through */ |
281 | 0 | case 0x83: |
282 | 0 | tlv->len = |
283 | 0 | (tlv->len << 8) + (0xff & *(buffer + n + j++)); |
284 | | /* fall through */ |
285 | 0 | case 0x82: |
286 | 0 | tlv->len = |
287 | 0 | (tlv->len << 8) + (0xff & *(buffer + n + j++)); |
288 | | /* fall through */ |
289 | 0 | case 0x81: |
290 | 0 | tlv->len = |
291 | 0 | (tlv->len << 8) + (0xff & *(buffer + n + j++)); |
292 | 0 | break; |
293 | | /* case 0x80 is not standard, but official code uses it */ |
294 | 0 | case 0x80: |
295 | 0 | tlv->len = |
296 | 0 | (tlv->len << 8) + (0xff & *(buffer + n + j++)); |
297 | 0 | break; |
298 | 0 | default: |
299 | 0 | if ((*(buffer + n + 1) & 0xff) < 0x80) { |
300 | 0 | tlv->len = 0xff & *(buffer + n + 1); |
301 | 0 | } else { |
302 | 0 | sc_log(ctx, "Invalid tag length indicator: %d", |
303 | 0 | *(buffer + n + 1)); |
304 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH); |
305 | 0 | } |
306 | 0 | } |
307 | 0 | tlv->data = buffer + n + j; |
308 | 0 | tlv->buflen = j + tlv->len; |
309 | 0 | sc_log(ctx, "Found Tag: '0x%02X': Length: '%"SC_FORMAT_LEN_SIZE_T"u' Value:\n%s", |
310 | 0 | tlv->tag, tlv->len, sc_dump_hex(tlv->data, tlv->len)); |
311 | | /* set index to next Tag to jump to */ |
312 | 0 | next = tlv->buflen; |
313 | 0 | } |
314 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); /* mark no error */ |
315 | 0 | } |
316 | | |
317 | | /*********************** authentication routines *******************/ |
318 | | |
319 | | /** |
320 | | * Verify certificates provided by card. |
321 | | * |
322 | | * This routine uses Root CA public key data From Annex III of manual |
323 | | * to verify intermediate CA icc certificate provided by card |
324 | | * if verify success, then extract public keys from intermediate CA |
325 | | * and verify icc certificate |
326 | | * |
327 | | * @param card pointer to sc_card_contex |
328 | | * @param sub_ca_cert icc intermediate CA certificate read from card |
329 | | * @param icc_ca icc certificate from card |
330 | | * @return SC_SUCCESS if verification is ok; else error code |
331 | | */ |
332 | | static int cwa_verify_icc_certificates(sc_card_t * card, |
333 | | cwa_provider_t * provider, |
334 | | X509 * sub_ca_cert, X509 * icc_cert) |
335 | 0 | { |
336 | 0 | char *msg = NULL; |
337 | 0 | int res = SC_SUCCESS; |
338 | 0 | EVP_PKEY *root_ca_key = NULL; |
339 | 0 | EVP_PKEY *sub_ca_key = NULL; |
340 | 0 | sc_context_t *ctx = NULL; |
341 | | |
342 | | /* safety check */ |
343 | 0 | if (!card || !card->ctx || !provider) |
344 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
345 | 0 | ctx = card->ctx; |
346 | 0 | LOG_FUNC_CALLED(ctx); |
347 | 0 | if (!sub_ca_cert || !icc_cert) /* check received arguments */ |
348 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
349 | | |
350 | | /* retrieve root ca pkey from provider */ |
351 | 0 | res = provider->cwa_get_root_ca_pubkey(card, &root_ca_key); |
352 | 0 | if (res != SC_SUCCESS) { |
353 | 0 | msg = "Cannot get root CA public key"; |
354 | 0 | res = SC_ERROR_INTERNAL; |
355 | 0 | goto verify_icc_certificates_end; |
356 | 0 | } |
357 | | |
358 | | /* verify sub_ca_cert against root_ca_key */ |
359 | 0 | res = X509_verify(sub_ca_cert, root_ca_key); |
360 | 0 | if (!res) { |
361 | 0 | sc_log_openssl(ctx); |
362 | 0 | msg = "Cannot verify icc Sub-CA certificate"; |
363 | 0 | res = SC_ERROR_SM_AUTHENTICATION_FAILED; |
364 | 0 | goto verify_icc_certificates_end; |
365 | 0 | } |
366 | | |
367 | | /* extract sub_ca_key from sub_ca_cert */ |
368 | 0 | if (!(sub_ca_key = X509_get_pubkey(sub_ca_cert))) { |
369 | 0 | sc_log_openssl(ctx); |
370 | 0 | msg = "Cannot extract public key icc Sub-CA certificate"; |
371 | 0 | res = SC_ERROR_INTERNAL; |
372 | 0 | goto verify_icc_certificates_end; |
373 | 0 | } |
374 | | |
375 | | /* verify icc_cert against sub_ca_key */ |
376 | 0 | res = X509_verify(icc_cert, sub_ca_key); |
377 | 0 | if (!res) { |
378 | 0 | sc_log_openssl(ctx); |
379 | 0 | msg = "Cannot verify icc certificate"; |
380 | 0 | res = SC_ERROR_SM_AUTHENTICATION_FAILED; |
381 | 0 | goto verify_icc_certificates_end; |
382 | 0 | } |
383 | | |
384 | | /* arriving here means certificate verification success */ |
385 | 0 | res = SC_SUCCESS; |
386 | 0 | verify_icc_certificates_end: |
387 | 0 | if (root_ca_key) |
388 | 0 | EVP_PKEY_free(root_ca_key); |
389 | 0 | if (sub_ca_key) |
390 | 0 | EVP_PKEY_free(sub_ca_key); |
391 | 0 | if (res != SC_SUCCESS) { |
392 | 0 | sc_log(ctx, "%s", msg); |
393 | 0 | } |
394 | 0 | LOG_FUNC_RETURN(ctx, res); |
395 | 0 | } |
396 | | |
397 | | /** |
398 | | * Verify CVC certificates in SM establishment process. |
399 | | * |
400 | | * This is done by mean of 00 2A 00 AE |
401 | | * (Perform Security Operation: Verify Certificate ) |
402 | | * |
403 | | * @param card pointer to card data |
404 | | * @param cert Certificate in CVC format |
405 | | * @param len length of CVC certificate |
406 | | * @return SC_SUCCESS if ok; else error code |
407 | | */ |
408 | | static int cwa_verify_cvc_certificate(sc_card_t * card, |
409 | | const u8 * cert, size_t len) |
410 | 0 | { |
411 | 0 | sc_apdu_t apdu; |
412 | 0 | int result = SC_SUCCESS; |
413 | 0 | sc_context_t *ctx = NULL; |
414 | | |
415 | | /* safety check */ |
416 | 0 | if (!card || !card->ctx) |
417 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
418 | 0 | ctx = card->ctx; |
419 | 0 | LOG_FUNC_CALLED(ctx); |
420 | 0 | if (!cert || (len <= 0)) /* check received arguments */ |
421 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
422 | | |
423 | | /* compose apdu for Perform Security Operation (Verify cert) cmd */ |
424 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x00, 0xAE, 0, len, |
425 | 0 | NULL, 0, cert, len); |
426 | | |
427 | | /* send composed apdu and parse result */ |
428 | 0 | result = sc_transmit_apdu(card, &apdu); |
429 | 0 | LOG_TEST_RET(ctx, result, "Verify CVC certificate failed"); |
430 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
431 | 0 | LOG_FUNC_RETURN(ctx, result); |
432 | 0 | } |
433 | | |
434 | | /** |
435 | | * Alternate implementation for set_security environment. |
436 | | * |
437 | | * Used to handle raw apdu data in set_security_env() on SM establishment |
438 | | * Standard set_security_env() method has sc_security_env->buffer limited |
439 | | * to 8 bytes; so cannot send some of required SM commands. |
440 | | * |
441 | | * @param card pointer to card data |
442 | | * @param p1 apdu P1 parameter |
443 | | * @param p2 apdu P2 parameter |
444 | | * @param buffer raw data to be inserted in apdu |
445 | | * @param length size of buffer |
446 | | * @return SC_SUCCESS if ok; else error code |
447 | | */ |
448 | | static int cwa_set_security_env(sc_card_t * card, |
449 | | u8 p1, u8 p2, u8 * buffer, size_t length) |
450 | 0 | { |
451 | 0 | sc_apdu_t apdu; |
452 | 0 | int result = SC_SUCCESS; |
453 | 0 | sc_context_t *ctx = NULL; |
454 | | |
455 | | /* safety check */ |
456 | 0 | if (!card || !card->ctx) |
457 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
458 | 0 | ctx = card->ctx; |
459 | 0 | LOG_FUNC_CALLED(ctx); |
460 | 0 | if (!buffer || (length <= 0)) /* check received arguments */ |
461 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
462 | | |
463 | | /* compose apdu for Manage Security Environment cmd */ |
464 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, p1, p2, 0, length, |
465 | 0 | NULL, 0, buffer, length); |
466 | | |
467 | | /* send composed apdu and parse result */ |
468 | 0 | result = sc_transmit_apdu(card, &apdu); |
469 | 0 | LOG_TEST_RET(ctx, result, "SM Set Security Environment failed"); |
470 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
471 | 0 | LOG_FUNC_RETURN(ctx, result); |
472 | 0 | } |
473 | | |
474 | | /** |
475 | | * SM internal authenticate. |
476 | | * |
477 | | * Internal (Card) authentication (let the card verify sent ifd certs) |
478 | | * |
479 | | * @param card pointer to card data |
480 | | * @param sig signature buffer |
481 | | * @param dig_len signature buffer length |
482 | | * @param data data to be sent in apdu |
483 | | * @param datalen length of data to send |
484 | | * @return SC_SUCCESS if OK: else error code |
485 | | */ |
486 | | static int cwa_internal_auth(sc_card_t * card, u8 * sig, size_t sig_len, u8 * data, size_t datalen) |
487 | 0 | { |
488 | 0 | sc_apdu_t apdu; |
489 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; |
490 | 0 | int result = SC_SUCCESS; |
491 | 0 | sc_context_t *ctx = NULL; |
492 | | |
493 | | /* safety check */ |
494 | 0 | if (!card || !card->ctx) |
495 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
496 | 0 | ctx = card->ctx; |
497 | 0 | LOG_FUNC_CALLED(ctx); |
498 | 0 | if (!data || (datalen <= 0)) /* check received arguments */ |
499 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
500 | | |
501 | | /* compose apdu for Internal Authenticate cmd */ |
502 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x00, 0x00, 0x80, datalen, |
503 | 0 | rbuf, sizeof(rbuf), data, datalen); |
504 | | |
505 | | /* send composed apdu and parse result */ |
506 | 0 | result = sc_transmit_apdu(card, &apdu); |
507 | 0 | LOG_TEST_RET(ctx, result, "SM internal auth failed"); |
508 | | |
509 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
510 | 0 | LOG_TEST_RET(ctx, result, "SM internal auth invalid response"); |
511 | | |
512 | 0 | if (apdu.resplen != sig_len) /* invalid number of bytes received */ |
513 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
514 | 0 | memcpy(sig, apdu.resp, apdu.resplen); /* copy result to buffer */ |
515 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
516 | 0 | } |
517 | | |
518 | | /** |
519 | | * Compose signature data for external auth according CWA-14890. |
520 | | * |
521 | | * This code prepares data to be sent to ICC for external |
522 | | * authentication procedure |
523 | | * |
524 | | * Store resulting data into sm->sig |
525 | | * |
526 | | * @param card pointer to st_card_t card data information |
527 | | * @param icc_pubkey public key of card |
528 | | * @param ifd_privkey private key of ifd |
529 | | * @param sn_icc card serial number |
530 | | * @param sig signature buffer |
531 | | * @param sig_len signature buffer length |
532 | | * @return SC_SUCCESS if ok; else errorcode |
533 | | */ |
534 | | static int cwa_prepare_external_auth(sc_card_t * card, |
535 | | EVP_PKEY *icc_pubkey, |
536 | | EVP_PKEY *ifd_privkey, |
537 | | u8 * sig, |
538 | | size_t sig_len) |
539 | 0 | { |
540 | | /* we have to compose following message: |
541 | | data = E[PK.ICC.AUT](SIGMIN) |
542 | | SIGMIN = min ( SIG, N.IFD-SIG ) |
543 | | SIG= DS[SK.IFD.AUT] ( |
544 | | 0x6A || - padding according iso 9796-2 |
545 | | PRND2 || - (74 bytes) random data to make buffer 128 bytes length |
546 | | Kifd || - (32 bytes)- ifd random generated key |
547 | | sha1_hash( |
548 | | PRND2 || |
549 | | Kifd || |
550 | | RND.ICC || - (8 bytes) response to get_challenge() cmd |
551 | | SN.ICC - (8 bytes) serial number from get_serialnr() cmd |
552 | | ) || |
553 | | 0xBC - iso 9796-2 padding |
554 | | ) - total: 128 bytes |
555 | | |
556 | | then, we should encrypt with our private key and then with icc pub key |
557 | | returning resulting data |
558 | | */ |
559 | 0 | char *msg = NULL; /* to store error messages */ |
560 | 0 | int res = SC_SUCCESS; |
561 | 0 | u8 *buf1 = NULL; /* where to encrypt with icc pub key */ |
562 | 0 | u8 *buf2 = NULL; /* where to encrypt with ifd pub key */ |
563 | 0 | u8 *buf3 = NULL; /* where to compose message to be encrypted */ |
564 | 0 | size_t len1 = 128, len2 = 128, len3 = 128; |
565 | 0 | u8 *sha_buf = NULL; /* to compose message to be sha'd */ |
566 | 0 | u8 *sha_data = NULL; /* sha signature data */ |
567 | 0 | BIGNUM *bn = NULL; |
568 | 0 | BIGNUM *bnsub = NULL; |
569 | 0 | BIGNUM *bnres = NULL; |
570 | 0 | sc_context_t *ctx = NULL; |
571 | 0 | struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa; |
572 | 0 | EVP_PKEY_CTX *pctx = NULL; |
573 | |
|
574 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
575 | 0 | const BIGNUM *ifd_privkey_n = NULL; |
576 | 0 | const RSA *rsa_ifd_privkey = EVP_PKEY_get0_RSA(ifd_privkey); |
577 | 0 | if (!rsa_ifd_privkey) { |
578 | 0 | res = SC_ERROR_INTERNAL; |
579 | 0 | msg = "Can not extract RSA object ifd priv"; |
580 | 0 | goto prepare_external_auth_end; |
581 | 0 | } |
582 | | #else |
583 | | BIGNUM *ifd_privkey_n = NULL; |
584 | | #endif |
585 | | |
586 | | /* safety check */ |
587 | 0 | if (!card || !card->ctx) |
588 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
589 | 0 | ctx = card->ctx; |
590 | 0 | LOG_FUNC_CALLED(ctx); |
591 | | /* check received arguments */ |
592 | 0 | if (!icc_pubkey || !ifd_privkey || !sm) |
593 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
594 | 0 | buf1 = calloc(128, sizeof(u8)); |
595 | 0 | buf2 = calloc(128, sizeof(u8)); |
596 | 0 | buf3 = calloc(128, sizeof(u8)); |
597 | 0 | sha_buf = calloc(74 + 32 + 8 + 8, sizeof(u8)); |
598 | 0 | sha_data = calloc(SHA_DIGEST_LENGTH, sizeof(u8)); |
599 | | /* alloc() resources */ |
600 | 0 | if (!buf1 || !buf2 || !buf3 || !sha_buf || !sha_data) { |
601 | 0 | msg = "prepare external auth: calloc error"; |
602 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
603 | 0 | goto prepare_external_auth_end; |
604 | 0 | } |
605 | | |
606 | | /* compose buffer data */ |
607 | 0 | buf3[0] = 0x6A; /* iso padding */ |
608 | 0 | if (RAND_bytes(buf3 + 1, 74) != 1 || /* pRND */ |
609 | 0 | RAND_bytes(sm->ifd.k, 32) != 1) { /* Kifd */ |
610 | 0 | sc_log_openssl(ctx); |
611 | 0 | msg = "prepare external auth: random data error"; |
612 | 0 | res = SC_ERROR_INTERNAL; |
613 | 0 | goto prepare_external_auth_end; |
614 | 0 | } |
615 | 0 | memcpy(buf3 + 1 + 74, sm->ifd.k, 32); /* copy Kifd into buffer */ |
616 | | /* prepare data to be hashed */ |
617 | 0 | memcpy(sha_buf, buf3 + 1, 74); /* copy pRND into sha_buf */ |
618 | 0 | memcpy(sha_buf + 74, buf3 + 1 + 74, 32); /* copy kifd into sha_buf */ |
619 | 0 | memcpy(sha_buf + 74 + 32, sm->icc.rnd, 8); /* copy 8 byte icc challenge */ |
620 | 0 | memcpy(sha_buf + 74 + 32 + 8, sm->icc.sn, 8); /* copy serialnr, 8 bytes */ |
621 | 0 | SHA1(sha_buf, 74 + 32 + 8 + 8, sha_data); |
622 | | /* copy hashed data into buffer */ |
623 | 0 | memcpy(buf3 + 1 + 74 + 32, sha_data, SHA_DIGEST_LENGTH); |
624 | 0 | buf3[127] = 0xBC; /* iso padding */ |
625 | | |
626 | | /* decrypt with ifd private key */ |
627 | 0 | pctx = EVP_PKEY_CTX_new(ifd_privkey, NULL); |
628 | 0 | if (!pctx || |
629 | 0 | EVP_PKEY_decrypt_init(pctx) != 1 || |
630 | 0 | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 || |
631 | 0 | EVP_PKEY_decrypt(pctx, buf2, &len2, buf3, 128) != 1) { |
632 | 0 | sc_log_openssl(ctx); |
633 | 0 | msg = "Prepare external auth: ifd_privk decrypt failed"; |
634 | 0 | res = SC_ERROR_SM_ENCRYPT_FAILED; |
635 | 0 | EVP_PKEY_CTX_free(pctx); |
636 | 0 | goto prepare_external_auth_end; |
637 | 0 | } |
638 | 0 | EVP_PKEY_CTX_free(pctx); |
639 | 0 | pctx = NULL; |
640 | | |
641 | | /* evaluate value of minsig and store into buf3 */ |
642 | 0 | bn = BN_bin2bn(buf2, (int)len2, NULL); |
643 | 0 | bnsub = BN_new(); |
644 | 0 | if (!bn || !bnsub) { |
645 | 0 | sc_log_openssl(ctx); |
646 | 0 | msg = "Prepare external auth: BN creation failed"; |
647 | 0 | res = SC_ERROR_INTERNAL; |
648 | 0 | goto prepare_external_auth_end; |
649 | 0 | } |
650 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
651 | 0 | RSA_get0_key(rsa_ifd_privkey, &ifd_privkey_n, NULL, NULL); |
652 | | #else |
653 | | if (EVP_PKEY_get_bn_param(ifd_privkey, OSSL_PKEY_PARAM_RSA_N, &ifd_privkey_n) != 1) { |
654 | | sc_log_openssl(ctx); |
655 | | msg = "Prepare external auth: BN get param failed"; |
656 | | res = SC_ERROR_INTERNAL; |
657 | | goto prepare_external_auth_end; |
658 | | } |
659 | | #endif |
660 | |
|
661 | 0 | res = BN_sub(bnsub, ifd_privkey_n, bn); /* eval N.IFD-SIG */ |
662 | 0 | if (res == 0) { /* 1:success 0 fail */ |
663 | 0 | sc_log_openssl(ctx); |
664 | 0 | msg = "Prepare external auth: BN sigmin evaluation failed"; |
665 | 0 | res = SC_ERROR_INTERNAL; |
666 | 0 | goto prepare_external_auth_end; |
667 | 0 | } |
668 | 0 | bnres = (BN_cmp(bn, bnsub) < 0) ? bn : bnsub; /* choose min(SIG,N.IFD-SIG) */ |
669 | 0 | if (BN_num_bytes(bnres) > 128) { |
670 | 0 | sc_log_openssl(ctx); |
671 | 0 | msg = "Prepare external auth: BN sigmin result is too big"; |
672 | 0 | res = SC_ERROR_INTERNAL; |
673 | 0 | goto prepare_external_auth_end; |
674 | 0 | } |
675 | 0 | len3 = BN_bn2bin(bnres, buf3); /* convert result back into buf3 */ |
676 | 0 | if (len3 <= 0) { |
677 | 0 | sc_log_openssl(ctx); |
678 | 0 | msg = "Prepare external auth: BN to buffer conversion failed"; |
679 | 0 | res = SC_ERROR_INTERNAL; |
680 | 0 | goto prepare_external_auth_end; |
681 | 0 | } |
682 | | |
683 | | /* re-encrypt result with icc public key */ |
684 | 0 | pctx = EVP_PKEY_CTX_new(icc_pubkey, NULL); |
685 | 0 | if (!pctx || |
686 | 0 | EVP_PKEY_encrypt_init(pctx) != 1 || |
687 | 0 | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 || |
688 | 0 | EVP_PKEY_encrypt(pctx, buf1, &len1, buf3, 128) != 1 || |
689 | 0 | (size_t)len1 != sig_len) { |
690 | 0 | sc_log_openssl(ctx); |
691 | 0 | msg = "Prepare external auth: icc_pubk encrypt failed"; |
692 | 0 | res = SC_ERROR_SM_ENCRYPT_FAILED; |
693 | 0 | EVP_PKEY_CTX_free(pctx); |
694 | 0 | goto prepare_external_auth_end; |
695 | 0 | } |
696 | 0 | EVP_PKEY_CTX_free(pctx); |
697 | | |
698 | | /* process done: copy result into cwa_internal buffer and return success */ |
699 | 0 | memcpy(sig, buf1, len1); |
700 | 0 | res = SC_SUCCESS; |
701 | |
|
702 | 0 | prepare_external_auth_end: |
703 | 0 | BN_free(bn); |
704 | 0 | BN_free(bnsub); |
705 | 0 | if (buf1) { |
706 | 0 | sc_mem_clear(buf1, 128); |
707 | 0 | free(buf1); |
708 | 0 | } |
709 | 0 | if (buf2) { |
710 | 0 | sc_mem_clear(buf2, 128); |
711 | 0 | free(buf2); |
712 | 0 | } |
713 | 0 | if (buf3) { |
714 | 0 | sc_mem_clear(buf3, 128); |
715 | 0 | free(buf3); |
716 | 0 | } |
717 | 0 | if (sha_buf) { |
718 | 0 | sc_mem_clear(sha_buf, 74 + 32 + 8 + 1 + 7); |
719 | 0 | free(sha_buf); |
720 | 0 | } |
721 | 0 | free(sha_data); |
722 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
723 | | BN_clear_free(ifd_privkey_n); |
724 | | #endif |
725 | |
|
726 | 0 | if (res != SC_SUCCESS) { |
727 | 0 | sc_log(ctx, "%s", msg); |
728 | 0 | } |
729 | 0 | LOG_FUNC_RETURN(ctx, res); |
730 | 0 | } |
731 | | |
732 | | /** |
733 | | * SM external authenticate. |
734 | | * |
735 | | * Perform external (IFD) authenticate procedure (8.4.1.2) |
736 | | * |
737 | | * @param card pointer to card data |
738 | | * @param sig signature buffer |
739 | | * @param sig signature buffer length |
740 | | * @return SC_SUCCESS if OK: else error code |
741 | | */ |
742 | | static int cwa_external_auth(sc_card_t * card, u8 * sig, size_t sig_len) |
743 | 0 | { |
744 | 0 | sc_apdu_t apdu; |
745 | 0 | int result = SC_SUCCESS; |
746 | 0 | sc_context_t *ctx = NULL; |
747 | | |
748 | | /* safety check */ |
749 | 0 | if (!card || !card->ctx) |
750 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
751 | 0 | ctx = card->ctx; |
752 | 0 | LOG_FUNC_CALLED(ctx); |
753 | | |
754 | | /* compose apdu for External Authenticate cmd */ |
755 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x00, 0x00, 0, sig_len, |
756 | 0 | NULL, 0, sig, sig_len); |
757 | | |
758 | | /* send composed apdu and parse result */ |
759 | 0 | result = sc_transmit_apdu(card, &apdu); |
760 | 0 | LOG_TEST_RET(ctx, result, "SM external auth failed"); |
761 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
762 | 0 | LOG_TEST_RET(ctx, result, "SM external auth invalid response"); |
763 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
764 | 0 | } |
765 | | |
766 | | /** |
767 | | * SM creation of session keys. |
768 | | * |
769 | | * Compute Kenc,Kmac, and SSC and store it into sm data |
770 | | * |
771 | | * @param card pointer to sc_card_t data |
772 | | * @return SC_SUCCESS if ok; else error code |
773 | | */ |
774 | | static int cwa_compute_session_keys(sc_card_t * card) |
775 | 0 | { |
776 | |
|
777 | 0 | char *msg = NULL; |
778 | 0 | int n = 0; |
779 | 0 | int res = SC_SUCCESS; |
780 | 0 | u8 *kseed; /* to compose kifd ^ kicc */ |
781 | 0 | u8 *data; /* to compose kenc and kmac to be hashed */ |
782 | 0 | u8 *sha_data; /* to store hash result */ |
783 | 0 | u8 kenc[4] = { 0x00, 0x00, 0x00, 0x01 }; |
784 | 0 | u8 kmac[4] = { 0x00, 0x00, 0x00, 0x02 }; |
785 | 0 | sc_context_t *ctx = NULL; |
786 | 0 | struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa; |
787 | | |
788 | | /* safety check */ |
789 | 0 | if (!card || !card->ctx) |
790 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
791 | 0 | ctx = card->ctx; |
792 | 0 | LOG_FUNC_CALLED(ctx); |
793 | | /* Just a literal transcription of cwa14890-1 sections 8.7.2 to 8.9 */ |
794 | 0 | kseed = calloc(32, sizeof(u8)); |
795 | 0 | data = calloc(32 + 4, sizeof(u8)); |
796 | 0 | sha_data = calloc(SHA_DIGEST_LENGTH, sizeof(u8)); |
797 | 0 | if (!kseed || !data || !sha_data) { |
798 | 0 | msg = "Compute Session Keys: calloc() failed"; |
799 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
800 | 0 | goto compute_session_keys_end; |
801 | 0 | } |
802 | | /* compose kseed (cwa-14890-1 sect 8.7.2) */ |
803 | 0 | for (n = 0; n < 32; n++) |
804 | 0 | *(kseed + n) = sm->icc.k[n] ^ sm->ifd.k[n]; |
805 | | |
806 | | /* evaluate kenc (cwa-14890-1 sect 8.8) */ |
807 | 0 | memcpy(data, kseed, 32); |
808 | 0 | memcpy(data + 32, kenc, 4); |
809 | 0 | SHA1(data, 32 + 4, sha_data); |
810 | 0 | memcpy(sm->session_enc, sha_data, 16); /* kenc=16 fsb sha((kifd^kicc)||00000001) */ |
811 | | |
812 | | /* evaluate kmac */ |
813 | 0 | memset(data, 0, 32 + 4); |
814 | 0 | memset(sha_data, 0, SHA_DIGEST_LENGTH); /* clear buffers */ |
815 | |
|
816 | 0 | memcpy(data, kseed, 32); |
817 | 0 | memcpy(data + 32, kmac, 4); |
818 | 0 | SHA1(data, 32 + 4, sha_data); |
819 | 0 | memcpy(sm->session_mac, sha_data, 16); /* kmac=16 fsb sha((kifd^kicc)||00000002) */ |
820 | | |
821 | | /* evaluate send sequence counter (cwa-14890-1 sect 8.9 & 9.6 */ |
822 | 0 | memcpy(sm->ssc, sm->icc.rnd + 4, 4); /* 4 least significant bytes of rndicc */ |
823 | 0 | memcpy(sm->ssc + 4, sm->ifd.rnd + 4, 4); /* 4 least significant bytes of rndifd */ |
824 | | |
825 | | /* arriving here means process ok */ |
826 | 0 | res = SC_SUCCESS; |
827 | |
|
828 | 0 | compute_session_keys_end: |
829 | 0 | if (kseed) { |
830 | 0 | sc_mem_clear(kseed, 32); |
831 | 0 | free(kseed); |
832 | 0 | } |
833 | 0 | if (data) { |
834 | 0 | sc_mem_clear(data, 32 + 4); |
835 | 0 | free(data); |
836 | 0 | } |
837 | 0 | free(sha_data); |
838 | 0 | if (res != SC_SUCCESS) |
839 | 0 | sc_log(ctx, "%s", msg); |
840 | 0 | else { |
841 | 0 | sc_log(ctx, "Kenc: %s", sc_dump_hex(sm->session_enc, 16)); |
842 | 0 | sc_log(ctx, "Kmac: %s", sc_dump_hex(sm->session_mac, 16)); |
843 | 0 | sc_log(ctx, "SSC: %s", sc_dump_hex(sm->ssc, 8)); |
844 | 0 | } |
845 | 0 | LOG_FUNC_RETURN(ctx, res); |
846 | 0 | } |
847 | | |
848 | | /* |
849 | | * Compare signature for internal auth procedure. |
850 | | * |
851 | | * @param data Received data to be checked |
852 | | * @param dlen data length |
853 | | * @param expected results |
854 | | * @return SC_SUCCESS or error code |
855 | | */ |
856 | | static int cwa_compare_signature(u8 * data, size_t dlen, u8 * ifd_data) |
857 | 0 | { |
858 | 0 | u8 *buf = calloc(74 + 32 + 32, sizeof(u8)); |
859 | 0 | u8 *sha = calloc(SHA_DIGEST_LENGTH, sizeof(u8)); |
860 | 0 | int res = SC_SUCCESS; |
861 | 0 | if (!buf || !sha) { |
862 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
863 | 0 | goto compare_signature_end; |
864 | 0 | } |
865 | 0 | res = SC_ERROR_INVALID_DATA; |
866 | 0 | if (dlen != 128) |
867 | 0 | goto compare_signature_end; /* check length */ |
868 | 0 | if (data[0] != 0x6a) |
869 | 0 | goto compare_signature_end; /* iso 9796-2 padding */ |
870 | 0 | if (data[127] != 0xBC) |
871 | 0 | goto compare_signature_end; /* iso 9796-2 padding */ |
872 | 0 | memcpy(buf, data + 1, 74 + 32); |
873 | 0 | memcpy(buf + 74 + 32, ifd_data, 16); |
874 | 0 | SHA1(buf, 74 + 32 + 16, sha); |
875 | 0 | if (memcmp(data + 127 - SHA_DIGEST_LENGTH, sha, SHA_DIGEST_LENGTH) == 0) |
876 | 0 | res = SC_SUCCESS; |
877 | 0 | compare_signature_end: |
878 | 0 | free(buf); |
879 | 0 | free(sha); |
880 | 0 | return res; |
881 | 0 | } |
882 | | |
883 | | /** |
884 | | * check the result of internal_authenticate operation. |
885 | | * |
886 | | * Checks icc received data from internal auth procedure against |
887 | | * expected results |
888 | | * |
889 | | * @param card Pointer to sc_card_t data |
890 | | * @param icc_pubkey icc public key |
891 | | * @param ifd_privkey ifd private key |
892 | | * @param ifdbuf buffer containing ( RND.IFD || SN.IFD ) |
893 | | * @param ifdlen buffer length; should be 16 |
894 | | * @param sig signature buffer |
895 | | * @param sig_len signature buffer length |
896 | | * @return SC_SUCCESS if ok; else error code |
897 | | */ |
898 | | static int cwa_verify_internal_auth(sc_card_t * card, |
899 | | EVP_PKEY *icc_pubkey, |
900 | | EVP_PKEY *ifd_privkey, |
901 | | u8 * ifdbuf, |
902 | | size_t ifdlen, |
903 | | u8 * sig, |
904 | | size_t sig_len) |
905 | 0 | { |
906 | 0 | int res = SC_SUCCESS; |
907 | 0 | char *msg = NULL; |
908 | 0 | u8 *buf1 = NULL; /* to decrypt with our private key */ |
909 | 0 | u8 *buf2 = NULL; /* to try SIGNUM==SIG */ |
910 | 0 | u8 *buf3 = NULL; /* to try SIGNUM==N.ICC-SIG */ |
911 | 0 | size_t len1 = 128, len2 = 128, len3 = 128; |
912 | 0 | BIGNUM *bn = NULL; |
913 | 0 | BIGNUM *sigbn = NULL; |
914 | 0 | sc_context_t *ctx = NULL; |
915 | 0 | struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa; |
916 | 0 | EVP_PKEY_CTX *pctx = NULL; |
917 | |
|
918 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
919 | 0 | const BIGNUM *icc_pubkey_n = NULL; |
920 | 0 | const RSA *rsa_icc_pubkey = EVP_PKEY_get0_RSA(icc_pubkey); |
921 | 0 | if (!rsa_icc_pubkey) { |
922 | 0 | res = SC_ERROR_INTERNAL; |
923 | 0 | msg = "Can not extract RSA object icc pub"; |
924 | 0 | goto verify_internal_done; |
925 | 0 | } |
926 | | #else |
927 | | BIGNUM *icc_pubkey_n = NULL; |
928 | | #endif |
929 | | |
930 | 0 | if (!card || !card->ctx) |
931 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
932 | 0 | ctx = card->ctx; |
933 | 0 | LOG_FUNC_CALLED(ctx); |
934 | 0 | if (!ifdbuf || (ifdlen != 16)) { |
935 | 0 | res = SC_ERROR_INVALID_ARGUMENTS; |
936 | 0 | msg = "Null buffers received as parameters"; |
937 | 0 | goto verify_internal_done; |
938 | 0 | } |
939 | 0 | if (!icc_pubkey || !ifd_privkey) { |
940 | 0 | res = SC_ERROR_SM_NO_SESSION_KEYS; |
941 | 0 | msg = "Either provided icc_pubk or ifd_privk are null"; |
942 | 0 | goto verify_internal_done; |
943 | 0 | } |
944 | 0 | buf1 = (u8 *) calloc(128, sizeof(u8)); /* 128: RSA key len in bytes */ |
945 | 0 | buf2 = (u8 *) calloc(128, sizeof(u8)); |
946 | 0 | buf3 = (u8 *) calloc(128, sizeof(u8)); |
947 | 0 | if (!buf1 || !buf2 || !buf3) { |
948 | 0 | msg = "Verify Signature: calloc() error"; |
949 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
950 | 0 | goto verify_internal_done; |
951 | 0 | } |
952 | | |
953 | | /* |
954 | | We have received data with this format: |
955 | | sigbuf = E[PK.IFD.AUT](SIGMIN) |
956 | | SIGMIN = min ( SIG, N.ICC-SIG ) |
957 | | SIG= DS[SK.ICC.AUT] ( |
958 | | 0x6A || |
959 | | PRND1 || |
960 | | Kicc || |
961 | | sha1_hash(PRND1 || Kicc || RND.IFD || SN.IFD) || |
962 | | 0xBC |
963 | | ) |
964 | | So we should reverse the process and try to get valid results |
965 | | */ |
966 | | |
967 | | /* decrypt data with our ifd priv key */ |
968 | 0 | pctx = EVP_PKEY_CTX_new(ifd_privkey, NULL); |
969 | 0 | if (!pctx || |
970 | 0 | EVP_PKEY_decrypt_init(pctx) != 1 || |
971 | 0 | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 || |
972 | 0 | EVP_PKEY_decrypt(pctx, buf1, &len1, sig, sig_len) != 1) { |
973 | 0 | sc_log_openssl(ctx); |
974 | 0 | msg = "Verify Signature: decrypt with ifd privk failed"; |
975 | 0 | res = SC_ERROR_SM_ENCRYPT_FAILED; |
976 | 0 | EVP_PKEY_CTX_free(pctx); |
977 | 0 | goto verify_internal_done; |
978 | 0 | } |
979 | 0 | EVP_PKEY_CTX_free(pctx); |
980 | 0 | pctx = NULL; |
981 | | |
982 | | /* OK: now we have SIGMIN in buf1 */ |
983 | | /* check if SIGMIN data matches SIG or N.ICC-SIG */ |
984 | | /* evaluate DS[SK.ICC.AUTH](SIG) trying to decrypt with icc pubk */ |
985 | 0 | pctx = EVP_PKEY_CTX_new(icc_pubkey, NULL); |
986 | 0 | if (!pctx || |
987 | 0 | EVP_PKEY_encrypt_init(pctx) != 1 || |
988 | 0 | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 || |
989 | 0 | EVP_PKEY_encrypt(pctx, buf3, &len3, buf1, len1) != 1) { |
990 | 0 | EVP_PKEY_CTX_free(pctx); |
991 | 0 | sc_log_openssl(ctx); |
992 | 0 | goto verify_nicc_sig; /* evaluate N.ICC-SIG and retry */ |
993 | 0 | } |
994 | | |
995 | 0 | EVP_PKEY_CTX_free(pctx); |
996 | |
|
997 | 0 | res = cwa_compare_signature(buf3, len3, ifdbuf); |
998 | 0 | if (res == SC_SUCCESS) |
999 | 0 | goto verify_internal_ok; |
1000 | | |
1001 | 0 | verify_nicc_sig: |
1002 | | /* |
1003 | | * Arriving here means need to evaluate N.ICC-SIG |
1004 | | * So convert buffers to bignums to operate |
1005 | | */ |
1006 | 0 | bn = BN_bin2bn(buf1, (int)len1, NULL); /* create BN data */ |
1007 | 0 | sigbn = BN_new(); |
1008 | 0 | if (!bn || !sigbn) { |
1009 | 0 | sc_log_openssl(ctx); |
1010 | 0 | msg = "Verify Signature: cannot bignums creation error"; |
1011 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1012 | 0 | goto verify_internal_done; |
1013 | 0 | } |
1014 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
1015 | 0 | RSA_get0_key(rsa_icc_pubkey, &icc_pubkey_n, NULL, NULL); |
1016 | | #else |
1017 | | if (EVP_PKEY_get_bn_param(icc_pubkey, OSSL_PKEY_PARAM_RSA_N, &icc_pubkey_n) != 1) { |
1018 | | sc_log_openssl(ctx); |
1019 | | msg = "Verify Signature: BN get param failed"; |
1020 | | res = SC_ERROR_INTERNAL; |
1021 | | goto verify_internal_done; |
1022 | | } |
1023 | | #endif |
1024 | 0 | res = BN_sub(sigbn, icc_pubkey_n, bn); /* eval N.ICC-SIG */ |
1025 | 0 | if (!res) { |
1026 | 0 | sc_log_openssl(ctx); |
1027 | 0 | msg = "Verify Signature: evaluation of N.ICC-SIG failed"; |
1028 | 0 | res = SC_ERROR_INTERNAL; |
1029 | 0 | goto verify_internal_done; |
1030 | 0 | } |
1031 | 0 | len2 = BN_bn2bin(sigbn, buf2); /* copy result to buffer */ |
1032 | 0 | if (len2 <= 0) { |
1033 | 0 | sc_log_openssl(ctx); |
1034 | 0 | msg = "Verify Signature: cannot convert bignum to buffer"; |
1035 | 0 | res = SC_ERROR_INTERNAL; |
1036 | 0 | goto verify_internal_done; |
1037 | 0 | } |
1038 | | /* ok: check again with new data */ |
1039 | | /* evaluate DS[SK.ICC.AUTH](I.ICC-SIG) trying to decrypt with icc pubk */ |
1040 | 0 | pctx = EVP_PKEY_CTX_new(icc_pubkey, NULL); |
1041 | 0 | if (!pctx || |
1042 | 0 | EVP_PKEY_encrypt_init(pctx) != 1 || |
1043 | 0 | EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 || |
1044 | 0 | EVP_PKEY_encrypt(pctx, buf3, &len3, buf2, len2) != 1) { |
1045 | 0 | sc_log_openssl(ctx); |
1046 | 0 | msg = "Verify Signature: cannot get valid SIG data"; |
1047 | 0 | res = SC_ERROR_INVALID_DATA; |
1048 | 0 | EVP_PKEY_CTX_free(pctx); |
1049 | 0 | goto verify_internal_done; |
1050 | 0 | } |
1051 | 0 | EVP_PKEY_CTX_free(pctx); |
1052 | 0 | pctx = NULL; |
1053 | |
|
1054 | 0 | res = cwa_compare_signature(buf3, len3, ifdbuf); |
1055 | 0 | if (res != SC_SUCCESS) { |
1056 | 0 | msg = "Verify Signature: cannot get valid SIG data"; |
1057 | 0 | res = SC_ERROR_INVALID_DATA; |
1058 | 0 | goto verify_internal_done; |
1059 | 0 | } |
1060 | | /* arriving here means OK: complete data structures */ |
1061 | 0 | verify_internal_ok: |
1062 | 0 | memcpy(sm->icc.k, buf3 + 1 + 74, 32); /* extract Kicc from buf3 */ |
1063 | 0 | res = SC_SUCCESS; |
1064 | 0 | verify_internal_done: |
1065 | 0 | free(buf1); |
1066 | 0 | free(buf2); |
1067 | 0 | free(buf3); |
1068 | 0 | BN_free(bn); |
1069 | 0 | BN_free(sigbn); |
1070 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
1071 | | BN_clear_free(icc_pubkey_n); |
1072 | | #endif |
1073 | 0 | if (res != SC_SUCCESS) { |
1074 | 0 | sc_log(ctx, "%s", msg); |
1075 | 0 | } |
1076 | 0 | LOG_FUNC_RETURN(ctx, res); |
1077 | 0 | } |
1078 | | |
1079 | | /** |
1080 | | * Create Secure Messaging channel. |
1081 | | * |
1082 | | * This is the main entry point for CWA14890 SM channel creation. |
1083 | | * It closely follows cwa standard, with a minor modification: |
1084 | | * - ICC serial number is taken at the beginning of SM creation |
1085 | | * - ICC and IFD certificate agreement process is reversed, to allow |
1086 | | * card to retain key references on further process (this behavior |
1087 | | * is also defined in standard) |
1088 | | * |
1089 | | * Based on Several documents: |
1090 | | * - "Understanding the DNIe" |
1091 | | * - "Manual de comandos del DNIe" |
1092 | | * - ISO7816-4 and CWA14890-{1,2} |
1093 | | * |
1094 | | * @param card card info structure |
1095 | | * @param provider cwa14890 info provider |
1096 | | * @param flag requested init method ( OFF, COLD, WARM ) |
1097 | | * @return SC_SUCCESS if OK; else error code |
1098 | | */ |
1099 | | int cwa_create_secure_channel(sc_card_t * card, |
1100 | | cwa_provider_t * provider, int flag) |
1101 | 0 | { |
1102 | 0 | u8 *cert = NULL; |
1103 | 0 | size_t certlen; |
1104 | |
|
1105 | 0 | int res = SC_SUCCESS; |
1106 | 0 | char *msg = "Success"; |
1107 | | |
1108 | | /* data to get and parse certificates */ |
1109 | 0 | X509 *icc_cert = NULL; |
1110 | 0 | X509 *ca_cert = NULL; |
1111 | 0 | EVP_PKEY *icc_pubkey = NULL; |
1112 | 0 | EVP_PKEY *ifd_privkey = NULL; |
1113 | 0 | sc_context_t *ctx = NULL; |
1114 | 0 | struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa; |
1115 | 0 | u8 sig[128]; |
1116 | | |
1117 | | /* several buffer and buffer pointers */ |
1118 | 0 | u8 *buffer = NULL; |
1119 | 0 | size_t bufferlen; |
1120 | 0 | u8 *tlv = NULL; /* buffer to compose TLV messages */ |
1121 | 0 | size_t tlvlen = 0; |
1122 | 0 | u8 rndbuf[16]; /* 8 RND.IFD + 8 SN.IFD */ |
1123 | | |
1124 | | /* preliminary checks */ |
1125 | 0 | if (!card || !card->ctx ) |
1126 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1127 | 0 | if (!provider) |
1128 | 0 | return SC_ERROR_SM_NOT_INITIALIZED; |
1129 | | /* commodity vars */ |
1130 | 0 | ctx = card->ctx; |
1131 | |
|
1132 | 0 | LOG_FUNC_CALLED(ctx); |
1133 | | |
1134 | | /* check requested initialization method */ |
1135 | 0 | switch (flag) { |
1136 | 0 | case CWA_SM_OFF: /* disable SM */ |
1137 | 0 | card->sm_ctx.sm_mode = SM_MODE_NONE; |
1138 | 0 | sc_log(ctx, "Setting CWA SM status to none"); |
1139 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1140 | 0 | case CWA_SM_ON: /* force sm initialization process */ |
1141 | 0 | sc_log(ctx, "CWA SM initialization requested"); |
1142 | 0 | break; |
1143 | 0 | default: |
1144 | 0 | sc_log(ctx, "Invalid provided SM initialization flag"); |
1145 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1146 | 0 | } |
1147 | | |
1148 | | /* OK: lets start process */ |
1149 | | |
1150 | | /* call provider pre-operation method */ |
1151 | 0 | sc_log(ctx, "CreateSecureChannel pre-operations"); |
1152 | 0 | if (provider->cwa_create_pre_ops) { |
1153 | 0 | res = provider->cwa_create_pre_ops(card, provider); |
1154 | 0 | if (res != SC_SUCCESS) { |
1155 | 0 | msg = "Create SM: provider pre_ops() failed"; |
1156 | 0 | sc_log(ctx, "%s", msg); |
1157 | 0 | goto csc_end; |
1158 | 0 | } |
1159 | 0 | } |
1160 | | |
1161 | | /* retrieve icc serial number */ |
1162 | 0 | sc_log(ctx, "Retrieve ICC serial number"); |
1163 | 0 | if (provider->cwa_get_sn_icc) { |
1164 | 0 | res = provider->cwa_get_sn_icc(card); |
1165 | 0 | if (res != SC_SUCCESS) { |
1166 | 0 | msg = "Retrieve ICC failed"; |
1167 | 0 | sc_log(ctx, "%s", msg); |
1168 | 0 | goto csc_end; |
1169 | 0 | } |
1170 | 0 | } else { |
1171 | 0 | msg = "Don't know how to obtain ICC serial number"; |
1172 | 0 | sc_log(ctx, "%s", msg); |
1173 | 0 | res = SC_ERROR_INTERNAL; |
1174 | 0 | goto csc_end; |
1175 | 0 | } |
1176 | | |
1177 | | /* |
1178 | | * Notice that this code inverts ICC and IFD certificate standard |
1179 | | * checking sequence. |
1180 | | */ |
1181 | | |
1182 | | /* Read Intermediate CA from card */ |
1183 | 0 | if (!provider->cwa_get_icc_intermediate_ca_cert) { |
1184 | 0 | sc_log(ctx, |
1185 | 0 | "Step 8.4.1.6: Skip Retrieving ICC intermediate CA"); |
1186 | 0 | ca_cert = NULL; |
1187 | 0 | } else { |
1188 | 0 | sc_log(ctx, "Step 8.4.1.7: Retrieving ICC intermediate CA"); |
1189 | 0 | res = |
1190 | 0 | provider->cwa_get_icc_intermediate_ca_cert(card, &ca_cert); |
1191 | 0 | if (res != SC_SUCCESS) { |
1192 | 0 | msg = |
1193 | 0 | "Cannot get ICC intermediate CA certificate from provider"; |
1194 | 0 | goto csc_end; |
1195 | 0 | } |
1196 | 0 | } |
1197 | | |
1198 | | /* Read ICC certificate from card */ |
1199 | 0 | sc_log(ctx, "Step 8.4.1.8: Retrieve ICC certificate"); |
1200 | 0 | res = provider->cwa_get_icc_cert(card, &icc_cert); |
1201 | 0 | if (res != SC_SUCCESS) { |
1202 | 0 | msg = "Cannot get ICC certificate from provider"; |
1203 | 0 | goto csc_end; |
1204 | 0 | } |
1205 | | |
1206 | | /* Verify icc Card certificate chain */ |
1207 | | /* Notice that Some implementations doesn't verify cert chain |
1208 | | * but simply verifies that icc_cert is a valid certificate */ |
1209 | 0 | if (ca_cert) { |
1210 | 0 | sc_log(ctx, "Verifying ICC certificate chain"); |
1211 | 0 | res = |
1212 | 0 | cwa_verify_icc_certificates(card, provider, ca_cert, |
1213 | 0 | icc_cert); |
1214 | 0 | if (res != SC_SUCCESS) { |
1215 | 0 | res = SC_ERROR_SM_AUTHENTICATION_FAILED; |
1216 | 0 | msg = "Icc Certificates verification failed"; |
1217 | 0 | goto csc_end; |
1218 | 0 | } |
1219 | 0 | } else { |
1220 | 0 | sc_log(ctx, "Cannot verify Certificate chain. skip step"); |
1221 | 0 | } |
1222 | | |
1223 | | /* Extract public key from ICC certificate */ |
1224 | 0 | if (!(icc_pubkey = X509_get_pubkey(icc_cert))) { |
1225 | 0 | res = SC_ERROR_INTERNAL; |
1226 | 0 | sc_log_openssl(ctx); |
1227 | 0 | msg = "Cannot extract public key from ICC certificate"; |
1228 | 0 | goto csc_end; |
1229 | 0 | } |
1230 | | |
1231 | | /* Select Root CA in card for ifd certificate verification */ |
1232 | 0 | sc_log(ctx, |
1233 | 0 | "Step 8.4.1.2: Select Root CA in card for IFD cert verification"); |
1234 | 0 | res = provider->cwa_get_root_ca_pubkey_ref(card, &buffer, &bufferlen); |
1235 | 0 | if (res != SC_SUCCESS) { |
1236 | 0 | msg = "Cannot get Root CA key reference from provider"; |
1237 | 0 | goto csc_end; |
1238 | 0 | } |
1239 | 0 | tlvlen = 0; |
1240 | 0 | tlv = calloc(10 + bufferlen, sizeof(u8)); |
1241 | 0 | if (!tlv) { |
1242 | 0 | msg = "calloc error"; |
1243 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1244 | 0 | goto csc_end; |
1245 | 0 | } |
1246 | 0 | res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen); |
1247 | 0 | if (res != SC_SUCCESS) { |
1248 | 0 | msg = "Cannot compose tlv for setting Root CA key reference"; |
1249 | 0 | goto csc_end; |
1250 | 0 | } |
1251 | 0 | res = cwa_set_security_env(card, 0x81, 0xB6, tlv, tlvlen); |
1252 | 0 | if (res != SC_SUCCESS) { |
1253 | 0 | msg = "Select Root CA key ref failed"; |
1254 | 0 | goto csc_end; |
1255 | 0 | } |
1256 | | |
1257 | | /* Send IFD intermediate CA in CVC format C_CV_CA */ |
1258 | 0 | sc_log(ctx, |
1259 | 0 | "Step 8.4.1.3: Send CVC IFD intermediate CA Cert for ICC verification"); |
1260 | 0 | res = provider->cwa_get_cvc_ca_cert(card, &cert, &certlen); |
1261 | 0 | if (res != SC_SUCCESS) { |
1262 | 0 | msg = "Get CVC CA cert from provider failed"; |
1263 | 0 | goto csc_end; |
1264 | 0 | } |
1265 | 0 | res = cwa_verify_cvc_certificate(card, cert, certlen); |
1266 | 0 | if (res != SC_SUCCESS) { |
1267 | 0 | msg = "Verify CVC CA failed"; |
1268 | 0 | goto csc_end; |
1269 | 0 | } |
1270 | | |
1271 | | /* select public key reference for sent IFD intermediate CA certificate */ |
1272 | 0 | sc_log(ctx, |
1273 | 0 | "Step 8.4.1.4: Select Intermediate CA pubkey ref for ICC verification"); |
1274 | 0 | res = |
1275 | 0 | provider->cwa_get_intermediate_ca_pubkey_ref(card, &buffer, |
1276 | 0 | &bufferlen); |
1277 | 0 | if (res != SC_SUCCESS) { |
1278 | 0 | msg = "Cannot get intermediate CA key reference from provider"; |
1279 | 0 | goto csc_end; |
1280 | 0 | } |
1281 | 0 | tlvlen = 0; |
1282 | 0 | free(tlv); |
1283 | 0 | tlv = calloc(10 + bufferlen, sizeof(u8)); |
1284 | 0 | if (!tlv) { |
1285 | 0 | msg = "calloc error"; |
1286 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1287 | 0 | goto csc_end; |
1288 | 0 | } |
1289 | 0 | res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen); |
1290 | 0 | if (res != SC_SUCCESS) { |
1291 | 0 | msg = |
1292 | 0 | "Cannot compose tlv for setting intermediate CA key reference"; |
1293 | 0 | goto csc_end; |
1294 | 0 | } |
1295 | 0 | res = cwa_set_security_env(card, 0x81, 0xB6, tlv, tlvlen); |
1296 | 0 | if (res != SC_SUCCESS) { |
1297 | 0 | msg = "Select CVC CA pubk failed"; |
1298 | 0 | goto csc_end; |
1299 | 0 | } |
1300 | | |
1301 | | /* Send IFD certificate in CVC format C_CV_IFD */ |
1302 | 0 | sc_log(ctx, |
1303 | 0 | "Step 8.4.1.5: Send CVC IFD Certificate for ICC verification"); |
1304 | 0 | res = provider->cwa_get_cvc_ifd_cert(card, &cert, &certlen); |
1305 | 0 | if (res != SC_SUCCESS) { |
1306 | 0 | msg = "Get CVC IFD cert from provider failed"; |
1307 | 0 | goto csc_end; |
1308 | 0 | } |
1309 | 0 | res = cwa_verify_cvc_certificate(card, cert, certlen); |
1310 | 0 | if (res != SC_SUCCESS) { |
1311 | 0 | msg = "Verify CVC IFD failed"; |
1312 | 0 | goto csc_end; |
1313 | 0 | } |
1314 | | |
1315 | | /* remember that this code changes IFD and ICC Cert verification steps */ |
1316 | | |
1317 | | /* select public key of ifd certificate and icc private key */ |
1318 | 0 | sc_log(ctx, |
1319 | 0 | "Step 8.4.1.9: Send IFD pubk and ICC privk key references for Internal Auth"); |
1320 | 0 | res = provider->cwa_get_ifd_pubkey_ref(card, &buffer, &bufferlen); |
1321 | 0 | if (res != SC_SUCCESS) { |
1322 | 0 | msg = "Cannot get ifd public key reference from provider"; |
1323 | 0 | goto csc_end; |
1324 | 0 | } |
1325 | 0 | tlvlen = 0; |
1326 | 0 | free(tlv); |
1327 | 0 | tlv = calloc(10 + bufferlen, sizeof(u8)); |
1328 | 0 | if (!tlv) { |
1329 | 0 | msg = "calloc error"; |
1330 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1331 | 0 | goto csc_end; |
1332 | 0 | } |
1333 | 0 | res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen); |
1334 | 0 | if (res != SC_SUCCESS) { |
1335 | 0 | msg = "Cannot compose tlv for setting ifd pubkey reference"; |
1336 | 0 | goto csc_end; |
1337 | 0 | } |
1338 | 0 | res = provider->cwa_get_icc_privkey_ref(card, &buffer, &bufferlen); |
1339 | 0 | if (res != SC_SUCCESS) { |
1340 | 0 | msg = "Cannot get icc private key reference from provider"; |
1341 | 0 | goto csc_end; |
1342 | 0 | } |
1343 | | /* add this tlv to old one; do not call calloc */ |
1344 | 0 | res = cwa_compose_tlv(card, 0x84, bufferlen, buffer, &tlv, &tlvlen); |
1345 | 0 | if (res != SC_SUCCESS) { |
1346 | 0 | msg = "Cannot compose tlv for setting ifd pubkey reference"; |
1347 | 0 | goto csc_end; |
1348 | 0 | } |
1349 | | |
1350 | 0 | res = cwa_set_security_env(card, 0xC1, 0xA4, tlv, tlvlen); |
1351 | 0 | if (res != SC_SUCCESS) { |
1352 | 0 | msg = "Select CVC IFD pubk failed"; |
1353 | 0 | goto csc_end; |
1354 | 0 | } |
1355 | | |
1356 | | /* Internal (Card) authentication (let the card verify sent ifd certs) |
1357 | | SN.IFD equals 8 lsb bytes of ifd.pubk ref according cwa14890 sec 8.4.1 */ |
1358 | 0 | sc_log(ctx, "Step 8.4.1.10: Perform Internal authentication"); |
1359 | 0 | res = provider->cwa_get_sn_ifd(card); |
1360 | 0 | if (res != SC_SUCCESS) { |
1361 | 0 | msg = "Cannot get ifd serial number from provider"; |
1362 | 0 | goto csc_end; |
1363 | 0 | } |
1364 | | /* generate 8 random bytes */ |
1365 | 0 | if (RAND_bytes(sm->ifd.rnd, 8) != 1) { |
1366 | 0 | msg = "Cannot generate random data"; |
1367 | 0 | res = SC_ERROR_INTERNAL; |
1368 | 0 | goto csc_end; |
1369 | 0 | } |
1370 | 0 | memcpy(rndbuf, sm->ifd.rnd, 8); /* insert RND.IFD into rndbuf */ |
1371 | 0 | memcpy(rndbuf + 8, sm->ifd.sn, 8); /* insert SN.IFD into rndbuf */ |
1372 | 0 | res = cwa_internal_auth(card, sig, 128, rndbuf, 16); |
1373 | 0 | if (res != SC_SUCCESS) { |
1374 | 0 | msg = "Internal auth cmd failed"; |
1375 | 0 | goto csc_end; |
1376 | 0 | } |
1377 | | |
1378 | | /* retrieve ifd private key from provider */ |
1379 | 0 | res = provider->cwa_get_ifd_privkey(card, &ifd_privkey); |
1380 | 0 | if (res != SC_SUCCESS) { |
1381 | 0 | msg = "Cannot retrieve IFD private key from provider"; |
1382 | 0 | res = SC_ERROR_SM_NO_SESSION_KEYS; |
1383 | 0 | goto csc_end; |
1384 | 0 | } |
1385 | | |
1386 | | /* verify received signature */ |
1387 | 0 | sc_log(ctx, "Verify Internal Auth command response"); |
1388 | 0 | res = cwa_verify_internal_auth(card, icc_pubkey, /* evaluated icc public key */ |
1389 | 0 | ifd_privkey, /* evaluated from DGP's Manual Annex 3 Data */ |
1390 | 0 | rndbuf, /* RND.IFD || SN.IFD */ |
1391 | 0 | 16, /* rndbuf length; should be 16 */ |
1392 | 0 | sig, 128 |
1393 | 0 | ); |
1394 | 0 | if (res != SC_SUCCESS) { |
1395 | 0 | msg = "Internal Auth Verify failed"; |
1396 | 0 | goto csc_end; |
1397 | 0 | } |
1398 | | |
1399 | | /* get challenge: retrieve 8 random bytes from card */ |
1400 | 0 | sc_log(ctx, "Step 8.4.1.11: Prepare External Auth: Get Challenge"); |
1401 | 0 | res = sc_get_challenge(card, sm->icc.rnd, sizeof(sm->icc.rnd)); |
1402 | 0 | if (res != SC_SUCCESS) { |
1403 | 0 | msg = "Get Challenge failed"; |
1404 | 0 | goto csc_end; |
1405 | 0 | } |
1406 | | |
1407 | | /* compose signature data for external auth */ |
1408 | 0 | res = cwa_prepare_external_auth(card, icc_pubkey, ifd_privkey, sig, 128); |
1409 | 0 | if (res != SC_SUCCESS) { |
1410 | 0 | msg = "Prepare external auth failed"; |
1411 | 0 | goto csc_end; |
1412 | 0 | } |
1413 | | |
1414 | | /* External (IFD) authentication */ |
1415 | 0 | sc_log(ctx, "Step 8.4.1.12: Perform External (IFD) Authentication"); |
1416 | 0 | res = cwa_external_auth(card, sig, 128); |
1417 | 0 | if (res != SC_SUCCESS) { |
1418 | 0 | msg = "External auth cmd failed"; |
1419 | 0 | goto csc_end; |
1420 | 0 | } |
1421 | | |
1422 | | /* Session key generation */ |
1423 | 0 | sc_log(ctx, "Step 8.4.2: Compute Session Keys"); |
1424 | 0 | res = cwa_compute_session_keys(card); |
1425 | 0 | if (res != SC_SUCCESS) { |
1426 | 0 | msg = "Session Key generation failed"; |
1427 | 0 | goto csc_end; |
1428 | 0 | } |
1429 | | |
1430 | | /* call provider post-operation method */ |
1431 | 0 | sc_log(ctx, "CreateSecureChannel post-operations"); |
1432 | 0 | if (provider->cwa_create_post_ops) { |
1433 | 0 | res = provider->cwa_create_post_ops(card, provider); |
1434 | 0 | if (res != SC_SUCCESS) { |
1435 | 0 | sc_log(ctx, "Create SM: provider post_ops() failed"); |
1436 | 0 | goto csc_end; |
1437 | 0 | } |
1438 | 0 | } |
1439 | | |
1440 | | /* arriving here means ok: cleanup */ |
1441 | 0 | res = SC_SUCCESS; |
1442 | 0 | csc_end: |
1443 | 0 | free(tlv); |
1444 | 0 | X509_free(icc_cert); |
1445 | 0 | X509_free(ca_cert); |
1446 | 0 | EVP_PKEY_free(icc_pubkey); |
1447 | 0 | EVP_PKEY_free(ifd_privkey); |
1448 | | /* setup SM state according result */ |
1449 | 0 | if (res != SC_SUCCESS) { |
1450 | 0 | sc_log(ctx, "%s", msg); |
1451 | 0 | card->sm_ctx.sm_mode = SM_MODE_NONE; |
1452 | 0 | } else { |
1453 | 0 | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
1454 | 0 | } |
1455 | 0 | LOG_FUNC_RETURN(ctx, res); |
1456 | 0 | } |
1457 | | |
1458 | | /******************* SM internal APDU encoding / decoding functions ******/ |
1459 | | |
1460 | | /** |
1461 | | * Encode an APDU. |
1462 | | * |
1463 | | * Calling this functions means that It's has been verified |
1464 | | * That source apdu needs encoding |
1465 | | * Based on section 9 of CWA-14890 and Sect 6 of iso7816-4 standards |
1466 | | * And DNIe's manual |
1467 | | * |
1468 | | * @param card card info structure |
1469 | | * @param sm Secure Messaging state information |
1470 | | * @param from APDU to be encoded |
1471 | | * @param to where to store encoded apdu |
1472 | | * @return SC_SUCCESS if ok; else error code |
1473 | | */ |
1474 | | int cwa_encode_apdu(sc_card_t * card, |
1475 | | cwa_provider_t * provider, sc_apdu_t * from, sc_apdu_t * to) |
1476 | 0 | { |
1477 | 0 | u8 *apdubuf = NULL; /* to store resulting apdu */ |
1478 | 0 | size_t apdulen, tlv_len; |
1479 | 0 | u8 *ccbuf = NULL; /* where to store data to eval cryptographic checksum CC */ |
1480 | 0 | size_t cclen = 0; |
1481 | 0 | u8 macbuf[8]; /* to store and compute CC */ |
1482 | 0 | char *msg = NULL; |
1483 | |
|
1484 | 0 | size_t i, j; /* for xor loops */ |
1485 | 0 | int res = SC_SUCCESS; |
1486 | 0 | sc_context_t *ctx = NULL; |
1487 | 0 | struct sm_cwa_session * sm_session = &card->sm_ctx.info.session.cwa; |
1488 | 0 | u8 *msgbuf = NULL; /* to encrypt apdu data */ |
1489 | 0 | u8 *cryptbuf = NULL; |
1490 | |
|
1491 | 0 | EVP_CIPHER_CTX *cctx = NULL; |
1492 | 0 | EVP_CIPHER *alg = NULL; |
1493 | 0 | unsigned char *key = NULL; |
1494 | 0 | int tmplen = 0; |
1495 | | |
1496 | | /* mandatory check */ |
1497 | 0 | if (!card || !card->ctx || !provider) |
1498 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1499 | 0 | ctx = card->ctx; |
1500 | |
|
1501 | 0 | LOG_FUNC_CALLED(ctx); |
1502 | | /* check remaining arguments */ |
1503 | 0 | if (!from || !to || !sm_session) |
1504 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_INITIALIZED); |
1505 | 0 | if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) |
1506 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL); |
1507 | | |
1508 | | /* reserve extra bytes for padding and tlv header */ |
1509 | 0 | msgbuf = calloc(12 + from->lc, sizeof(u8)); /* to encrypt apdu data */ |
1510 | 0 | cryptbuf = calloc(12 + from->lc, sizeof(u8)); |
1511 | 0 | if (!msgbuf || !cryptbuf) { |
1512 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1513 | 0 | goto err; |
1514 | 0 | } |
1515 | | |
1516 | | /* check if APDU is already encoded */ |
1517 | 0 | if ((from->cla & 0x0C) != 0) { |
1518 | 0 | memcpy(to, from, sizeof(sc_apdu_t)); |
1519 | 0 | res = SC_SUCCESS; /* already encoded */ |
1520 | 0 | goto encode_end; |
1521 | 0 | } |
1522 | 0 | if (from->ins == 0xC0) { |
1523 | 0 | memcpy(to, from, sizeof(sc_apdu_t)); |
1524 | 0 | res = SC_SUCCESS; /* dont encode GET Response cmd */ |
1525 | 0 | goto encode_end; |
1526 | 0 | } |
1527 | | |
1528 | | /* trace APDU before encoding process */ |
1529 | 0 | cwa_trace_apdu(card, from, 0); |
1530 | | |
1531 | | /* reserve enough space for apdulen+tlv bytes |
1532 | | * to-be-crypted buffer and result apdu buffer */ |
1533 | | /* TODO DEE add 4 more bytes for testing.... */ |
1534 | 0 | apdubuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen), |
1535 | 0 | sizeof(u8)); |
1536 | 0 | ccbuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen), |
1537 | 0 | sizeof(u8)); |
1538 | | /* always create a new buffer for the encoded response */ |
1539 | 0 | to->resp = calloc(MAX_RESP_BUFFER_SIZE, sizeof(u8)); |
1540 | 0 | to->resplen = MAX_RESP_BUFFER_SIZE; |
1541 | 0 | if (!apdubuf || !ccbuf || (!from->resp && !to->resp)) { |
1542 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1543 | 0 | goto err; |
1544 | 0 | } |
1545 | | |
1546 | | /* set up data on destination apdu */ |
1547 | 0 | to->cse = SC_APDU_CASE_4_SHORT; |
1548 | 0 | to->cla = from->cla | 0x0C; /* mark apdu as encoded */ |
1549 | 0 | to->ins = from->ins; |
1550 | 0 | to->p1 = from->p1; |
1551 | 0 | to->p2 = from->p2; |
1552 | 0 | to->le = from->le; |
1553 | 0 | if (!to->le) |
1554 | 0 | to->le = 255; |
1555 | 0 | to->lc = 0; /* to be evaluated */ |
1556 | | /* fill buffer with header info */ |
1557 | 0 | *(ccbuf + cclen++) = to->cla; |
1558 | 0 | *(ccbuf + cclen++) = to->ins; |
1559 | 0 | *(ccbuf + cclen++) = to->p1; |
1560 | 0 | *(ccbuf + cclen++) = to->p2; |
1561 | 0 | cwa_iso7816_padding(ccbuf, &cclen); /* pad header (4 bytes pad) */ |
1562 | |
|
1563 | 0 | if (!(cctx = EVP_CIPHER_CTX_new())) { |
1564 | 0 | res = SC_ERROR_INTERNAL; |
1565 | 0 | goto err; |
1566 | 0 | } |
1567 | | |
1568 | | /* if no data, skip data encryption step */ |
1569 | 0 | if (from->lc != 0) { |
1570 | 0 | unsigned char iv[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
1571 | 0 | int dlen = (int)from->lc; |
1572 | 0 | size_t len = dlen; |
1573 | | |
1574 | | /* pad message */ |
1575 | 0 | memcpy(msgbuf, from->data, dlen); |
1576 | 0 | cwa_iso7816_padding(msgbuf, &len); |
1577 | 0 | dlen = (int)len; |
1578 | | |
1579 | | /* start kriptbuff with iso padding indicator */ |
1580 | 0 | *cryptbuf = 0x01; |
1581 | 0 | key = sm_session->session_enc; |
1582 | |
|
1583 | 0 | alg = sc_evp_cipher(card->ctx, "DES-EDE-CBC"); |
1584 | |
|
1585 | 0 | if (!alg || |
1586 | 0 | EVP_EncryptInit_ex(cctx, alg, NULL, key, iv) != 1 || |
1587 | 0 | EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 || |
1588 | 0 | EVP_EncryptUpdate(cctx, cryptbuf + 1, &dlen, msgbuf, dlen) != 1 || |
1589 | 0 | EVP_EncryptFinal_ex(cctx, cryptbuf + 1 + dlen, &tmplen) != 1) { |
1590 | 0 | msg = "Error in encrypting APDU"; |
1591 | 0 | res = SC_ERROR_INTERNAL; |
1592 | 0 | goto encode_end; |
1593 | 0 | } |
1594 | 0 | dlen += tmplen; |
1595 | | |
1596 | | /* compose data TLV and add to result buffer */ |
1597 | 0 | res = cwa_compose_tlv(card, 0x87, dlen + 1, cryptbuf, &ccbuf, &cclen); |
1598 | 0 | if (res != SC_SUCCESS) { |
1599 | 0 | msg = "Error in compose tag 8x87 TLV"; |
1600 | 0 | goto encode_end; |
1601 | 0 | } |
1602 | 0 | } else if ((0xff & from->le) > 0) { |
1603 | | /* if le byte is declared, compose and add Le TLV */ |
1604 | | /* FIXME: For DNIe we must not send the le bytes |
1605 | | when le == 256 but this goes against the standard |
1606 | | and might break other cards reusing this code */ |
1607 | | /* NOTE: In FNMT MultiPKCS11 code this is an if, i.e., |
1608 | | the le is only sent if no data (lc) is set. |
1609 | | In DNIe 3.0 pin verification sending both TLV return |
1610 | | 69 88 "SM Data Object incorrect". For the moment it is |
1611 | | fixed sendind le=0 in pin verification apdu */ |
1612 | 0 | u8 le = 0xff & from->le; |
1613 | 0 | res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen); |
1614 | 0 | if (res != SC_SUCCESS) { |
1615 | 0 | msg = "Encode APDU compose_tlv(0x97) failed"; |
1616 | 0 | goto encode_end; |
1617 | 0 | } |
1618 | 0 | } |
1619 | | /* copy current data to apdu buffer (skip header and header padding) */ |
1620 | 0 | if (cclen < 8) { |
1621 | 0 | res = SC_ERROR_INTERNAL; |
1622 | 0 | msg = "Incorrect checksum length"; |
1623 | 0 | goto encode_end; |
1624 | 0 | } |
1625 | 0 | memcpy(apdubuf, ccbuf + 8, cclen - 8); |
1626 | 0 | apdulen = cclen - 8; |
1627 | | /* pad again ccbuffer to compute CC */ |
1628 | 0 | cwa_iso7816_padding(ccbuf, &cclen); |
1629 | | |
1630 | | /* sc_log(ctx,"data to compose mac: %s",sc_dump_hex(ccbuf,cclen)); */ |
1631 | | /* compute MAC Cryptographic Checksum using kmac and increased SSC */ |
1632 | 0 | res = cwa_increase_ssc(card); /* increase send sequence counter */ |
1633 | 0 | if (res != SC_SUCCESS) { |
1634 | 0 | msg = "Error in computing SSC"; |
1635 | 0 | goto encode_end; |
1636 | 0 | } |
1637 | | |
1638 | 0 | memcpy(macbuf, sm_session->ssc, 8); /* start with computed SSC */ |
1639 | |
|
1640 | 0 | tmplen = 0; |
1641 | 0 | key = sm_session->session_mac; |
1642 | |
|
1643 | 0 | sc_evp_cipher_free(alg); |
1644 | 0 | alg = sc_evp_cipher(card->ctx, "DES-ECB"); |
1645 | 0 | if (!alg || |
1646 | 0 | EVP_EncryptInit_ex(cctx, alg, NULL, key, NULL) != 1 || |
1647 | 0 | EVP_CIPHER_CTX_set_padding(cctx, 0) != 1) { |
1648 | 0 | msg = "Error in DES ECB encryption"; |
1649 | 0 | res = SC_ERROR_INTERNAL; |
1650 | 0 | goto encode_end; |
1651 | 0 | } |
1652 | | |
1653 | 0 | for (i = 0; i < cclen; i += 8) { /* divide data in 8 byte blocks */ |
1654 | | /* compute DES */ |
1655 | 0 | if (EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf , 8) != 1) { |
1656 | 0 | msg = "Error in DES ECB encryption"; |
1657 | 0 | res = SC_ERROR_INTERNAL; |
1658 | 0 | goto encode_end; |
1659 | 0 | } |
1660 | | /* XOR with next data and repeat */ |
1661 | 0 | for (j = 0; j < 8; j++) |
1662 | 0 | macbuf[j] ^= ccbuf[i + j]; |
1663 | 0 | } |
1664 | 0 | if (EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) { |
1665 | 0 | msg = "Error in DES ECB encryption"; |
1666 | 0 | res = SC_ERROR_INTERNAL; |
1667 | 0 | goto encode_end; |
1668 | 0 | } |
1669 | | |
1670 | | /* and apply 3DES to result */ |
1671 | 0 | sc_evp_cipher_free(alg); |
1672 | 0 | alg = sc_evp_cipher(card->ctx, "DES-EDE-ECB"); |
1673 | |
|
1674 | 0 | if (!alg || |
1675 | 0 | EVP_EncryptInit_ex(cctx, alg, NULL, key, NULL) != 1 || |
1676 | 0 | EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 || |
1677 | 0 | EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf, 8) != 1 || |
1678 | 0 | EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) { |
1679 | 0 | msg = "Error in 3DEC ECB encryption"; |
1680 | 0 | res = SC_ERROR_INTERNAL; |
1681 | 0 | goto encode_end; |
1682 | 0 | } |
1683 | | |
1684 | | /* compose and add computed MAC TLV to result buffer */ |
1685 | 0 | tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4; |
1686 | 0 | sc_log(ctx, "Using TLV length: %"SC_FORMAT_LEN_SIZE_T"u", tlv_len); |
1687 | 0 | res = cwa_compose_tlv(card, 0x8E, tlv_len, macbuf, &apdubuf, &apdulen); |
1688 | 0 | if (res != SC_SUCCESS) { |
1689 | 0 | msg = "Encode APDU compose_tlv(0x87) failed"; |
1690 | 0 | goto encode_end; |
1691 | 0 | } |
1692 | | |
1693 | | /* rewrite resulting header */ |
1694 | 0 | to->lc = apdulen; |
1695 | 0 | to->data = apdubuf; |
1696 | 0 | to->datalen = apdulen; |
1697 | | |
1698 | | /* that's all folks */ |
1699 | 0 | res = SC_SUCCESS; |
1700 | 0 | goto encode_end_apdu_valid; |
1701 | | |
1702 | 0 | err: |
1703 | 0 | encode_end: |
1704 | 0 | free(apdubuf); |
1705 | 0 | if (from->resp != to->resp) |
1706 | 0 | free(to->resp); |
1707 | 0 | encode_end_apdu_valid: |
1708 | 0 | sc_evp_cipher_free(alg); |
1709 | 0 | EVP_CIPHER_CTX_free(cctx); |
1710 | 0 | if (msg) { |
1711 | 0 | sc_log_openssl(ctx); |
1712 | 0 | sc_log(ctx, "%s", msg); |
1713 | 0 | } |
1714 | 0 | free(msgbuf); |
1715 | 0 | free(cryptbuf); |
1716 | 0 | free(ccbuf); |
1717 | 0 | LOG_FUNC_RETURN(ctx, res); |
1718 | 0 | } |
1719 | | |
1720 | | /** |
1721 | | * Decode an APDU response. |
1722 | | * |
1723 | | * Calling this functions means that It's has been verified |
1724 | | * That apdu response comes in TLV encoded format and needs decoding |
1725 | | * Based on section 9 of CWA-14890 and Sect 6 of iso7816-4 standards |
1726 | | * And DNIe's manual |
1727 | | * |
1728 | | * @param card card info structure |
1729 | | * @param sm Secure Messaging state information |
1730 | | * @param from APDU with response to be decoded |
1731 | | * @param to where to store decoded apdu |
1732 | | * @return SC_SUCCESS if ok; else error code |
1733 | | */ |
1734 | | int cwa_decode_response(sc_card_t * card, |
1735 | | cwa_provider_t * provider, |
1736 | | sc_apdu_t * apdu) |
1737 | 0 | { |
1738 | 0 | size_t i, j, tlv_len; |
1739 | 0 | cwa_tlv_t tlv_array[4]; |
1740 | 0 | cwa_tlv_t *p_tlv = &tlv_array[0]; /* to store plain data (Tag 0x81) */ |
1741 | 0 | cwa_tlv_t *e_tlv = &tlv_array[1]; /* to store pad encoded data (Tag 0x87) */ |
1742 | 0 | cwa_tlv_t *m_tlv = &tlv_array[2]; /* to store mac CC (Tag 0x8E) */ |
1743 | 0 | cwa_tlv_t *s_tlv = &tlv_array[3]; /* to store sw1-sw2 status (Tag 0x99) */ |
1744 | 0 | u8 *buffer = NULL; /* buffer for data. pointers to this buffer are in tlv_array */ |
1745 | 0 | u8 *ccbuf = NULL; /* buffer for mac CC calculation */ |
1746 | 0 | size_t cclen = 0; /* ccbuf len */ |
1747 | 0 | u8 macbuf[8]; /* where to calculate mac */ |
1748 | 0 | size_t resplen = 0; /* respbuf length */ |
1749 | 0 | int res = SC_SUCCESS; |
1750 | 0 | char *msg = NULL; /* to store error messages */ |
1751 | 0 | sc_context_t *ctx = NULL; |
1752 | 0 | struct sm_cwa_session * sm_session = &card->sm_ctx.info.session.cwa; |
1753 | |
|
1754 | 0 | EVP_CIPHER_CTX *cctx = NULL; |
1755 | 0 | EVP_CIPHER *alg = NULL; |
1756 | 0 | unsigned char *key = NULL; |
1757 | 0 | int tmplen = 0; |
1758 | |
|
1759 | 0 | if ((cctx = EVP_CIPHER_CTX_new()) == NULL) { |
1760 | 0 | sc_log_openssl(ctx); |
1761 | 0 | return SC_ERROR_INTERNAL; |
1762 | 0 | } |
1763 | | |
1764 | | /* mandatory check */ |
1765 | 0 | if (!card || !card->ctx || !provider) |
1766 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1767 | 0 | ctx = card->ctx; |
1768 | |
|
1769 | 0 | LOG_FUNC_CALLED(ctx); |
1770 | | /* check remaining arguments */ |
1771 | 0 | if ((apdu == NULL) || (sm_session == NULL)) |
1772 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_INITIALIZED); |
1773 | 0 | if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) |
1774 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL); |
1775 | | |
1776 | | /* cwa14890 sect 9.3: check SW1 or SW2 for SM related errors */ |
1777 | 0 | if (apdu->sw1 == 0x69) { |
1778 | 0 | if ((apdu->sw2 == 0x88) || (apdu->sw2 == 0x87)) { |
1779 | | /* configure the driver to re-establish the SM */ |
1780 | 0 | msg = "SM related errors in APDU response"; |
1781 | 0 | cwa_create_secure_channel(card, provider, CWA_SM_OFF); |
1782 | 0 | res = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; |
1783 | 0 | goto response_decode_end; |
1784 | 0 | } |
1785 | 0 | } |
1786 | | /* if response is null/empty assume unencoded apdu */ |
1787 | 0 | if (!apdu->resp || (apdu->resplen == 0)) { |
1788 | 0 | sc_log(ctx, "Empty APDU response: assume not cwa encoded"); |
1789 | 0 | return SC_SUCCESS; |
1790 | 0 | } |
1791 | | /* checks if apdu response needs decoding by checking tags in response */ |
1792 | 0 | switch (*apdu->resp) { |
1793 | 0 | case CWA_SM_PLAIN_TAG: |
1794 | 0 | case CWA_SM_CRYPTO_TAG: |
1795 | 0 | case CWA_SM_MAC_TAG: |
1796 | 0 | case CWA_SM_LE_TAG: |
1797 | 0 | case CWA_SM_STATUS_TAG: |
1798 | 0 | break; /* cwa tags found: continue decoding */ |
1799 | 0 | default: /* else apdu response seems not to be cwa encoded */ |
1800 | 0 | sc_log(card->ctx, "APDU Response seems not to be cwa encoded"); |
1801 | 0 | return SC_SUCCESS; /* let process continue */ |
1802 | 0 | } |
1803 | | |
1804 | | /* parse response to find TLV's data and check results */ |
1805 | 0 | memset(tlv_array, 0, 4 * sizeof(cwa_tlv_t)); |
1806 | | /* create buffer and copy data into */ |
1807 | 0 | buffer = calloc(apdu->resplen, sizeof(u8)); |
1808 | 0 | if (!buffer) { |
1809 | 0 | msg = "Cannot allocate space for response buffer"; |
1810 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1811 | 0 | goto response_decode_end; |
1812 | 0 | } |
1813 | 0 | memcpy(buffer, apdu->resp, apdu->resplen); |
1814 | |
|
1815 | 0 | res = cwa_parse_tlv(card, buffer, apdu->resplen, tlv_array); |
1816 | 0 | if (res != SC_SUCCESS) { |
1817 | 0 | msg = "Error in TLV parsing"; |
1818 | 0 | goto response_decode_end; |
1819 | 0 | } |
1820 | | |
1821 | | /* check consistency of received TLV's */ |
1822 | 0 | if (p_tlv->buf && e_tlv->buf) { |
1823 | 0 | msg = |
1824 | 0 | "Plain and Encoded data are mutually exclusive in apdu response"; |
1825 | 0 | res = SC_ERROR_INVALID_DATA; |
1826 | 0 | goto response_decode_end; |
1827 | 0 | } |
1828 | 0 | if (!m_tlv->buf) { |
1829 | 0 | msg = "No MAC TAG found in apdu response"; |
1830 | 0 | res = SC_ERROR_INVALID_DATA; |
1831 | 0 | goto response_decode_end; |
1832 | 0 | } |
1833 | 0 | tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4; |
1834 | 0 | if (m_tlv->len != tlv_len) { |
1835 | 0 | msg = "Invalid MAC TAG Length"; |
1836 | 0 | res = SC_ERROR_INVALID_DATA; |
1837 | 0 | goto response_decode_end; |
1838 | 0 | } |
1839 | | |
1840 | | /* compose buffer to evaluate mac */ |
1841 | | |
1842 | | /* reserve enough space for data+status+padding */ |
1843 | 0 | ccbuf = |
1844 | 0 | calloc(e_tlv->buflen + s_tlv->buflen + p_tlv->buflen + 8, |
1845 | 0 | sizeof(u8)); |
1846 | 0 | if (!ccbuf) { |
1847 | 0 | msg = "Cannot allocate space for mac checking"; |
1848 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
1849 | 0 | goto response_decode_end; |
1850 | 0 | } |
1851 | | /* copy data into buffer */ |
1852 | 0 | cclen = 0; |
1853 | 0 | if (e_tlv->buf) { /* encoded data */ |
1854 | 0 | memcpy(ccbuf, e_tlv->buf, e_tlv->buflen); |
1855 | 0 | cclen = e_tlv->buflen; |
1856 | 0 | } |
1857 | 0 | if (p_tlv->buf) { /* plain data */ |
1858 | 0 | memcpy(ccbuf, p_tlv->buf, p_tlv->buflen); |
1859 | 0 | cclen += p_tlv->buflen; |
1860 | 0 | } |
1861 | 0 | if (s_tlv->buf) { /* response status */ |
1862 | 0 | if (s_tlv->len != 2) { |
1863 | 0 | msg = "Invalid SW TAG length"; |
1864 | 0 | res = SC_ERROR_INVALID_DATA; |
1865 | 0 | goto response_decode_end; |
1866 | 0 | } |
1867 | 0 | memcpy(ccbuf + cclen, s_tlv->buf, s_tlv->buflen); |
1868 | 0 | cclen += s_tlv->buflen; |
1869 | 0 | apdu->sw1 = s_tlv->data[0]; |
1870 | 0 | apdu->sw2 = s_tlv->data[1]; |
1871 | 0 | } /* if no response status tag, use sw1 and sw2 from apdu */ |
1872 | | /* add iso7816 padding */ |
1873 | 0 | cwa_iso7816_padding(ccbuf, &cclen); |
1874 | | |
1875 | | /* evaluate mac by mean of kmac and increased SendSequence Counter SSC */ |
1876 | | |
1877 | | /* increase SSC */ |
1878 | 0 | res = cwa_increase_ssc(card); /* increase send sequence counter */ |
1879 | 0 | if (res != SC_SUCCESS) { |
1880 | 0 | msg = "Error in computing SSC"; |
1881 | 0 | goto response_decode_end; |
1882 | 0 | } |
1883 | | /* set up key for mac computing */ |
1884 | 0 | key = sm_session->session_mac; |
1885 | |
|
1886 | 0 | alg = sc_evp_cipher(card->ctx, "DES-ECB"); |
1887 | 0 | if (!alg || |
1888 | 0 | EVP_EncryptInit_ex(cctx, alg, NULL, key, NULL) != 1 || |
1889 | 0 | EVP_CIPHER_CTX_set_padding(cctx, 0) != 1) { |
1890 | 0 | sc_log_openssl(ctx); |
1891 | 0 | msg = "Error in DES ECB encryption"; |
1892 | 0 | res = SC_ERROR_INTERNAL; |
1893 | 0 | goto response_decode_end; |
1894 | 0 | } |
1895 | | |
1896 | 0 | memcpy(macbuf, sm_session->ssc, 8); /* start with computed SSC */ |
1897 | 0 | for (i = 0; i < cclen; i += 8) { /* divide data in 8 byte blocks */ |
1898 | | /* compute DES */ |
1899 | 0 | if (EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf, 8) != 1) { |
1900 | 0 | sc_log_openssl(ctx); |
1901 | 0 | msg = "Error in DES ECB encryption"; |
1902 | 0 | res = SC_ERROR_INTERNAL; |
1903 | 0 | goto response_decode_end; |
1904 | 0 | } |
1905 | | /* XOR with data and repeat */ |
1906 | 0 | for (j = 0; j < 8; j++) |
1907 | 0 | macbuf[j] ^= ccbuf[i + j]; |
1908 | 0 | } |
1909 | 0 | if (EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) { |
1910 | 0 | sc_log_openssl(ctx); |
1911 | 0 | msg = "Error in DES ECB encryption"; |
1912 | 0 | res = SC_ERROR_INTERNAL; |
1913 | 0 | goto response_decode_end; |
1914 | 0 | } |
1915 | | |
1916 | | /* finally apply 3DES to result */ |
1917 | 0 | sc_evp_cipher_free(alg); |
1918 | 0 | alg = sc_evp_cipher(card->ctx, "DES-EDE-ECB"); |
1919 | |
|
1920 | 0 | if (!alg || |
1921 | 0 | EVP_EncryptInit_ex(cctx, alg, NULL, key, NULL) != 1 || |
1922 | 0 | EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 || |
1923 | 0 | EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf, 8) != 1 || |
1924 | 0 | EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) { |
1925 | 0 | sc_log_openssl(ctx); |
1926 | 0 | msg = "Error in 3DEC ECB encryption"; |
1927 | 0 | res = SC_ERROR_INTERNAL; |
1928 | 0 | goto response_decode_end; |
1929 | 0 | } |
1930 | | |
1931 | | /* check evaluated mac with provided by apdu response */ |
1932 | | |
1933 | 0 | res = memcmp(m_tlv->data, macbuf, 4); /* check first 4 bytes */ |
1934 | 0 | if (res != 0) { |
1935 | 0 | msg = "Error in MAC CC checking: value doesn't match"; |
1936 | 0 | res = SC_ERROR_SM_ENCRYPT_FAILED; |
1937 | 0 | goto response_decode_end; |
1938 | 0 | } |
1939 | | |
1940 | | /* allocate response buffer */ |
1941 | 0 | resplen = 10 + MAX(p_tlv->len, e_tlv->len); /* estimate response buflen */ |
1942 | 0 | if (apdu->resplen < resplen) { |
1943 | 0 | msg = "Cannot allocate buffer to store response"; |
1944 | 0 | res = SC_ERROR_BUFFER_TOO_SMALL; |
1945 | 0 | goto response_decode_end; |
1946 | 0 | } |
1947 | 0 | apdu->resplen = resplen; |
1948 | | |
1949 | | /* fill destination response apdu buffer with data */ |
1950 | | |
1951 | | /* if plain data, just copy TLV data into apdu response */ |
1952 | 0 | if (p_tlv->buf) { /* plain data */ |
1953 | 0 | memcpy(apdu->resp, p_tlv->data, p_tlv->len); |
1954 | 0 | apdu->resplen = p_tlv->len; |
1955 | 0 | } |
1956 | | |
1957 | | /* if encoded data, decode and store into apdu response */ |
1958 | 0 | else if (e_tlv->buf) { /* encoded data */ |
1959 | 0 | unsigned char iv[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
1960 | 0 | int dlen = (int)apdu->resplen; |
1961 | | /* check data len */ |
1962 | 0 | if ((e_tlv->len < 9) || ((e_tlv->len - 1) % 8) != 0) { |
1963 | 0 | msg = "Invalid length for Encoded data TLV"; |
1964 | 0 | res = SC_ERROR_INVALID_DATA; |
1965 | 0 | goto response_decode_end; |
1966 | 0 | } |
1967 | | /* first byte is padding info; check value */ |
1968 | 0 | if (e_tlv->data[0] != 0x01) { |
1969 | 0 | msg = "Encoded TLV: Invalid padding info value"; |
1970 | 0 | res = SC_ERROR_INVALID_DATA; |
1971 | 0 | goto response_decode_end; |
1972 | 0 | } |
1973 | | /* prepare keys to decode */ |
1974 | 0 | key = sm_session->session_enc; |
1975 | | |
1976 | | /* decrypt into response buffer |
1977 | | * by using 3DES CBC by mean of kenc and iv={0,...0} */ |
1978 | 0 | sc_evp_cipher_free(alg); |
1979 | 0 | alg = sc_evp_cipher(card->ctx, "DES-EDE-CBC"); |
1980 | |
|
1981 | 0 | if (!alg || |
1982 | 0 | EVP_DecryptInit_ex(cctx, alg, NULL, key, iv) != 1 || |
1983 | 0 | EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 || |
1984 | 0 | EVP_DecryptUpdate(cctx, apdu->resp, &dlen, &e_tlv->data[1], (int)(e_tlv->len - 1)) != 1 || |
1985 | 0 | EVP_DecryptFinal_ex(cctx, apdu->resp + dlen, &tmplen) != 1) { |
1986 | 0 | sc_log_openssl(ctx); |
1987 | 0 | res = SC_ERROR_INTERNAL; |
1988 | 0 | msg = "Can not decrypt 3DES CBC"; |
1989 | 0 | goto response_decode_end; |
1990 | 0 | } |
1991 | 0 | apdu->resplen = dlen + tmplen; |
1992 | | |
1993 | | /* remove iso padding from response length */ |
1994 | 0 | for (; (apdu->resplen > 0) && *(apdu->resp + apdu->resplen - 1) == 0x00; apdu->resplen--) ; /* empty loop */ |
1995 | |
|
1996 | 0 | if (*(apdu->resp + apdu->resplen - 1) != 0x80) { /* check padding byte */ |
1997 | 0 | msg = "Decrypted TLV has no 0x80 iso padding indicator!"; |
1998 | 0 | res = SC_ERROR_INVALID_DATA; |
1999 | 0 | goto response_decode_end; |
2000 | 0 | } |
2001 | | /* everything ok: remove ending 0x80 from response */ |
2002 | 0 | apdu->resplen--; |
2003 | 0 | } |
2004 | | |
2005 | 0 | else |
2006 | 0 | apdu->resplen = 0; /* neither plain, nor encoded data */ |
2007 | | |
2008 | | /* that's all folks */ |
2009 | 0 | res = SC_SUCCESS; |
2010 | |
|
2011 | 0 | response_decode_end: |
2012 | 0 | sc_evp_cipher_free(alg); |
2013 | 0 | EVP_CIPHER_CTX_free(cctx); |
2014 | 0 | free(buffer); |
2015 | 0 | free(ccbuf); |
2016 | 0 | if (msg) { |
2017 | 0 | sc_log(ctx, "%s", msg); |
2018 | 0 | } else { |
2019 | 0 | cwa_trace_apdu(card, apdu, 1); |
2020 | 0 | } /* trace apdu response */ |
2021 | 0 | LOG_FUNC_RETURN(ctx, res); |
2022 | 0 | } |
2023 | | |
2024 | | /********************* default provider for cwa14890 ****************/ |
2025 | | |
2026 | | /* pre and post operations */ |
2027 | | |
2028 | | static int default_create_pre_ops(sc_card_t * card, cwa_provider_t * provider) |
2029 | 0 | { |
2030 | 0 | return SC_SUCCESS; |
2031 | 0 | } |
2032 | | |
2033 | | static int default_create_post_ops(sc_card_t * card, cwa_provider_t * provider) |
2034 | 0 | { |
2035 | 0 | return SC_SUCCESS; |
2036 | 0 | } |
2037 | | |
2038 | | static int default_get_root_ca_pubkey(sc_card_t * card, EVP_PKEY ** root_ca_key) |
2039 | 0 | { |
2040 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2041 | 0 | } |
2042 | | |
2043 | | /* retrieve CVC intermediate CA certificate and length */ |
2044 | | static int default_get_cvc_ca_cert(sc_card_t * card, u8 ** cert, |
2045 | | size_t * length) |
2046 | 0 | { |
2047 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2048 | 0 | } |
2049 | | |
2050 | | /* retrieve CVC IFD certificate and length */ |
2051 | | static int default_get_cvc_ifd_cert(sc_card_t * card, u8 ** cert, |
2052 | | size_t * length) |
2053 | 0 | { |
2054 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2055 | 0 | } |
2056 | | |
2057 | | static int default_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey) |
2058 | 0 | { |
2059 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2060 | 0 | } |
2061 | | |
2062 | | /* get ICC intermediate CA path */ |
2063 | | static int default_get_icc_intermediate_ca_cert(sc_card_t * card, X509 ** cert) |
2064 | 0 | { |
2065 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2066 | 0 | } |
2067 | | |
2068 | | /* get ICC certificate path */ |
2069 | | static int default_get_icc_cert(sc_card_t * card, X509 ** cert) |
2070 | 0 | { |
2071 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2072 | 0 | } |
2073 | | |
2074 | | /* Retrieve key reference for Root CA to validate CVC intermediate CA certs */ |
2075 | | static int default_get_root_ca_pubkey_ref(sc_card_t * card, u8 ** buf, |
2076 | | size_t * len) |
2077 | 0 | { |
2078 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2079 | 0 | } |
2080 | | |
2081 | | /* Retrieve key reference for intermediate CA to validate IFD certs */ |
2082 | | static int default_get_intermediate_ca_pubkey_ref(sc_card_t * card, u8 ** buf, |
2083 | | size_t * len) |
2084 | 0 | { |
2085 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2086 | 0 | } |
2087 | | |
2088 | | /* Retrieve key reference for IFD certificate */ |
2089 | | static int default_get_ifd_pubkey_ref(sc_card_t * card, u8 ** buf, size_t * len) |
2090 | 0 | { |
2091 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2092 | 0 | } |
2093 | | |
2094 | | /* Retrieve key reference for ICC privkey */ |
2095 | | static int default_get_icc_privkey_ref(sc_card_t * card, u8 ** buf, |
2096 | | size_t * len) |
2097 | 0 | { |
2098 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2099 | 0 | } |
2100 | | |
2101 | | /* Retrieve SN.IFD (8 bytes left padded with zeroes if needed) */ |
2102 | | static int default_get_sn_ifd(sc_card_t * card) |
2103 | 0 | { |
2104 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2105 | 0 | } |
2106 | | |
2107 | | /* Retrieve SN.ICC (8 bytes left padded with zeroes if needed) */ |
2108 | | static int default_get_sn_icc(sc_card_t * card) |
2109 | 0 | { |
2110 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2111 | 0 | } |
2112 | | |
2113 | | static cwa_provider_t default_cwa_provider = { |
2114 | | |
2115 | | /************ data related with SM operations *************************/ |
2116 | | |
2117 | | /************ operations related with secure channel creation *********/ |
2118 | | |
2119 | | /* pre and post operations */ |
2120 | | default_create_pre_ops, |
2121 | | default_create_post_ops, |
2122 | | |
2123 | | /* Get ICC intermediate CA path */ |
2124 | | default_get_icc_intermediate_ca_cert, |
2125 | | /* Get ICC certificate path */ |
2126 | | default_get_icc_cert, |
2127 | | |
2128 | | /* Obtain RSA public key from RootCA */ |
2129 | | default_get_root_ca_pubkey, |
2130 | | /* Obtain RSA IFD private key */ |
2131 | | default_get_ifd_privkey, |
2132 | | |
2133 | | /* Retrieve CVC intermediate CA certificate and length */ |
2134 | | default_get_cvc_ca_cert, |
2135 | | /* Retrieve CVC IFD certificate and length */ |
2136 | | default_get_cvc_ifd_cert, |
2137 | | |
2138 | | /* Get public key references for Root CA to validate intermediate CA cert */ |
2139 | | default_get_root_ca_pubkey_ref, |
2140 | | |
2141 | | /* Get public key reference for IFD intermediate CA certificate */ |
2142 | | default_get_intermediate_ca_pubkey_ref, |
2143 | | |
2144 | | /* Get public key reference for IFD CVC certificate */ |
2145 | | default_get_ifd_pubkey_ref, |
2146 | | |
2147 | | /* Get ICC private key reference */ |
2148 | | default_get_icc_privkey_ref, |
2149 | | |
2150 | | /* Get IFD Serial Number */ |
2151 | | default_get_sn_ifd, |
2152 | | |
2153 | | /* Get ICC Serial Number */ |
2154 | | default_get_sn_icc, |
2155 | | |
2156 | | |
2157 | | }; |
2158 | | |
2159 | | /** |
2160 | | * Get a copy of default cwa provider. |
2161 | | * |
2162 | | * @param card pointer to card info structure |
2163 | | * @return copy of default provider or null on error |
2164 | | */ |
2165 | | cwa_provider_t *cwa_get_default_provider(sc_card_t * card) |
2166 | 0 | { |
2167 | 0 | cwa_provider_t *res = NULL; |
2168 | 0 | if (!card || !card->ctx) |
2169 | 0 | return NULL; |
2170 | 0 | LOG_FUNC_CALLED(card->ctx); |
2171 | 0 | res = calloc(1, sizeof(cwa_provider_t)); |
2172 | 0 | if (!res) { |
2173 | 0 | sc_log(card->ctx, "Cannot allocate space for cwa_provider"); |
2174 | 0 | return NULL; |
2175 | 0 | } |
2176 | 0 | memcpy(res, &default_cwa_provider, sizeof(cwa_provider_t)); |
2177 | 0 | return res; |
2178 | 0 | } |
2179 | | |
2180 | | /* end of cwa14890.c */ |
2181 | | #undef __CWA14890_C__ |
2182 | | |
2183 | | #endif /* ENABLE_OPENSSL */ |