Coverage Report

Created: 2026-01-09 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/openpace/src/ta_lib.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 ta_lib.c
40
 *
41
 * @author Frank Morgner <frankmorgner@gmail.com>
42
 * @author Dominik Oepen <oepen@informatik.hu-berlin.de>
43
 */
44
45
#ifdef HAVE_CONFIG_H
46
#include "config.h"
47
#endif
48
49
#include "eac_err.h"
50
#include "eac_util.h"
51
#include "ssl_compat.h"
52
#include "ta_lib.h"
53
#include <eac/cv_cert.h>
54
#include <eac/ta.h>
55
#include <openssl/evp.h>
56
#include <openssl/objects.h>
57
#include <openssl/rsa.h>
58
#include <string.h>
59
60
TA_CTX *
61
0
TA_CTX_new(void) {
62
0
    TA_CTX *ctx = (TA_CTX *) OPENSSL_zalloc(sizeof(TA_CTX));
63
0
    if (!ctx)
64
0
        return NULL;
65
66
0
    ctx->lookup_cvca_cert = EAC_get_default_cvca_lookup();
67
68
0
    return ctx;
69
0
}
70
71
void
72
0
TA_CTX_clear_free(TA_CTX *ctx) {
73
0
    if (!ctx)
74
0
        return;
75
76
0
    if (ctx->pk_pcd)
77
0
        BUF_MEM_free(ctx->pk_pcd);
78
0
    if (ctx->priv_key)
79
0
        EVP_PKEY_free(ctx->priv_key);
80
0
    if (ctx->pub_key)
81
0
        EVP_PKEY_free(ctx->pub_key);
82
0
    if (ctx->trust_anchor)
83
0
        CVC_CERT_free(ctx->trust_anchor);
84
0
    if (ctx->current_cert)
85
0
        CVC_CERT_free(ctx->current_cert);
86
0
    if (ctx->new_trust_anchor)
87
0
        CVC_CERT_free(ctx->new_trust_anchor);
88
0
    BUF_MEM_clear_free(ctx->nonce);
89
90
0
    OPENSSL_free(ctx);
91
0
    return;
92
0
}
93
94
#include <time.h>
95
static int
96
cvc_check_time(const CVC_CERT *cert)
97
0
{
98
0
    time_t loc;
99
0
    struct tm exp_tm, eff_tm, *utc_tm;
100
101
0
    if (!cert || !cert->body
102
0
            || !cert->body->certificate_effective_date
103
0
            || cert->body->certificate_effective_date->length != 6
104
0
            || !is_bcd(cert->body->certificate_effective_date->data,
105
0
                cert->body->certificate_effective_date->length)
106
0
            || cert->body->certificate_expiration_date->length != 6
107
0
            || !is_bcd(cert->body->certificate_expiration_date->data,
108
0
                cert->body->certificate_expiration_date->length))
109
0
        return -1;
110
111
    /* FIXME gmtime is not thread safe */
112
0
    time(&loc);
113
0
    utc_tm = gmtime(&loc);
114
0
    if (!utc_tm)
115
0
        return -1;
116
117
0
    memcpy(&eff_tm, utc_tm, sizeof(struct tm));
118
0
    eff_tm.tm_sec = 0;          /* seconds */
119
0
    eff_tm.tm_min = 0;          /* minutes */
120
0
    eff_tm.tm_hour = 0;         /* hours */
121
0
    eff_tm.tm_wday = -1;        /* day of the week */
122
0
    eff_tm.tm_yday = -1;        /* day in the year */
123
0
    eff_tm.tm_year = 100        /* The number of years since 1900 */
124
0
        + ((unsigned char) cert->body->certificate_effective_date->data[0])*10
125
0
        + (unsigned char) cert->body->certificate_effective_date->data[1];
126
0
    eff_tm.tm_mon = ((unsigned char) cert->body->certificate_effective_date->data[2])*10
127
0
        + (unsigned char) cert->body->certificate_effective_date->data[3] - 1;
128
0
    eff_tm.tm_mday = ((unsigned char) cert->body->certificate_effective_date->data[4])*10
129
0
        + (unsigned char) cert->body->certificate_effective_date->data[5];
130
131
0
    memcpy(&exp_tm, utc_tm, sizeof(struct tm));
132
0
    exp_tm.tm_sec = 59;         /* seconds */
133
0
    exp_tm.tm_min = 59;         /* minutes */
134
0
    exp_tm.tm_hour = 23;        /* hours */
135
0
    exp_tm.tm_wday = -1;        /* day of the week */
136
0
    exp_tm.tm_yday = -1;        /* day in the year */
137
0
    exp_tm.tm_year = 100        /* The number of years since 1900 */
138
0
        + ((unsigned char) cert->body->certificate_expiration_date->data[0])*10
139
0
        + (unsigned char) cert->body->certificate_expiration_date->data[1];
140
0
    exp_tm.tm_mon = ((unsigned char) cert->body->certificate_expiration_date->data[2])*10
141
0
        + (unsigned char) cert->body->certificate_expiration_date->data[3] - 1;
142
0
    exp_tm.tm_mday = ((unsigned char) cert->body->certificate_expiration_date->data[4])*10
143
0
        + (unsigned char) cert->body->certificate_expiration_date->data[5];
144
145
0
    if (exp_tm.tm_mon < 0 || exp_tm.tm_mon > 12
146
0
            || exp_tm.tm_mday > 31
147
0
            || eff_tm.tm_mon < 0 || eff_tm.tm_mon > 11
148
0
            || eff_tm.tm_mday > 31
149
0
            || difftime(mktime(utc_tm), mktime(&eff_tm)) < 0
150
0
            || difftime(mktime(&exp_tm), mktime(utc_tm)) < 0) {
151
0
        return 0;
152
0
    }
153
154
0
    return 1;
155
0
}
156
157
static int
158
TA_CTX_set_parameters(TA_CTX *ctx, const CVC_CERT *cert,
159
        BN_CTX *bn_ctx)
160
0
{
161
0
    EVP_PKEY *pub = NULL;
162
0
    int ok = 0, oid;
163
164
0
    check(ctx && cert && cert->body && cert->body->public_key,
165
0
            "Invalid arguments");
166
167
    /* Extract the public key of the terminal and overwrite the current key. */
168
0
    if (ctx->priv_key) {
169
0
        pub = EVP_PKEY_dup(ctx->priv_key);
170
0
        check(pub, "Failed to create public key");
171
0
        check(CVC_pubkey2pkey(cert, bn_ctx, pub),
172
0
                "Failed to extract public key");
173
0
    } else {
174
        /* ctx->pub might be NULL (in case of a CVCA certificate). */
175
0
        pub = CVC_pubkey2pkey(cert, bn_ctx, ctx->pub_key);
176
0
        check(pub, "Failed to extract public key");
177
0
    }
178
0
    ctx->pub_key = pub;
179
0
    pub = NULL;
180
181
    /* Extract OID from the terminal certificate */
182
0
    oid = OBJ_obj2nid(cert->body->public_key->oid);
183
0
    check(oid != NID_undef, "Unknown public key format");
184
185
    /* Use the oid as the protocol identifier in the TA context */
186
0
    ctx->protocol = oid;
187
188
0
    ok = 1;
189
190
0
err:
191
0
    if (pub)
192
0
        EVP_PKEY_free(pub);
193
0
    return ok;
194
0
}
195
196
int
197
TA_CTX_import_certificate(TA_CTX *ctx, const CVC_CERT *next_cert,
198
           BN_CTX *bn_ctx)
199
0
{
200
0
    int ok = 0, i;
201
0
    CVC_CERT *trust_anchor = NULL;
202
203
0
    check(ctx && next_cert && next_cert->body && next_cert->body->chat &&
204
0
            next_cert->body->certificate_authority_reference,
205
0
           "Invalid arguments");
206
207
    /* Check date to see if the certificate is still valid
208
     * (not for link certificates). */
209
0
    if ((ctx->flags & TA_FLAG_SKIP_TIMECHECK) != TA_FLAG_SKIP_TIMECHECK
210
0
            && CVC_get_role(next_cert->body->chat) != CVC_CVCA) {
211
0
        check(cvc_check_time(next_cert) == 1,
212
0
                "Could not verify certificate's validity period");
213
0
    }
214
215
    /* get the current trust anchor */
216
0
    if (ctx->current_cert) {
217
0
        trust_anchor = ctx->current_cert;
218
0
    } else if (ctx->trust_anchor) {
219
0
        trust_anchor = ctx->trust_anchor;
220
0
    } else if (ctx->lookup_cvca_cert) {
221
0
        trust_anchor = ctx->lookup_cvca_cert(
222
0
                next_cert->body->certificate_authority_reference->data,
223
0
                next_cert->body->certificate_authority_reference->length);
224
0
        check(trust_anchor, "Could not look up trust anchor");
225
226
        /* lookup the whole certificate chain until we hit an CVCA
227
         * certificate, otherwise we won't have a complete public key */
228
0
        if (CVC_get_role(trust_anchor->body->chat) == CVC_CVCA) {
229
0
            TA_CTX_set_trust_anchor(ctx, trust_anchor, bn_ctx);
230
0
        } else {
231
0
            check(TA_CTX_import_certificate(ctx, trust_anchor, bn_ctx),
232
0
                    "Could not look up certificate chain");
233
0
        }
234
0
    }
235
0
    check(trust_anchor && trust_anchor->body
236
0
            && trust_anchor->body->certificate_holder_reference,
237
0
            "No trust anchor, can't verify certificate");
238
239
    /* Check chain integrity: The CAR of a certificate must be equal to the
240
     * the CHR of the next certificate in the chain */
241
0
    check((next_cert->body->certificate_authority_reference
242
0
                && trust_anchor->body->certificate_holder_reference
243
0
                && next_cert->body->certificate_authority_reference->length ==
244
0
                trust_anchor->body->certificate_holder_reference->length
245
0
                && memcmp(trust_anchor->body->certificate_holder_reference->data,
246
0
                    next_cert->body->certificate_authority_reference->data,
247
0
                    trust_anchor->body->certificate_holder_reference->length) == 0),
248
0
            "Current CHR does not match next CAR");
249
250
0
    i = CVC_verify_signature(next_cert,
251
0
            OBJ_obj2nid(trust_anchor->body->public_key->oid), ctx->pub_key);
252
0
    check((i > 0), "Could not verify current signature");
253
254
    /* Certificate has been verified as next part of the chain */
255
0
    if (ctx->current_cert) {
256
0
        if (trust_anchor == ctx->current_cert)
257
0
            trust_anchor = NULL;
258
0
        CVC_CERT_free(ctx->current_cert);
259
0
    }
260
0
    ctx->current_cert = CVC_CERT_dup(next_cert);
261
0
    if (!ctx->current_cert)
262
0
        goto err;
263
264
    /* Set a (new) trust anchor */
265
0
    if (CVC_get_role(next_cert->body->chat) == CVC_CVCA) {
266
0
        if (ctx->new_trust_anchor)
267
0
            CVC_CERT_free(ctx->new_trust_anchor);
268
0
        ctx->new_trust_anchor = CVC_CERT_dup(next_cert);
269
0
        if (!ctx->new_trust_anchor)
270
0
            goto err;
271
0
    }
272
273
0
    ok = TA_CTX_set_parameters(ctx, next_cert, bn_ctx);
274
275
0
err:
276
0
    if (trust_anchor && trust_anchor != ctx->current_cert
277
0
            && trust_anchor != ctx->trust_anchor) {
278
0
        CVC_CERT_free(trust_anchor);
279
0
    }
280
281
0
    return ok;
282
0
}
283
284
int
285
TA_CTX_set_trust_anchor(TA_CTX *ctx, const CVC_CERT *trust_anchor,
286
           BN_CTX *bn_ctx)
287
0
{
288
0
    int ok = 0;
289
290
0
    check(ctx, "Invalid Parameters");
291
292
0
    if (ctx->trust_anchor)
293
0
        CVC_CERT_free(ctx->trust_anchor);
294
0
    ctx->trust_anchor = CVC_CERT_dup(trust_anchor);
295
0
    if (!ctx->trust_anchor)
296
0
        goto err;
297
298
0
    if (ctx->current_cert) {
299
0
        CVC_CERT_free(ctx->current_cert);
300
0
        ctx->current_cert = NULL;
301
0
    }
302
303
0
    ok = TA_CTX_set_parameters(ctx, trust_anchor, bn_ctx);
304
305
0
err:
306
0
    return ok;
307
0
}