/src/opensc/openpace/src/eac_asn1.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2010-2012 Dominik Oepen and Frank Morgner |
3 | | * |
4 | | * This file is part of OpenPACE. |
5 | | * |
6 | | * OpenPACE is free software: you can redistribute it and/or modify it under |
7 | | * the terms of the GNU General Public License as published by the Free |
8 | | * Software Foundation, either version 3 of the License, or (at your option) |
9 | | * any later version. |
10 | | * |
11 | | * OpenPACE is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
13 | | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
14 | | * details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License along with |
17 | | * OpenPACE. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * Additional permission under GNU GPL version 3 section 7 |
20 | | * |
21 | | * If you modify this Program, or any covered work, by linking or combining it |
22 | | * with OpenSSL (or a modified version of that library), containing |
23 | | * parts covered by the terms of OpenSSL's license, the licensors of |
24 | | * this Program grant you additional permission to convey the resulting work. |
25 | | * Corresponding Source for a non-source form of such a combination shall include |
26 | | * the source code for the parts of OpenSSL used as well as that of the |
27 | | * covered work. |
28 | | * |
29 | | * If you modify this Program, or any covered work, by linking or combining it |
30 | | * with OpenSC (or a modified version of that library), containing |
31 | | * parts covered by the terms of OpenSC's license, the licensors of |
32 | | * this Program grant you additional permission to convey the resulting work. |
33 | | * Corresponding Source for a non-source form of such a combination shall include |
34 | | * the source code for the parts of OpenSC used as well as that of the |
35 | | * covered work. |
36 | | */ |
37 | | |
38 | | /** |
39 | | * @file eac_asn1.c |
40 | | * @brief ASN.1 structures related to PACE |
41 | | * |
42 | | * @author Dominik Oepen <oepen@informatik.hu-berlin.de> |
43 | | * @author Frank Morgner <frankmorgner@gmail.com> |
44 | | */ |
45 | | |
46 | | #ifdef HAVE_CONFIG_H |
47 | | #include "config.h" |
48 | | #endif |
49 | | |
50 | | #include "ca_lib.h" |
51 | | #include "eac_asn1.h" |
52 | | #include "eac_dh.h" |
53 | | #include "eac_err.h" |
54 | | #include "eac_util.h" |
55 | | #include "misc.h" |
56 | | #include "pace_lib.h" |
57 | | #include <eac/eac.h> |
58 | | #include <eac/pace.h> |
59 | | #include <eac/ri.h> |
60 | | #include <openssl/asn1.h> |
61 | | #include <openssl/dh.h> |
62 | | #include <openssl/ec.h> |
63 | | #include <openssl/objects.h> |
64 | | #include <openssl/obj_mac.h> |
65 | | |
66 | | /** PACEInfo structure */ |
67 | | typedef struct pace_info_st { |
68 | | /** OID of the algorithm to be used */ |
69 | | ASN1_OBJECT *protocol; |
70 | | /** Protocol Version number. Version number 1 is deprecated, version 2 is |
71 | | recommended */ |
72 | | ASN1_INTEGER *version; |
73 | | /** Indicates the domain parameter identifier. named parameterID in BSI TR-03110 */ |
74 | | ASN1_INTEGER *keyID; |
75 | | } PACE_INFO; |
76 | | |
77 | | /** Algorithm Identifier structure */ |
78 | | typedef struct algorithm_identifier_st { |
79 | | /** OID of the algorithm */ |
80 | | ASN1_OBJECT *algorithm; |
81 | | ASN1_TYPE *parameters; |
82 | | } ALGORITHM_IDENTIFIER; |
83 | | |
84 | | /** Subject Public Key Info structure */ |
85 | | typedef struct subject_public_key_info_st { |
86 | | ALGORITHM_IDENTIFIER *algorithmIdentifier; |
87 | | ASN1_BIT_STRING *subjectPublicKey; |
88 | | } SUBJECT_PUBLIC_KEY_INFO; |
89 | | |
90 | | /** Domain parameter structure */ |
91 | | typedef struct pace_dp_info_st { |
92 | | /** OID of the type of domain parameters*/ |
93 | | ASN1_OBJECT *protocol; |
94 | | /** The actual domain parameters */ |
95 | | ALGORITHM_IDENTIFIER *aid; |
96 | | /** Optional: specifies the local domain parameters if multiple sets of domain |
97 | | parameters are provided. named parameterID in BSI TR-03110 */ |
98 | | ASN1_INTEGER *keyID; |
99 | | } PACE_DP_INFO; |
100 | | |
101 | | /** ChipAuthenticationInfo structure */ |
102 | | typedef struct ca_info_st { |
103 | | /** OID */ |
104 | | ASN1_OBJECT *protocol; |
105 | | /** Protocol Version number. Currently Version 1 and Version 2 are supported */ |
106 | | ASN1_INTEGER *version; |
107 | | /** keyID MAY be used to indicate the local key identifier */ |
108 | | ASN1_INTEGER *keyID; |
109 | | } CA_INFO; |
110 | | |
111 | | /** CA Domain parameter structure */ |
112 | | typedef struct ca_dp_info_st { |
113 | | /** OID of the type of domain parameters*/ |
114 | | ASN1_OBJECT *protocol; |
115 | | /** The actual domain parameters */ |
116 | | ALGORITHM_IDENTIFIER *aid; |
117 | | /** Optional: specifies the local domain parameters if multiple sets of domain |
118 | | parameters are provided */ |
119 | | ASN1_INTEGER *keyID; |
120 | | } CA_DP_INFO; |
121 | | |
122 | | /** CA public key info */ |
123 | | typedef struct ca_public_key_info_st { |
124 | | /** OID of the type of domain parameters*/ |
125 | | ASN1_OBJECT *protocol; |
126 | | /** The actual public key */ |
127 | | SUBJECT_PUBLIC_KEY_INFO *chipAuthenticationPublicKeyInfo; |
128 | | /** Optional: specifies the local domain parameters if multiple sets of domain |
129 | | parameters are provided */ |
130 | | ASN1_INTEGER *keyID; |
131 | | } CA_PUBLIC_KEY_INFO; |
132 | | |
133 | | /** File ID */ |
134 | | typedef struct file_id_st { |
135 | | /** File identifier */ |
136 | | ASN1_OCTET_STRING *fid; |
137 | | /** Short file ifentifier */ |
138 | | ASN1_OCTET_STRING *sfid; |
139 | | } FILE_ID; |
140 | | |
141 | | /** TerminalAuthenticationInfo */ |
142 | | typedef struct ta_info_st { |
143 | | /** OID */ |
144 | | ASN1_OBJECT *protocol; |
145 | | /** Protocol Version number. Currently Version 1 and Version 2 are supported */ |
146 | | ASN1_INTEGER *version; |
147 | | /** FileIdentifier of EF.CVCA */ |
148 | | FILE_ID *efCVCA; |
149 | | } TA_INFO; |
150 | | |
151 | | /** ProtocolParams */ |
152 | | typedef struct protocol_params_st { |
153 | | /* Protocol version. Currently only version 1 is supported */ |
154 | | ASN1_INTEGER *version; |
155 | | /** keyID identifies the private key that shall be used */ |
156 | | ASN1_INTEGER *keyID; |
157 | | /** Indicates whether explicit authorization is required to use the |
158 | | * corresponding secret key */ |
159 | | ASN1_BOOLEAN *authorizedOnly; |
160 | | } PROTOCOL_PARAMS; |
161 | | |
162 | | /** Restricted Authentication Info*/ |
163 | | typedef struct ri_info_st { |
164 | | /** OID */ |
165 | | ASN1_OBJECT *protocol; |
166 | | /** Protocol parameters */ |
167 | | PROTOCOL_PARAMS *params; |
168 | | /** indicates the maximum length of the supported sector |
169 | | * specific public keys */ |
170 | | ASN1_INTEGER *maxKeyLen; |
171 | | } RI_INFO; |
172 | | |
173 | | /** RI domain parameter info */ |
174 | | typedef struct ri_dp_info_st { |
175 | | /** OID of the type of domain parameters*/ |
176 | | ASN1_OBJECT *protocol; |
177 | | /** The actual domain parameters */ |
178 | | ALGORITHM_IDENTIFIER *aid; |
179 | | } RI_DP_INFO; |
180 | | |
181 | | /** Card Info Locator */ |
182 | | typedef struct card_info_locator_st { |
183 | | /** OID */ |
184 | | ASN1_OBJECT *protocol; |
185 | | ASN1_IA5STRING *url; |
186 | | FILE_ID *efCardInfo; |
187 | | } CARD_INFO_LOCATOR; |
188 | | |
189 | | ASN1_SEQUENCE(PACE_INFO) = { |
190 | | ASN1_SIMPLE(PACE_INFO, protocol, ASN1_OBJECT), |
191 | | ASN1_SIMPLE(PACE_INFO, version, ASN1_INTEGER), |
192 | | ASN1_OPT(PACE_INFO, keyID, ASN1_INTEGER) |
193 | | } ASN1_SEQUENCE_END(PACE_INFO) |
194 | | |
195 | | IMPLEMENT_ASN1_FUNCTIONS(PACE_INFO) |
196 | | |
197 | | ASN1_SEQUENCE(ALGORITHM_IDENTIFIER) = { |
198 | | ASN1_SIMPLE(ALGORITHM_IDENTIFIER, algorithm, ASN1_OBJECT), |
199 | | ASN1_SIMPLE(ALGORITHM_IDENTIFIER, parameters, ASN1_ANY) |
200 | | } ASN1_SEQUENCE_END(ALGORITHM_IDENTIFIER) |
201 | | |
202 | | ASN1_SEQUENCE(SUBJECT_PUBLIC_KEY_INFO) = { |
203 | | ASN1_SIMPLE(SUBJECT_PUBLIC_KEY_INFO, algorithmIdentifier, ALGORITHM_IDENTIFIER), |
204 | | ASN1_SIMPLE(SUBJECT_PUBLIC_KEY_INFO, subjectPublicKey, ASN1_BIT_STRING) |
205 | | } ASN1_SEQUENCE_END(SUBJECT_PUBLIC_KEY_INFO) |
206 | | |
207 | | /* PACEDomainParameterInfo */ |
208 | | ASN1_SEQUENCE(PACE_DP_INFO) = { |
209 | | ASN1_SIMPLE(PACE_DP_INFO, protocol, ASN1_OBJECT), |
210 | | ASN1_SIMPLE(PACE_DP_INFO, aid, ALGORITHM_IDENTIFIER), |
211 | | ASN1_OPT(PACE_DP_INFO, keyID, ASN1_INTEGER) |
212 | | } ASN1_SEQUENCE_END(PACE_DP_INFO) |
213 | | |
214 | | IMPLEMENT_ASN1_FUNCTIONS(PACE_DP_INFO) |
215 | | |
216 | | /* ChipAuthenticationInfo */ |
217 | | ASN1_SEQUENCE(CA_INFO) = { |
218 | | ASN1_SIMPLE(CA_INFO, protocol, ASN1_OBJECT), |
219 | | ASN1_SIMPLE(CA_INFO, version, ASN1_INTEGER), |
220 | | ASN1_OPT(CA_INFO, keyID, ASN1_INTEGER) |
221 | | } ASN1_SEQUENCE_END(CA_INFO) |
222 | | IMPLEMENT_ASN1_FUNCTIONS(CA_INFO) |
223 | | |
224 | | /* ChipAuthenticationDomainParameterInfo */ |
225 | | ASN1_SEQUENCE(CA_DP_INFO) = { |
226 | | ASN1_SIMPLE(CA_DP_INFO, protocol, ASN1_OBJECT), |
227 | | ASN1_SIMPLE(CA_DP_INFO, aid, ALGORITHM_IDENTIFIER), |
228 | | ASN1_OPT(CA_DP_INFO, keyID, ASN1_INTEGER) |
229 | | } ASN1_SEQUENCE_END(CA_DP_INFO) |
230 | | IMPLEMENT_ASN1_FUNCTIONS(CA_DP_INFO) |
231 | | |
232 | | /* ChipAuthenticationPublicKeyInfo */ |
233 | | ASN1_SEQUENCE(CA_PUBLIC_KEY_INFO) = { |
234 | | ASN1_SIMPLE(CA_PUBLIC_KEY_INFO, protocol, ASN1_OBJECT), |
235 | | ASN1_SIMPLE(CA_PUBLIC_KEY_INFO, chipAuthenticationPublicKeyInfo, SUBJECT_PUBLIC_KEY_INFO), |
236 | | ASN1_OPT(CA_PUBLIC_KEY_INFO, keyID, ASN1_INTEGER) |
237 | | } ASN1_SEQUENCE_END(CA_PUBLIC_KEY_INFO) |
238 | | IMPLEMENT_ASN1_FUNCTIONS(CA_PUBLIC_KEY_INFO) |
239 | | |
240 | | /* FileId */ |
241 | | ASN1_SEQUENCE(FILE_ID) = { |
242 | | ASN1_SIMPLE(FILE_ID, fid, ASN1_OCTET_STRING), |
243 | | ASN1_OPT(FILE_ID, sfid, ASN1_OCTET_STRING) |
244 | | } ASN1_SEQUENCE_END(FILE_ID) |
245 | | |
246 | | /* TerminalAuthenticationInfo */ |
247 | | ASN1_SEQUENCE(TA_INFO) = { |
248 | | ASN1_SIMPLE(TA_INFO, protocol, ASN1_OBJECT), |
249 | | ASN1_SIMPLE(TA_INFO, version, ASN1_INTEGER), |
250 | | ASN1_OPT(TA_INFO, efCVCA, FILE_ID) |
251 | | } ASN1_SEQUENCE_END(TA_INFO) |
252 | | IMPLEMENT_ASN1_FUNCTIONS(TA_INFO) |
253 | | |
254 | | /* ProtocolParams */ |
255 | | ASN1_SEQUENCE(PROTOCOL_PARAMS) = { |
256 | | ASN1_SIMPLE(PROTOCOL_PARAMS, version, ASN1_INTEGER), |
257 | | ASN1_SIMPLE(PROTOCOL_PARAMS, keyID, ASN1_INTEGER), |
258 | | ASN1_SIMPLE(PROTOCOL_PARAMS, authorizedOnly, ASN1_BOOLEAN) |
259 | | } ASN1_SEQUENCE_END(PROTOCOL_PARAMS) |
260 | | |
261 | | /* RestrictedIdentificationInfo */ |
262 | | ASN1_SEQUENCE(RI_INFO) = { |
263 | | ASN1_SIMPLE(RI_INFO, protocol, ASN1_OBJECT), |
264 | | ASN1_SIMPLE(RI_INFO, params, PROTOCOL_PARAMS), |
265 | | ASN1_OPT(RI_INFO, maxKeyLen, ASN1_INTEGER) |
266 | | } ASN1_SEQUENCE_END(RI_INFO) |
267 | | IMPLEMENT_ASN1_FUNCTIONS(RI_INFO) |
268 | | |
269 | | /* RestrictedIdentificationDomainParameterInfo */ |
270 | | ASN1_SEQUENCE(RI_DP_INFO) = { |
271 | | ASN1_SIMPLE(RI_DP_INFO, protocol, ASN1_OBJECT), |
272 | | ASN1_SIMPLE(RI_DP_INFO, aid, ALGORITHM_IDENTIFIER), |
273 | | } ASN1_SEQUENCE_END(RI_DP_INFO) |
274 | | IMPLEMENT_ASN1_FUNCTIONS(RI_DP_INFO) |
275 | | |
276 | | /* CardInfoLocator */ |
277 | | ASN1_SEQUENCE(CARD_INFO_LOCATOR) = { |
278 | | ASN1_SIMPLE(CARD_INFO_LOCATOR, protocol, ASN1_OBJECT), |
279 | | ASN1_SIMPLE(CARD_INFO_LOCATOR, url, ASN1_IA5STRING), |
280 | | ASN1_OPT(CARD_INFO_LOCATOR, efCardInfo, FILE_ID) |
281 | | } ASN1_SEQUENCE_END(CARD_INFO_LOCATOR) |
282 | | |
283 | | |
284 | | |
285 | | static EC_KEY * |
286 | | ecpkparameters2eckey(ASN1_TYPE *ec_params) |
287 | 0 | { |
288 | 0 | EC_GROUP *group = NULL; |
289 | 0 | EC_KEY *ec = NULL; |
290 | 0 | int length, fail = 1; |
291 | 0 | unsigned char *encoded = NULL; |
292 | 0 | const unsigned char *p; |
293 | |
|
294 | 0 | check(ec_params && ec_params->type == V_ASN1_SEQUENCE, |
295 | 0 | "Invalid arguments"); |
296 | | |
297 | | /* unfortunately we need to re-pack and re-parse the ECPKPARAMETERS, |
298 | | * because there is no official API for using it directly (see |
299 | | * openssl/crypto/ec/ec.h) */ |
300 | 0 | length = i2d_ASN1_TYPE(ec_params, &encoded); |
301 | 0 | p = encoded; |
302 | 0 | check(length > 0 && d2i_ECPKParameters(&group, &p, length), |
303 | 0 | "Could not decode EC parameters"); |
304 | |
|
305 | 0 | ec = EC_KEY_new(); |
306 | 0 | check(ec && EC_KEY_set_group(ec, group), |
307 | 0 | "Could not initialize key object"); |
308 | |
|
309 | 0 | fail = 0; |
310 | |
|
311 | 0 | err: |
312 | 0 | if (group) |
313 | 0 | EC_GROUP_free(group); |
314 | 0 | OPENSSL_free(encoded); |
315 | 0 | if (fail) { |
316 | 0 | if (ec) |
317 | 0 | EC_KEY_free(ec); |
318 | 0 | ec = NULL; |
319 | 0 | } |
320 | 0 | return ec; |
321 | 0 | } |
322 | | |
323 | | static DH * |
324 | | dhparams2dh(ASN1_TYPE *dh_params) |
325 | 0 | { |
326 | 0 | DH *dh = NULL; |
327 | 0 | int length = 1; |
328 | 0 | unsigned char *encoded = NULL; |
329 | 0 | const unsigned char *p; |
330 | |
|
331 | 0 | check(dh_params && dh_params->type == V_ASN1_SEQUENCE, |
332 | 0 | "Invalid arguments"); |
333 | | |
334 | | /* unfortunately we need to re-pack and re-parse the DHparams, |
335 | | * because there is no official API for using it directly (see |
336 | | * openssl/crypto/dh/dh.h) */ |
337 | 0 | length = i2d_ASN1_TYPE(dh_params, &encoded); |
338 | 0 | p = encoded; |
339 | 0 | check(length > 0 && d2i_DHparams(&dh, &p, length), |
340 | 0 | "Could not decode DH parameters"); |
341 | |
|
342 | 0 | err: |
343 | 0 | OPENSSL_free(encoded); |
344 | 0 | return dh; |
345 | 0 | } |
346 | | |
347 | | static EVP_PKEY * |
348 | | aid2pkey(EVP_PKEY **key, ALGORITHM_IDENTIFIER *aid, BN_CTX *bn_ctx) |
349 | 0 | { |
350 | 0 | EC_KEY *tmp_ec; |
351 | 0 | DH *tmp_dh; |
352 | 0 | EVP_PKEY *tmp_key = NULL, *ret = NULL; |
353 | 0 | char obj_txt[32]; |
354 | 0 | int nid; |
355 | | |
356 | | /* If there is no key, allocate memory */ |
357 | 0 | if (!key || !*key) { |
358 | 0 | tmp_key = EVP_PKEY_new(); |
359 | 0 | if (!tmp_key) |
360 | 0 | goto err; |
361 | 0 | } else |
362 | 0 | tmp_key = *key; |
363 | | |
364 | | /* Extract actual parameters */ |
365 | 0 | nid = OBJ_obj2nid(aid->algorithm); |
366 | 0 | if ( nid == NID_dhpublicnumber) { |
367 | 0 | tmp_dh = dhparams2dh(aid->parameters); |
368 | 0 | check(tmp_dh, "Could not decode DH key"); |
369 | 0 | EVP_PKEY_set1_DH(tmp_key, tmp_dh); |
370 | 0 | DH_free(tmp_dh); |
371 | |
|
372 | 0 | } else if (nid == NID_X9_62_id_ecPublicKey |
373 | 0 | || nid == NID_ecka_dh_SessionKDF_DES3 |
374 | 0 | || nid == NID_ecka_dh_SessionKDF_AES128 |
375 | 0 | || nid == NID_ecka_dh_SessionKDF_AES192 |
376 | 0 | || nid == NID_ecka_dh_SessionKDF_AES256) { |
377 | 0 | tmp_ec = ecpkparameters2eckey(aid->parameters); |
378 | 0 | check(tmp_ec, "Could not decode EC key"); |
379 | 0 | EVP_PKEY_set1_EC_KEY(tmp_key, tmp_ec); |
380 | 0 | EC_KEY_free(tmp_ec); |
381 | |
|
382 | 0 | } else if (nid == NID_standardizedDomainParameters) { |
383 | 0 | check(aid->parameters->type == V_ASN1_INTEGER, |
384 | 0 | "Invalid data"); |
385 | 0 | check(EVP_PKEY_set_std_dp(tmp_key, |
386 | 0 | ASN1_INTEGER_get(aid->parameters->value.integer)), |
387 | 0 | "Could not decode standardized domain parameter") |
388 | |
|
389 | 0 | } else { |
390 | 0 | OBJ_obj2txt(obj_txt, sizeof obj_txt, aid->algorithm, 0); |
391 | 0 | debug("Unknown Identifier (%s) for %s", OBJ_nid2sn(nid), obj_txt); |
392 | 0 | } |
393 | | |
394 | 0 | ret = tmp_key; |
395 | 0 | if (key) |
396 | 0 | *key = tmp_key; |
397 | |
|
398 | 0 | err: |
399 | 0 | if (tmp_key && tmp_key != ret) { |
400 | 0 | EVP_PKEY_free(tmp_key); |
401 | 0 | } |
402 | |
|
403 | 0 | return ret; |
404 | 0 | } |
405 | | |
406 | | |
407 | 0 | #define get_ctx_by_id(ctx, stack, _id) \ |
408 | 0 | { \ |
409 | 0 | int __i, __count; \ |
410 | 0 | __count = sk_num((_STACK*) stack); \ |
411 | 0 | for (__i = 0; __i < __count; __i++) { \ |
412 | 0 | ctx = sk_value((_STACK*) stack, __i); \ |
413 | 0 | if (ctx && ctx->id == _id) { \ |
414 | 0 | break; \ |
415 | 0 | } \ |
416 | 0 | } \ |
417 | 0 | if (__i >= __count) { \ |
418 | 0 | ctx = NULL; \ |
419 | 0 | } \ |
420 | 0 | } |
421 | | |
422 | 0 | #define get_ctx_by_keyID(ctx, stack, keyID, structure) \ |
423 | 0 | { \ |
424 | 0 | int __id; \ |
425 | 0 | if (keyID) { \ |
426 | 0 | __id = (int) ASN1_INTEGER_get(keyID); \ |
427 | 0 | } \ |
428 | 0 | else { \ |
429 | 0 | __id = -1; \ |
430 | 0 | } \ |
431 | 0 | /* lookup the context in the stack identified by info's keyID */ \ |
432 | 0 | get_ctx_by_id(ctx, stack, __id); \ |
433 | 0 | \ |
434 | 0 | /* if no context was found, create one and push it onto the stack */ \ |
435 | 0 | if (!ctx) { \ |
436 | 0 | ctx = structure##_new(); \ |
437 | 0 | if (ctx) { \ |
438 | 0 | if (!sk_push((_STACK *) stack, ctx)) { \ |
439 | 0 | structure##_clear_free(ctx); \ |
440 | 0 | ctx = NULL; \ |
441 | 0 | } else { \ |
442 | 0 | /* created and pushed successfully, now initialize id */ \ |
443 | 0 | if(keyID) { \ |
444 | 0 | ctx->id = __id; \ |
445 | 0 | } else { \ |
446 | 0 | ctx->id = -1; \ |
447 | 0 | } \ |
448 | 0 | } \ |
449 | 0 | } \ |
450 | 0 | } \ |
451 | 0 | } |
452 | | |
453 | | int |
454 | | EAC_CTX_init_ef_cardaccess(const unsigned char * in, size_t in_len, |
455 | | EAC_CTX *ctx) |
456 | 0 | { |
457 | 0 | ASN1_INTEGER *i = NULL; |
458 | 0 | ASN1_OBJECT *oid = NULL; |
459 | 0 | const unsigned char *pubkey; |
460 | 0 | size_t pubkey_len; |
461 | 0 | CA_CTX *ca_ctx = NULL; |
462 | 0 | CA_DP_INFO *tmp_ca_dp_info = NULL; |
463 | 0 | CA_INFO *tmp_ca_info = NULL; |
464 | 0 | CA_PUBLIC_KEY_INFO *ca_public_key_info = NULL; |
465 | 0 | PACE_CTX *pace_ctx = NULL; |
466 | 0 | PACE_DP_INFO *tmp_dp_info = NULL; |
467 | 0 | PACE_INFO *tmp_info = NULL; |
468 | 0 | RI_CTX *ri_ctx = NULL; |
469 | 0 | RI_DP_INFO *tmp_ri_dp_info = NULL; |
470 | 0 | RI_INFO *tmp_ri_info = NULL; |
471 | 0 | TA_INFO *tmp_ta_info = NULL; |
472 | 0 | char obj_txt[32]; |
473 | 0 | const unsigned char *info_start; |
474 | 0 | int tag, class, nid, _count, _i, r = 0, has_no_pace_dp_info = 1; |
475 | 0 | long data_len, info_len; |
476 | 0 | unsigned int todo = 0; |
477 | |
|
478 | 0 | check((in && ctx && ctx->pace_ctxs && ctx->ca_ctxs && ctx->ri_ctxs), |
479 | 0 | "Invalid arguments"); |
480 | | |
481 | | /* We need to manually extract all members of the SET OF SecurityInfos, |
482 | | * because some files contain junk and look something like this: |
483 | | * |
484 | | * SET { SecurityInfo, ..., SecurityInfo } , junk |
485 | | * |
486 | | * As far as we know, there is no way of telling OpenSSL to simply ignore |
487 | | * the junk in d2i_* functions. That's why we iterate manually through |
488 | | * the set */ |
489 | |
|
490 | 0 | check(!(0x80 & ASN1_get_object(&in, &data_len, &tag, &class, in_len)) |
491 | 0 | && tag == V_ASN1_SET, |
492 | 0 | "Invalid data"); |
493 | |
|
494 | 0 | todo = data_len; |
495 | |
|
496 | 0 | while (todo > 0) { |
497 | 0 | info_start = in; |
498 | |
|
499 | 0 | if (!(ASN1_get_object(&in, &data_len, &tag, &class, todo)) |
500 | 0 | || tag != V_ASN1_SEQUENCE) { |
501 | | /* we've reached the junk */ |
502 | 0 | break; |
503 | 0 | } |
504 | | |
505 | 0 | info_len = (in-info_start) + data_len; |
506 | |
|
507 | 0 | check(d2i_ASN1_OBJECT(&oid, &in, data_len), |
508 | 0 | "Invalid oid"); |
509 | |
|
510 | 0 | in = info_start; |
511 | |
|
512 | 0 | nid = OBJ_obj2nid(oid); |
513 | 0 | if ( nid == NID_id_PACE_DH_GM_3DES_CBC_CBC |
514 | 0 | || nid == NID_id_PACE_DH_IM_3DES_CBC_CBC |
515 | 0 | || nid == NID_id_PACE_ECDH_GM_3DES_CBC_CBC |
516 | 0 | || nid == NID_id_PACE_ECDH_IM_3DES_CBC_CBC |
517 | 0 | || nid == NID_id_PACE_DH_GM_AES_CBC_CMAC_128 |
518 | 0 | || nid == NID_id_PACE_DH_GM_AES_CBC_CMAC_192 |
519 | 0 | || nid == NID_id_PACE_DH_GM_AES_CBC_CMAC_256 |
520 | 0 | || nid == NID_id_PACE_DH_IM_AES_CBC_CMAC_128 |
521 | 0 | || nid == NID_id_PACE_DH_IM_AES_CBC_CMAC_192 |
522 | 0 | || nid == NID_id_PACE_DH_IM_AES_CBC_CMAC_256 |
523 | 0 | || nid == NID_id_PACE_ECDH_GM_AES_CBC_CMAC_128 |
524 | 0 | || nid == NID_id_PACE_ECDH_GM_AES_CBC_CMAC_192 |
525 | 0 | || nid == NID_id_PACE_ECDH_GM_AES_CBC_CMAC_256 |
526 | 0 | || nid == NID_id_PACE_ECDH_IM_AES_CBC_CMAC_128 |
527 | 0 | || nid == NID_id_PACE_ECDH_IM_AES_CBC_CMAC_192 |
528 | 0 | || nid == NID_id_PACE_ECDH_IM_AES_CBC_CMAC_256) { |
529 | | /* PACEInfo */ |
530 | 0 | check(d2i_PACE_INFO(&tmp_info, &in, info_len), |
531 | 0 | "Could not decode PACE info"); |
532 | | |
533 | | /* lookup or create a pace context */ |
534 | 0 | get_ctx_by_keyID(pace_ctx, ctx->pace_ctxs, tmp_info->keyID, PACE_CTX); |
535 | 0 | if (!pace_ctx) { |
536 | 0 | goto err; |
537 | 0 | } |
538 | | |
539 | 0 | pace_ctx->version = (unsigned char) ASN1_INTEGER_get(tmp_info->version); |
540 | 0 | if (pace_ctx->version <= 0 || pace_ctx->version > 2) |
541 | 0 | goto err; |
542 | | |
543 | 0 | if (!PACE_CTX_set_protocol(pace_ctx, |
544 | 0 | OBJ_obj2nid(tmp_info->protocol), ctx->tr_version)) |
545 | 0 | goto err; |
546 | |
|
547 | 0 | } else if (nid == NID_id_PACE_ECDH_GM |
548 | 0 | || nid == NID_id_PACE_ECDH_IM |
549 | 0 | || nid == NID_id_PACE_DH_GM |
550 | 0 | || nid == NID_id_PACE_DH_IM) { |
551 | | /* PACEDomainParameterInfo */ |
552 | 0 | has_no_pace_dp_info = 0; |
553 | 0 | check(d2i_PACE_DP_INFO(&tmp_dp_info, &in, info_len), |
554 | 0 | "Could not decode PACE domain parameter information"); |
555 | | |
556 | | /* lookup or create a pace context */ |
557 | 0 | get_ctx_by_keyID(pace_ctx, ctx->pace_ctxs, tmp_dp_info->keyID, PACE_CTX); |
558 | 0 | if (!pace_ctx) { |
559 | 0 | goto err; |
560 | 0 | } |
561 | | |
562 | 0 | if (!aid2pkey(&ctx->pace_ctx->static_key, tmp_dp_info->aid, ctx->bn_ctx)) |
563 | 0 | goto err; |
564 | |
|
565 | 0 | } else if (nid == NID_id_TA) { |
566 | | /* TAInfo */ |
567 | 0 | check(d2i_TA_INFO(&tmp_ta_info, &in, info_len), |
568 | 0 | "Could not decode TA info"); |
569 | |
|
570 | 0 | ctx->ta_ctx->version = (unsigned char) ASN1_INTEGER_get(tmp_ta_info->version); |
571 | 0 | if (ctx->ta_ctx->version <= 0 || ctx->ta_ctx->version > 2) |
572 | 0 | goto err; |
573 | | /* OID in TAInfo is less specific than the one in the certificate |
574 | | * Therefore this OID will be overwritten when we import a certificate |
575 | | * later on.*/ |
576 | 0 | ctx->ta_ctx->protocol = OBJ_obj2nid(tmp_ta_info->protocol); |
577 | 0 | } else if (nid == NID_id_CA_DH_3DES_CBC_CBC |
578 | 0 | || nid == NID_id_CA_DH_AES_CBC_CMAC_128 |
579 | 0 | || nid == NID_id_CA_DH_AES_CBC_CMAC_192 |
580 | 0 | || nid == NID_id_CA_DH_AES_CBC_CMAC_256 |
581 | 0 | || nid == NID_id_CA_ECDH_3DES_CBC_CBC |
582 | 0 | || nid == NID_id_CA_ECDH_AES_CBC_CMAC_128 |
583 | 0 | || nid == NID_id_CA_ECDH_AES_CBC_CMAC_192 |
584 | 0 | || nid == NID_id_CA_ECDH_AES_CBC_CMAC_256) { |
585 | | /* CAInfo */ |
586 | 0 | check(d2i_CA_INFO(&tmp_ca_info, &in, info_len), |
587 | 0 | "Could not decode CA info"); |
588 | | |
589 | | /* lookup or create a ca context */ |
590 | 0 | get_ctx_by_keyID(ca_ctx, ctx->ca_ctxs, tmp_ca_info->keyID, CA_CTX); |
591 | 0 | if (!ca_ctx) { |
592 | 0 | goto err; |
593 | 0 | } |
594 | | |
595 | 0 | ca_ctx->version = (unsigned char) ASN1_INTEGER_get(tmp_ca_info->version); |
596 | 0 | if (ca_ctx->version <= 0 || ca_ctx->version > 3 |
597 | 0 | || !CA_CTX_set_protocol(ca_ctx, nid)) |
598 | 0 | goto err; |
599 | |
|
600 | 0 | } else if (nid == NID_id_CA_DH |
601 | 0 | || nid == NID_id_CA_ECDH) { |
602 | | /* ChipAuthenticationDomainParameterInfo */ |
603 | 0 | check(d2i_CA_DP_INFO(&tmp_ca_dp_info, &in, info_len), |
604 | 0 | "Could not decode CA domain parameter info"); |
605 | | |
606 | | /* lookup or create a ca context */ |
607 | 0 | get_ctx_by_keyID(ca_ctx, ctx->ca_ctxs, tmp_ca_dp_info->keyID, CA_CTX); |
608 | 0 | if (!ca_ctx) { |
609 | 0 | goto err; |
610 | 0 | } |
611 | | |
612 | 0 | if (!aid2pkey(&ca_ctx->ka_ctx->key, tmp_ca_dp_info->aid, ctx->bn_ctx)) |
613 | 0 | goto err; |
614 | |
|
615 | 0 | } else if (nid == NID_id_PK_DH |
616 | 0 | || nid == NID_id_PK_ECDH) { |
617 | | /* ChipAuthenticationPublicKeyInfo */ |
618 | 0 | check(d2i_CA_PUBLIC_KEY_INFO(&ca_public_key_info, &in, info_len), |
619 | 0 | "Could not decode CA PK domain parameter info"); |
620 | | |
621 | | /* lookup or create a ca context */ |
622 | 0 | if (!tmp_ca_info) { |
623 | 0 | goto err; |
624 | 0 | } |
625 | 0 | get_ctx_by_keyID(ca_ctx, ctx->ca_ctxs, tmp_ca_info->keyID, CA_CTX); |
626 | 0 | if (!ca_ctx) { |
627 | 0 | goto err; |
628 | 0 | } |
629 | | |
630 | 0 | if (!aid2pkey(&ca_ctx->ka_ctx->key, |
631 | 0 | ca_public_key_info->chipAuthenticationPublicKeyInfo->algorithmIdentifier, |
632 | 0 | ctx->bn_ctx)) |
633 | 0 | goto err; |
634 | | |
635 | 0 | if (nid == NID_id_PK_DH) { |
636 | | /* FIXME the public key for DH is actually an ASN.1 |
637 | | * UNSIGNED INTEGER, which is an ASN.1 INTEGER that is |
638 | | * always positive. Parsing the unsigned integer should be |
639 | | * done in EVP_PKEY_set_key. */ |
640 | 0 | const unsigned char *p = ASN1_STRING_get0_data(ca_public_key_info->chipAuthenticationPublicKeyInfo->subjectPublicKey); |
641 | 0 | check(d2i_ASN1_UINTEGER(&i, &p, |
642 | 0 | ASN1_STRING_length(ca_public_key_info->chipAuthenticationPublicKeyInfo->subjectPublicKey)), |
643 | 0 | "Could not decode CA PK"); |
644 | 0 | pubkey = ASN1_STRING_get0_data(i); |
645 | 0 | pubkey_len = ASN1_STRING_length(i); |
646 | 0 | } else { |
647 | 0 | pubkey = ASN1_STRING_get0_data(ca_public_key_info->chipAuthenticationPublicKeyInfo->subjectPublicKey); |
648 | 0 | pubkey_len = ASN1_STRING_length(ca_public_key_info->chipAuthenticationPublicKeyInfo->subjectPublicKey); |
649 | 0 | } |
650 | | |
651 | 0 | if (!EVP_PKEY_set_keys(ca_ctx->ka_ctx->key, NULL, 0, pubkey, pubkey_len, ctx->bn_ctx)) |
652 | 0 | goto err; |
653 | |
|
654 | 0 | } else if (nid == NID_id_CI) { |
655 | | /* ChipIdentifer or cardInfoLocator */ |
656 | 0 | } else if (nid == NID_id_PT) { |
657 | 0 | } else if (nid == NID_id_RI_DH_SHA_1 |
658 | 0 | || nid == NID_id_RI_DH_SHA_224 |
659 | 0 | || nid == NID_id_RI_DH_SHA_256 |
660 | 0 | || nid == NID_id_RI_DH_SHA_384 |
661 | 0 | || nid == NID_id_RI_DH_SHA_512 |
662 | 0 | || nid == NID_id_RI_ECDH_SHA_1 |
663 | 0 | || nid == NID_id_RI_ECDH_SHA_224 |
664 | 0 | || nid == NID_id_RI_ECDH_SHA_256 |
665 | 0 | || nid == NID_id_RI_ECDH_SHA_384 |
666 | 0 | || nid == NID_id_RI_ECDH_SHA_512) { |
667 | | /* RestrictedIdentificationInfo */ |
668 | 0 | check(d2i_RI_INFO(&tmp_ri_info, &in, info_len), |
669 | 0 | "Could not decode RI info"); |
670 | | |
671 | | /* create a ri context */ |
672 | 0 | get_ctx_by_keyID(ri_ctx, ctx->ri_ctxs, NULL, RI_CTX); |
673 | 0 | if (!ri_ctx) { |
674 | 0 | goto err; |
675 | 0 | } |
676 | | |
677 | 0 | if (!RI_CTX_set_protocol(ri_ctx, nid)) |
678 | 0 | goto err; |
679 | |
|
680 | 0 | } else if (nid == NID_id_RI_DH |
681 | 0 | || nid == NID_id_RI_ECDH) { |
682 | | /* RestrictedIdentificationDomainParameterInfo */ |
683 | 0 | check(d2i_RI_DP_INFO(&tmp_ri_dp_info, &in, info_len), |
684 | 0 | "Could not decode RI domain parameter info"); |
685 | |
|
686 | 0 | _count = sk_num((_STACK*) ctx->ri_ctxs); |
687 | 0 | for (_i = 0; _i < _count; _i++) { |
688 | 0 | ri_ctx = sk_value((_STACK*) ctx->ri_ctxs, _i); |
689 | 0 | if (!ri_ctx) |
690 | 0 | goto err; |
691 | 0 | if (!aid2pkey(&ri_ctx->static_key, tmp_ri_dp_info->aid, ctx->bn_ctx)) |
692 | 0 | goto err; |
693 | 0 | } |
694 | |
|
695 | 0 | } else { |
696 | 0 | OBJ_obj2txt(obj_txt, sizeof obj_txt, oid, 0); |
697 | 0 | debug("Unknown Identifier (%s) for %s", OBJ_nid2sn(nid), obj_txt); |
698 | 0 | } |
699 | | |
700 | | /* if we have created the first PACE context, use it as default */ |
701 | 0 | if (!ctx->pace_ctx) |
702 | 0 | ctx->pace_ctx = pace_ctx; |
703 | | /* if we have created the first CA context, use it as default */ |
704 | 0 | if (!ctx->ca_ctx) |
705 | 0 | ctx->ca_ctx = ca_ctx; |
706 | | /* if we have created the first RI context, use it as default */ |
707 | 0 | if (!ctx->ri_ctx) |
708 | 0 | ctx->ri_ctx = ri_ctx; |
709 | |
|
710 | 0 | todo -= info_len; |
711 | 0 | in = info_start+info_len; |
712 | 0 | } |
713 | | |
714 | | /* although a PACEDomainParameterInfo MUST be present in every version of |
715 | | * BSI TR-03110, they are not included in the EAC worked Example. We |
716 | | * recognize this error and use the keyID as standardizedDomainParameter */ |
717 | 0 | if (ctx->pace_ctx && has_no_pace_dp_info) { |
718 | 0 | if (!EVP_PKEY_set_std_dp(ctx->pace_ctx->static_key, ctx->pace_ctx->id)) |
719 | 0 | goto err; |
720 | 0 | } |
721 | | |
722 | 0 | r = 1; |
723 | |
|
724 | 0 | err: |
725 | 0 | if (oid) |
726 | 0 | ASN1_OBJECT_free(oid); |
727 | 0 | if (tmp_info) |
728 | 0 | PACE_INFO_free(tmp_info); |
729 | 0 | if (tmp_dp_info) |
730 | 0 | PACE_DP_INFO_free(tmp_dp_info); |
731 | 0 | if (tmp_ta_info) |
732 | 0 | TA_INFO_free(tmp_ta_info); |
733 | 0 | if (tmp_ca_info) |
734 | 0 | CA_INFO_free(tmp_ca_info); |
735 | 0 | if (tmp_ri_info) |
736 | 0 | RI_INFO_free(tmp_ri_info); |
737 | 0 | if (tmp_ri_dp_info) |
738 | 0 | RI_DP_INFO_free(tmp_ri_dp_info); |
739 | 0 | if (i) |
740 | 0 | ASN1_INTEGER_free(i); |
741 | 0 | if (tmp_ca_dp_info) |
742 | 0 | CA_DP_INFO_free(tmp_ca_dp_info); |
743 | 0 | if (ca_public_key_info) |
744 | 0 | CA_PUBLIC_KEY_INFO_free(ca_public_key_info); |
745 | |
|
746 | 0 | return r; |
747 | 0 | } |
748 | | |
749 | | BUF_MEM * |
750 | | asn1_pubkey(int protocol, EVP_PKEY *key, BN_CTX *bn_ctx, enum eac_tr_version tr_version) |
751 | 0 | { |
752 | 0 | CVC_PUBKEY *eac_pubkey = NULL; |
753 | 0 | BUF_MEM *pubkey = NULL; |
754 | 0 | int l; |
755 | |
|
756 | 0 | eac_pubkey = CVC_pkey2pubkey(tr_version == EAC_TR_VERSION_2_01 ? 1 : 0, protocol, key, bn_ctx, NULL); |
757 | 0 | if (!eac_pubkey) |
758 | 0 | goto err; |
759 | | |
760 | 0 | pubkey = BUF_MEM_new(); |
761 | 0 | if (!pubkey) |
762 | 0 | goto err; |
763 | | |
764 | 0 | l = i2d_CVC_PUBKEY(eac_pubkey, (unsigned char **) &pubkey->data); |
765 | 0 | if (l < 0) { |
766 | 0 | BUF_MEM_free(pubkey); |
767 | 0 | pubkey = NULL; |
768 | 0 | goto err; |
769 | 0 | } |
770 | 0 | pubkey->length = l; |
771 | 0 | pubkey->max = l; |
772 | |
|
773 | 0 | err: |
774 | 0 | if (eac_pubkey) |
775 | 0 | CVC_PUBKEY_free(eac_pubkey); |
776 | |
|
777 | 0 | return pubkey; |
778 | 0 | } |