Coverage Report

Created: 2025-10-13 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}