/src/opensc/openpace/src/eac_ca.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2010-2012 Frank Morgner and Dominik Oepen |
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_ca.c |
40 | | * @brief Chip Authentication implementation |
41 | | * |
42 | | * @author Frank Morgner <frankmorgner@gmail.com> |
43 | | * @author Dominik Oepen <oepen@informatik.hu-berlin.de> |
44 | | */ |
45 | | |
46 | | #ifdef HAVE_CONFIG_H |
47 | | #include "config.h" |
48 | | #endif |
49 | | |
50 | | #include "eac_asn1.h" |
51 | | #include "eac_err.h" |
52 | | #include "eac_lib.h" |
53 | | #include "eac_util.h" |
54 | | #include <eac/ca.h> |
55 | | #include <eac/pace.h> |
56 | | #include <openssl/crypto.h> |
57 | | #include <openssl/dh.h> |
58 | | #include <openssl/ec.h> |
59 | | #include <openssl/evp.h> |
60 | | #include <openssl/obj_mac.h> |
61 | | #include <openssl/pkcs7.h> |
62 | | #include <openssl/x509.h> |
63 | | #include <string.h> |
64 | | |
65 | | static int CA_passive_authentication(const EAC_CTX *ctx, PKCS7 *ef_cardsecurity); |
66 | | |
67 | | BUF_MEM * |
68 | | CA_STEP1_get_pubkey(const EAC_CTX *ctx) |
69 | 0 | { |
70 | 0 | check_return(ctx && ctx->ca_ctx && ctx->ca_ctx->ka_ctx, |
71 | 0 | "Invalid arguments"); |
72 | |
|
73 | 0 | return asn1_pubkey(ctx->ca_ctx->protocol, ctx->ca_ctx->ka_ctx->key, |
74 | 0 | ctx->bn_ctx, ctx->tr_version); |
75 | 0 | } |
76 | | |
77 | | BUF_MEM * |
78 | | CA_STEP2_get_eph_pubkey(const EAC_CTX *ctx) |
79 | 0 | { |
80 | 0 | check_return(ctx && ctx->ca_ctx && ctx->ca_ctx->ka_ctx, |
81 | 0 | "Invalid arguments"); |
82 | |
|
83 | 0 | return get_pubkey(ctx->ca_ctx->ka_ctx->key, ctx->bn_ctx); |
84 | 0 | } |
85 | | |
86 | | int |
87 | | CA_STEP3_check_pcd_pubkey(const EAC_CTX *ctx, |
88 | | const BUF_MEM *comp_pubkey, const BUF_MEM *pubkey) |
89 | 0 | { |
90 | 0 | BUF_MEM *my_comp_pubkey = NULL; |
91 | 0 | int r = -1; |
92 | |
|
93 | 0 | check((ctx && ctx->ca_ctx && comp_pubkey && ctx->ca_ctx->ka_ctx), |
94 | 0 | "Invalid arguments"); |
95 | | |
96 | | /* Compress own public key */ |
97 | 0 | my_comp_pubkey = Comp(ctx->ca_ctx->ka_ctx->key, pubkey, ctx->bn_ctx, ctx->md_ctx); |
98 | 0 | check(my_comp_pubkey, "Failed to compress public key"); |
99 | | |
100 | | /* Check whether or not the received data fits the own data */ |
101 | 0 | if (my_comp_pubkey->length != comp_pubkey->length |
102 | 0 | || memcmp(my_comp_pubkey->data, comp_pubkey->data, comp_pubkey->length) != 0) { |
103 | 0 | log_err("Wrong public key"); |
104 | 0 | r = 0; |
105 | 0 | } else |
106 | 0 | r = 1; |
107 | |
|
108 | 0 | err: |
109 | 0 | if (my_comp_pubkey) |
110 | 0 | BUF_MEM_free(my_comp_pubkey); |
111 | |
|
112 | 0 | return r; |
113 | 0 | } |
114 | | |
115 | | int |
116 | | CA_STEP4_compute_shared_secret(const EAC_CTX *ctx, const BUF_MEM *pubkey) |
117 | 0 | { |
118 | 0 | if (!ctx || !ctx->ca_ctx |
119 | 0 | || !KA_CTX_compute_key(ctx->ca_ctx->ka_ctx, pubkey, ctx->bn_ctx)) { |
120 | 0 | log_err("Invalid arguments"); |
121 | 0 | return 0; |
122 | 0 | } |
123 | | |
124 | 0 | return 1; |
125 | 0 | } |
126 | | |
127 | | int |
128 | | CA_passive_authentication(const EAC_CTX *ctx, PKCS7 *ef_cardsecurity) |
129 | 0 | { |
130 | 0 | X509 *ds_cert; |
131 | 0 | X509_STORE *store; |
132 | 0 | STACK_OF(X509) *ds_certs = NULL; |
133 | 0 | unsigned long issuer_name_hash; |
134 | 0 | int ret = 0; |
135 | |
|
136 | 0 | check(ef_cardsecurity && ctx && ctx->ca_ctx && ctx->ca_ctx->lookup_csca_cert, "Invalid arguments"); |
137 | | |
138 | | /* Extract the DS certificates from the EF.CardSecurity */ |
139 | 0 | ds_certs = PKCS7_get0_signers(ef_cardsecurity, NULL, 0); |
140 | 0 | check(ds_certs, "Failed to retrieve certificates from EF.CardSecurity"); |
141 | | |
142 | | /* NOTE: The following code assumes that there is only one certificate in |
143 | | * PKCS7 structure. ds_cert is implicitly freed together with ds_certs. */ |
144 | 0 | ds_cert = sk_X509_pop(ds_certs); |
145 | 0 | check(ds_cert, "Failed to retrieve DS certificate from EF.CardSecurity"); |
146 | | |
147 | | /* Get the trust store with at least the csca certificate */ |
148 | 0 | issuer_name_hash = X509_issuer_name_hash(ds_cert); |
149 | 0 | store = ctx->ca_ctx->lookup_csca_cert(issuer_name_hash); |
150 | 0 | check (store, "Failed to retrieve CSCA truststore"); |
151 | | |
152 | | /* Verify the signature and the certificate chain */ |
153 | 0 | ret = PKCS7_verify(ef_cardsecurity, ds_certs, store, NULL, NULL, 0); |
154 | |
|
155 | 0 | err: |
156 | 0 | if (ds_certs) |
157 | 0 | sk_X509_free(ds_certs); |
158 | |
|
159 | 0 | return ret; |
160 | 0 | } |
161 | | |
162 | | int |
163 | | EAC_CTX_init_ef_cardsecurity(const unsigned char *ef_cardsecurity, |
164 | | size_t ef_cardsecurity_len, EAC_CTX *ctx) |
165 | 0 | { |
166 | 0 | PKCS7 *p7 = NULL, *signed_data; |
167 | 0 | ASN1_OCTET_STRING *os; |
168 | 0 | int r = 0; |
169 | |
|
170 | 0 | check(ef_cardsecurity, "Invalid arguments"); |
171 | |
|
172 | 0 | if (!d2i_PKCS7(&p7, &ef_cardsecurity, ef_cardsecurity_len) |
173 | 0 | || !PKCS7_type_is_signed(p7)) |
174 | 0 | goto err; |
175 | | |
176 | 0 | if (ctx && ctx->ca_ctx && |
177 | 0 | !(ctx->ca_ctx->flags & CA_FLAG_DISABLE_PASSIVE_AUTH)) |
178 | 0 | check((CA_passive_authentication(ctx, p7) == 1), |
179 | 0 | "Failed to perform passive authentication"); |
180 | |
|
181 | 0 | signed_data = p7->d.sign->contents; |
182 | 0 | if (OBJ_obj2nid(signed_data->type) != NID_id_SecurityObject |
183 | 0 | || ASN1_TYPE_get(signed_data->d.other) != V_ASN1_OCTET_STRING) |
184 | 0 | goto err; |
185 | 0 | os = signed_data->d.other->value.octet_string; |
186 | |
|
187 | 0 | if (!EAC_CTX_init_ef_cardaccess(os->data, os->length, ctx) |
188 | 0 | || !ctx || !ctx->ca_ctx || !ctx->ca_ctx->ka_ctx) |
189 | 0 | goto err; |
190 | | |
191 | 0 | r = 1; |
192 | |
|
193 | 0 | err: |
194 | 0 | if (p7) |
195 | 0 | PKCS7_free(p7); |
196 | |
|
197 | 0 | return r; |
198 | 0 | } |
199 | | |
200 | | BUF_MEM * |
201 | | CA_get_pubkey(const EAC_CTX *ctx, |
202 | | const unsigned char *ef_cardsecurity, |
203 | | size_t ef_cardsecurity_len) |
204 | 0 | { |
205 | 0 | BUF_MEM *pubkey = NULL; |
206 | 0 | EAC_CTX *signed_ctx = EAC_CTX_new(); |
207 | 0 | check(ctx && ctx->ca_ctx, "Invalid arguments"); |
208 | |
|
209 | 0 | if (ctx->ca_ctx->flags & CA_FLAG_DISABLE_PASSIVE_AUTH) |
210 | 0 | CA_disable_passive_authentication(signed_ctx); |
211 | |
|
212 | 0 | check(EAC_CTX_init_ef_cardsecurity(ef_cardsecurity, ef_cardsecurity_len, |
213 | 0 | signed_ctx) |
214 | 0 | && signed_ctx && signed_ctx->ca_ctx && signed_ctx->ca_ctx->ka_ctx, |
215 | 0 | "Could not parse EF.CardSecurity"); |
216 | |
|
217 | 0 | pubkey = get_pubkey(signed_ctx->ca_ctx->ka_ctx->key, signed_ctx->bn_ctx); |
218 | |
|
219 | 0 | err: |
220 | 0 | EAC_CTX_clear_free(signed_ctx); |
221 | |
|
222 | 0 | return pubkey; |
223 | 0 | } |
224 | | |
225 | | int |
226 | | CA_set_key(const EAC_CTX *ctx, |
227 | | const unsigned char *priv, size_t priv_len, |
228 | | const unsigned char *pub, size_t pub_len) |
229 | 0 | { |
230 | 0 | int r = 0; |
231 | 0 | const unsigned char *p = priv; |
232 | 0 | EVP_PKEY *key = NULL; |
233 | |
|
234 | 0 | check(ctx && ctx->ca_ctx && ctx->ca_ctx->ka_ctx, |
235 | 0 | "Invalid arguments"); |
236 | | |
237 | | /* always try d2i_AutoPrivateKey as priv may contain domain parameters */ |
238 | 0 | if (priv && d2i_AutoPrivateKey(&key, &p, priv_len)) { |
239 | 0 | EVP_PKEY_free(ctx->ca_ctx->ka_ctx->key); |
240 | 0 | ctx->ca_ctx->ka_ctx->key = key; |
241 | 0 | if (pub) { |
242 | | /* it's OK if import of public key fails */ |
243 | 0 | EVP_PKEY_set_keys(key, NULL, 0, pub, pub_len, ctx->bn_ctx); |
244 | 0 | } |
245 | 0 | } else { |
246 | | /* wipe errors from d2i_AutoPrivateKey() */ |
247 | 0 | ERR_clear_error(); |
248 | 0 | check(EVP_PKEY_set_keys(ctx->ca_ctx->ka_ctx->key, priv, priv_len, pub, |
249 | 0 | pub_len, ctx->bn_ctx), |
250 | 0 | "no valid keys given"); |
251 | 0 | } |
252 | 0 | r = 1; |
253 | |
|
254 | 0 | err: |
255 | 0 | return r; |
256 | 0 | } |
257 | | |
258 | | /* Nonce for CA is always 8 bytes long */ |
259 | 0 | #define CA_NONCE_SIZE 8 |
260 | | int |
261 | | CA_STEP5_derive_keys(const EAC_CTX *ctx, const BUF_MEM *pub, |
262 | | BUF_MEM **nonce, BUF_MEM **token) |
263 | 0 | { |
264 | 0 | BUF_MEM *r = NULL; |
265 | 0 | BUF_MEM *authentication_token = NULL; |
266 | |
|
267 | 0 | check((ctx && ctx->ca_ctx && ctx->ca_ctx->ka_ctx && nonce && token), |
268 | 0 | "Invalid arguments"); |
269 | | |
270 | | /* Generate nonce and derive k_mac and k_enc*/ |
271 | 0 | r = randb(CA_NONCE_SIZE); |
272 | 0 | if (!r || !KA_CTX_derive_keys(ctx->ca_ctx->ka_ctx, r, ctx->md_ctx)) |
273 | 0 | goto err; |
274 | | |
275 | | /* Compute authentication token */ |
276 | 0 | authentication_token = get_authentication_token(ctx->ca_ctx->protocol, |
277 | 0 | ctx->ca_ctx->ka_ctx, ctx->bn_ctx, ctx->tr_version, |
278 | 0 | pub); |
279 | 0 | check(authentication_token, "Failed to compute authentication token"); |
280 | |
|
281 | 0 | *nonce = r; |
282 | 0 | *token = authentication_token; |
283 | |
|
284 | 0 | return 1; |
285 | | |
286 | 0 | err: |
287 | 0 | BUF_MEM_clear_free(r); |
288 | |
|
289 | 0 | return 0; |
290 | 0 | } |
291 | | |
292 | | int |
293 | | CA_STEP6_derive_keys(EAC_CTX *ctx, const BUF_MEM *nonce, const BUF_MEM *token) |
294 | 0 | { |
295 | 0 | int rv = -1; |
296 | |
|
297 | 0 | check((ctx && ctx->ca_ctx), "Invalid arguments"); |
298 | |
|
299 | 0 | if (!KA_CTX_derive_keys(ctx->ca_ctx->ka_ctx, nonce, ctx->md_ctx)) |
300 | 0 | goto err; |
301 | | |
302 | 0 | rv = verify_authentication_token(ctx->ca_ctx->protocol, |
303 | 0 | ctx->ca_ctx->ka_ctx, |
304 | 0 | ctx->bn_ctx, ctx->tr_version, token); |
305 | 0 | check(rv >= 0, "Failed to verify authentication token"); |
306 | | |
307 | | /* PACE, TA and CA were successful. Update the trust anchor! */ |
308 | 0 | if (rv) { |
309 | 0 | if (ctx->ta_ctx->new_trust_anchor) { |
310 | 0 | CVC_CERT_free(ctx->ta_ctx->trust_anchor); |
311 | 0 | ctx->ta_ctx->trust_anchor = ctx->ta_ctx->new_trust_anchor; |
312 | 0 | ctx->ta_ctx->new_trust_anchor = NULL; |
313 | 0 | } |
314 | 0 | } |
315 | |
|
316 | 0 | err: |
317 | 0 | return rv; |
318 | 0 | } |
319 | | |
320 | | void |
321 | | CA_disable_passive_authentication (EAC_CTX *ctx) |
322 | 0 | { |
323 | 0 | if (!ctx || !ctx->ca_ctx) |
324 | 0 | return; |
325 | 0 | ctx->ca_ctx->flags |= CA_FLAG_DISABLE_PASSIVE_AUTH; |
326 | 0 | return; |
327 | 0 | } |