Coverage Report

Created: 2026-03-08 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/openpace/src/pace_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 pace_lib.c
40
 * @brief Data management functions
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_dh.h"
51
#include "eac_ecdh.h"
52
#include "eac_err.h"
53
#include "eac_lib.h"
54
#include "eac_util.h"
55
#include "misc.h"
56
#include "ssl_compat.h"
57
#include "pace_mappings.h"
58
#include <eac/pace.h>
59
#include <openssl/buffer.h>
60
#include <openssl/crypto.h>
61
#include <openssl/evp.h>
62
#include <openssl/objects.h>
63
#include <string.h>
64
65
/**
66
 * @brief Encodes a shared secret according to TR-3110 Table F.2
67
 *
68
 * @param pi Password to encode
69
 *
70
 * @return BUF_MEM object containing the encoded password or NULL if an error occurred
71
 *
72
 * @note This function is automatically called during PACE, normally you should not need to use it.
73
 */
74
static BUF_MEM *
75
encoded_secret(const PACE_SEC * pi);
76
/* Data must include the check byte when used for PACE */
77
0
#define MRZ_SERIALNUMBER_LEN    (9+1)
78
0
#define MRZ_DATEOFBIRTH_LEN     (6+1)
79
0
#define MRZ_DATEOFEXPIRY_LEN    (6+1)
80
0
#define MRZ_SERIALNUMBER_OFF    5
81
0
#define MRZ_DATEOFBIRTH_OFF     30
82
0
#define MRZ_DATEOFEXPIRY_OFF    38
83
/**
84
 * @brief Encodes the Machine readable zone according to TR-03110 table A.3
85
 *
86
 * @param[in] mrz buffer containing the MRZ
87
 * @param[in] len size of the buffer
88
 *
89
 * @return the encoded MRZ or NULL on error
90
 */
91
static BUF_MEM *
92
encoded_mrz(const char *mrz, size_t len);
93
94
void
95
PACE_SEC_clear_free(PACE_SEC * s)
96
0
{
97
0
    if (s) {
98
0
        if (s->mem) {
99
0
            OPENSSL_cleanse(s->mem->data, s->mem->max);
100
0
            BUF_MEM_free(s->mem);
101
0
        }
102
0
        if (s->encoded) {
103
0
            OPENSSL_cleanse(s->encoded->data, s->encoded->max);
104
0
            BUF_MEM_free(s->encoded);
105
0
        }
106
0
        OPENSSL_free(s);
107
0
    }
108
0
}
109
110
PACE_SEC *
111
PACE_SEC_new(const char *sec, size_t sec_len, enum s_type type)
112
0
{
113
0
    PACE_SEC *out = OPENSSL_zalloc(sizeof(PACE_SEC));
114
0
    check(out, "Out of memory");
115
116
0
    switch (type) {
117
0
        case PACE_PUK:
118
0
        case PACE_CAN:
119
0
        case PACE_PIN:
120
0
        case PACE_MRZ:
121
0
        case PACE_RAW:
122
0
            out->type = type;
123
0
            break;
124
125
0
        default:
126
0
            log_err("Invalid arguments");
127
0
            goto err;
128
0
    }
129
130
0
    out->mem = BUF_MEM_create_init(sec, sec_len);
131
0
    out->encoded = encoded_secret(out);
132
0
    if (!out->mem || !out->encoded)
133
0
        goto err;
134
135
0
    return out;
136
137
0
err:
138
0
    PACE_SEC_clear_free(out);
139
140
0
    return NULL;
141
0
}
142
143
static BUF_MEM *
144
encoded_secret(const PACE_SEC * pi)
145
0
{
146
    /* Encoding of the secret according to TR-03110 2.02 Table A3 */
147
0
    BUF_MEM * out;
148
149
0
    check_return(pi && pi->mem, "Invalid arguments");
150
151
0
    switch (pi->type) {
152
0
        case PACE_PUK:
153
0
        case PACE_CAN:
154
0
        case PACE_PIN:
155
0
            if (!is_char_str((unsigned char*) pi->mem->data, (size_t) pi->mem->length))
156
0
                return NULL;
157
            /* fall through */
158
0
        case PACE_RAW:
159
0
            out = BUF_MEM_create_init(pi->mem->data, pi->mem->length);
160
0
            break;
161
162
0
        case PACE_MRZ:
163
0
            out = encoded_mrz(pi->mem->data, pi->mem->length);
164
0
            break;
165
166
0
        default:
167
0
            log_err("Invalid arguments");
168
0
            return NULL;
169
0
    }
170
171
0
    return out;
172
0
}
173
174
static BUF_MEM *
175
encoded_mrz(const char *in, size_t len)
176
0
{
177
0
    const char *serial, *dob, *doe;
178
0
    BUF_MEM *cat = NULL, *out = NULL;
179
180
0
    check(in, "Invalid arguments");
181
182
    /* Parse MRZ */
183
0
    check((len >= MRZ_SERIALNUMBER_OFF + MRZ_SERIALNUMBER_LEN
184
0
            && len >= MRZ_DATEOFBIRTH_OFF + MRZ_DATEOFBIRTH_LEN
185
0
            && len >= MRZ_DATEOFEXPIRY_OFF + MRZ_DATEOFEXPIRY_LEN),
186
0
           "Invalid data");
187
188
0
    serial = in + MRZ_SERIALNUMBER_OFF;
189
0
    dob = in + MRZ_DATEOFBIRTH_OFF;
190
0
    doe = in + MRZ_DATEOFEXPIRY_OFF;
191
192
    /* Concatenate Serial Number || Date of Birth || Date of Expiry */
193
0
    cat = BUF_MEM_create(MRZ_SERIALNUMBER_LEN + MRZ_DATEOFBIRTH_LEN +
194
0
            MRZ_DATEOFEXPIRY_LEN);
195
0
    if (!cat)
196
0
        goto err;
197
0
    memcpy(cat->data, serial, MRZ_SERIALNUMBER_LEN);
198
0
    memcpy(cat->data + MRZ_SERIALNUMBER_LEN, dob, MRZ_DATEOFBIRTH_LEN);
199
0
    memcpy(cat->data + MRZ_SERIALNUMBER_LEN + MRZ_DATEOFBIRTH_LEN,
200
0
            doe, MRZ_DATEOFEXPIRY_LEN);
201
202
    /* Compute and output SHA1 hash of concatenation */
203
0
    out = hash(EVP_sha1(), NULL, NULL, cat);
204
205
0
err:
206
0
    if(cat) {
207
0
        OPENSSL_cleanse(cat->data, cat->length);
208
0
        BUF_MEM_free(cat);
209
0
    }
210
211
0
    return out;
212
0
}
213
214
void
215
PACE_CTX_clear_free(PACE_CTX * ctx)
216
0
{
217
0
    if (ctx) {
218
0
        BUF_MEM_clear_free(ctx->nonce);
219
0
        KA_CTX_clear_free(ctx->ka_ctx);
220
0
        if (ctx->static_key)
221
0
            EVP_PKEY_free(ctx->static_key);
222
0
        if (ctx->my_eph_pubkey)
223
0
            BUF_MEM_free(ctx->my_eph_pubkey);
224
0
        OPENSSL_free(ctx);
225
0
    }
226
0
}
227
228
PACE_CTX *
229
PACE_CTX_new(void)
230
0
{
231
0
    PACE_CTX *out = OPENSSL_zalloc(sizeof(PACE_CTX));
232
0
    check(out, "Out of memory");
233
234
0
    out->ka_ctx = KA_CTX_new();
235
0
    out->static_key = EVP_PKEY_new();
236
0
    if (!out->ka_ctx || !out->static_key)
237
0
        goto err;
238
239
0
    out->id = -1;
240
241
0
    return out;
242
243
0
err:
244
0
    if (out) {
245
0
        if (out->static_key)
246
0
            EVP_PKEY_free(out->static_key);
247
0
        KA_CTX_clear_free(out->ka_ctx);
248
0
        OPENSSL_free(out);
249
0
    }
250
251
0
    return NULL;
252
0
}
253
254
int
255
PACE_CTX_set_protocol(PACE_CTX * ctx, int protocol, enum eac_tr_version tr_version)
256
0
{
257
0
    if (!ctx) {
258
0
        log_err("Invalid arguments");
259
0
        return 0;
260
0
    }
261
0
    if (!KA_CTX_set_protocol(ctx->ka_ctx, protocol))
262
0
        return 0;
263
264
0
    if (protocol == NID_id_PACE_ECDH_GM_3DES_CBC_CBC
265
0
            || protocol == NID_id_PACE_ECDH_GM_AES_CBC_CMAC_128
266
0
            || protocol == NID_id_PACE_ECDH_GM_AES_CBC_CMAC_192
267
0
            || protocol == NID_id_PACE_ECDH_GM_AES_CBC_CMAC_256) {
268
0
        ctx->map_generate_key = ecdh_gm_generate_key;
269
0
        ctx->map_compute_key = ecdh_gm_compute_key;
270
271
0
    } else if (protocol == NID_id_PACE_DH_GM_3DES_CBC_CBC
272
0
            || protocol == NID_id_PACE_DH_GM_AES_CBC_CMAC_128
273
0
            || protocol == NID_id_PACE_DH_GM_AES_CBC_CMAC_192
274
0
            || protocol == NID_id_PACE_DH_GM_AES_CBC_CMAC_256) {
275
0
        ctx->map_generate_key = dh_gm_generate_key;
276
0
        ctx->map_compute_key = dh_gm_compute_key;
277
278
0
    } else if (protocol == NID_id_PACE_DH_IM_3DES_CBC_CBC
279
0
            || protocol == NID_id_PACE_DH_IM_AES_CBC_CMAC_128
280
0
            || protocol == NID_id_PACE_DH_IM_AES_CBC_CMAC_192
281
0
            || protocol == NID_id_PACE_DH_IM_AES_CBC_CMAC_256) {
282
0
        if (tr_version > EAC_TR_VERSION_2_01) {
283
0
            log_err("Invalid arguments");
284
0
            return 0;
285
0
        }
286
0
        ctx->map_generate_key = dh_im_generate_key;
287
0
        ctx->map_compute_key = dh_im_compute_key;
288
289
0
    } else if (protocol == NID_id_PACE_ECDH_IM_3DES_CBC_CBC
290
0
            || protocol == NID_id_PACE_ECDH_IM_AES_CBC_CMAC_128
291
0
            || protocol == NID_id_PACE_ECDH_IM_AES_CBC_CMAC_192
292
0
            || protocol == NID_id_PACE_ECDH_IM_AES_CBC_CMAC_256) {
293
0
        if (tr_version > EAC_TR_VERSION_2_01) {
294
0
            log_err("Invalid arguments");
295
0
            return 0;
296
0
        }
297
0
        ctx->map_generate_key = ecdh_im_generate_key;
298
0
        ctx->map_compute_key = ecdh_im_compute_key;
299
300
0
    } else {
301
0
        log_err("Invalid arguments");
302
0
        return 0;
303
0
    }
304
0
    ctx->protocol = protocol;
305
306
0
    return 1;
307
0
}