Coverage Report

Created: 2025-06-13 06:58

/src/openssl31/crypto/ct/ct_log.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <stdlib.h>
11
#include <string.h>
12
13
#include <openssl/conf.h>
14
#include <openssl/ct.h>
15
#include <openssl/err.h>
16
#include <openssl/evp.h>
17
#include <openssl/safestack.h>
18
19
#include "internal/cryptlib.h"
20
21
/*
22
 * Information about a CT log server.
23
 */
24
struct ctlog_st {
25
    OSSL_LIB_CTX *libctx;
26
    char *propq;
27
    char *name;
28
    uint8_t log_id[CT_V1_HASHLEN];
29
    EVP_PKEY *public_key;
30
};
31
32
/*
33
 * A store for multiple CTLOG instances.
34
 * It takes ownership of any CTLOG instances added to it.
35
 */
36
struct ctlog_store_st {
37
    OSSL_LIB_CTX *libctx;
38
    char *propq;
39
    STACK_OF(CTLOG) *logs;
40
};
41
42
/* The context when loading a CT log list from a CONF file. */
43
typedef struct ctlog_store_load_ctx_st {
44
    CTLOG_STORE *log_store;
45
    CONF *conf;
46
    size_t invalid_log_entries;
47
} CTLOG_STORE_LOAD_CTX;
48
49
/*
50
 * Creates an empty context for loading a CT log store.
51
 * It should be populated before use.
52
 */
53
static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new(void);
54
55
/*
56
 * Deletes a CT log store load context.
57
 * Does not delete any of the fields.
58
 */
59
static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx);
60
61
static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new(void)
62
0
{
63
0
    CTLOG_STORE_LOAD_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
64
65
0
    if (ctx == NULL)
66
0
        ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
67
68
0
    return ctx;
69
0
}
70
71
static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx)
72
0
{
73
0
    OPENSSL_free(ctx);
74
0
}
75
76
/* Converts a log's public key into a SHA256 log ID */
77
static int ct_v1_log_id_from_pkey(CTLOG *log, EVP_PKEY *pkey)
78
0
{
79
0
    int ret = 0;
80
0
    unsigned char *pkey_der = NULL;
81
0
    int pkey_der_len = i2d_PUBKEY(pkey, &pkey_der);
82
0
    unsigned int len;
83
0
    EVP_MD *sha256 = NULL;
84
85
0
    if (pkey_der_len <= 0) {
86
0
        ERR_raise(ERR_LIB_CT, CT_R_LOG_KEY_INVALID);
87
0
        goto err;
88
0
    }
89
0
    sha256 = EVP_MD_fetch(log->libctx, "SHA2-256", log->propq);
90
0
    if (sha256 == NULL) {
91
0
        ERR_raise(ERR_LIB_CT, ERR_R_EVP_LIB);
92
0
        goto err;
93
0
    }
94
95
0
    ret = EVP_Digest(pkey_der, pkey_der_len, log->log_id, &len, sha256,
96
0
                     NULL);
97
0
err:
98
0
    EVP_MD_free(sha256);
99
0
    OPENSSL_free(pkey_der);
100
0
    return ret;
101
0
}
102
103
CTLOG_STORE *CTLOG_STORE_new_ex(OSSL_LIB_CTX *libctx, const char *propq)
104
79.3k
{
105
79.3k
    CTLOG_STORE *ret = OPENSSL_zalloc(sizeof(*ret));
106
107
79.3k
    if (ret == NULL) {
108
0
        ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
109
0
        return NULL;
110
0
    }
111
112
79.3k
    ret->libctx = libctx;
113
79.3k
    if (propq != NULL) {
114
0
        ret->propq = OPENSSL_strdup(propq);
115
0
        if (ret->propq == NULL) {
116
0
            ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
117
0
            goto err;
118
0
        }
119
0
    }
120
121
79.3k
    ret->logs = sk_CTLOG_new_null();
122
79.3k
    if (ret->logs == NULL) {
123
0
        ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
124
0
        goto err;
125
0
    }
126
127
79.3k
    return ret;
128
0
err:
129
0
    CTLOG_STORE_free(ret);
130
0
    return NULL;
131
79.3k
}
132
133
CTLOG_STORE *CTLOG_STORE_new(void)
134
0
{
135
0
    return CTLOG_STORE_new_ex(NULL, NULL);
136
0
}
137
138
void CTLOG_STORE_free(CTLOG_STORE *store)
139
79.3k
{
140
79.3k
    if (store != NULL) {
141
79.3k
        OPENSSL_free(store->propq);
142
79.3k
        sk_CTLOG_pop_free(store->logs, CTLOG_free);
143
79.3k
        OPENSSL_free(store);
144
79.3k
    }
145
79.3k
}
146
147
static int ctlog_new_from_conf(CTLOG_STORE *store, CTLOG **ct_log,
148
                               const CONF *conf, const char *section)
149
0
{
150
0
    const char *description = NCONF_get_string(conf, section, "description");
151
0
    char *pkey_base64;
152
153
0
    if (description == NULL) {
154
0
        ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_MISSING_DESCRIPTION);
155
0
        return 0;
156
0
    }
157
158
0
    pkey_base64 = NCONF_get_string(conf, section, "key");
159
0
    if (pkey_base64 == NULL) {
160
0
        ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_MISSING_KEY);
161
0
        return 0;
162
0
    }
163
164
0
    return CTLOG_new_from_base64_ex(ct_log, pkey_base64, description,
165
0
                                    store->libctx, store->propq);
166
0
}
167
168
int CTLOG_STORE_load_default_file(CTLOG_STORE *store)
169
0
{
170
0
    const char *fpath = ossl_safe_getenv(CTLOG_FILE_EVP);
171
172
0
    if (fpath == NULL)
173
0
      fpath = CTLOG_FILE;
174
175
0
    return CTLOG_STORE_load_file(store, fpath);
176
0
}
177
178
/*
179
 * Called by CONF_parse_list, which stops if this returns <= 0,
180
 * Otherwise, one bad log entry would stop loading of any of
181
 * the following log entries.
182
 * It may stop parsing and returns -1 on any internal (malloc) error.
183
 */
184
static int ctlog_store_load_log(const char *log_name, int log_name_len,
185
                                void *arg)
186
0
{
187
0
    CTLOG_STORE_LOAD_CTX *load_ctx = arg;
188
0
    CTLOG *ct_log = NULL;
189
    /* log_name may not be null-terminated, so fix that before using it */
190
0
    char *tmp;
191
0
    int ret = 0;
192
193
    /* log_name will be NULL for empty list entries */
194
0
    if (log_name == NULL)
195
0
        return 1;
196
197
0
    tmp = OPENSSL_strndup(log_name, log_name_len);
198
0
    if (tmp == NULL)
199
0
        goto mem_err;
200
201
0
    ret = ctlog_new_from_conf(load_ctx->log_store, &ct_log, load_ctx->conf, tmp);
202
0
    OPENSSL_free(tmp);
203
204
0
    if (ret < 0) {
205
        /* Propagate any internal error */
206
0
        return ret;
207
0
    }
208
0
    if (ret == 0) {
209
        /* If we can't load this log, record that fact and skip it */
210
0
        ++load_ctx->invalid_log_entries;
211
0
        return 1;
212
0
    }
213
214
0
    if (!sk_CTLOG_push(load_ctx->log_store->logs, ct_log)) {
215
0
        goto mem_err;
216
0
    }
217
0
    return 1;
218
219
0
mem_err:
220
0
    CTLOG_free(ct_log);
221
0
    ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
222
0
    return -1;
223
0
}
224
225
int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file)
226
0
{
227
0
    int ret = 0;
228
0
    char *enabled_logs;
229
0
    CTLOG_STORE_LOAD_CTX* load_ctx = ctlog_store_load_ctx_new();
230
231
0
    if (load_ctx == NULL)
232
0
        return 0;
233
0
    load_ctx->log_store = store;
234
0
    load_ctx->conf = NCONF_new(NULL);
235
0
    if (load_ctx->conf == NULL)
236
0
        goto end;
237
238
0
    if (NCONF_load(load_ctx->conf, file, NULL) <= 0) {
239
0
        ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_INVALID);
240
0
        goto end;
241
0
    }
242
243
0
    enabled_logs = NCONF_get_string(load_ctx->conf, NULL, "enabled_logs");
244
0
    if (enabled_logs == NULL) {
245
0
        ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_INVALID);
246
0
        goto end;
247
0
    }
248
249
0
    if (!CONF_parse_list(enabled_logs, ',', 1, ctlog_store_load_log, load_ctx) ||
250
0
        load_ctx->invalid_log_entries > 0) {
251
0
        ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_INVALID);
252
0
        goto end;
253
0
    }
254
255
0
    ret = 1;
256
0
end:
257
0
    NCONF_free(load_ctx->conf);
258
0
    ctlog_store_load_ctx_free(load_ctx);
259
0
    return ret;
260
0
}
261
262
/*
263
 * Initialize a new CTLOG object.
264
 * Takes ownership of the public key.
265
 * Copies the name.
266
 */
267
CTLOG *CTLOG_new_ex(EVP_PKEY *public_key, const char *name, OSSL_LIB_CTX *libctx,
268
                    const char *propq)
269
0
{
270
0
    CTLOG *ret = OPENSSL_zalloc(sizeof(*ret));
271
272
0
    if (ret == NULL) {
273
0
        ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
274
0
        return NULL;
275
0
    }
276
277
0
    ret->libctx = libctx;
278
0
    if (propq != NULL) {
279
0
        ret->propq = OPENSSL_strdup(propq);
280
0
        if (ret->propq == NULL) {
281
0
            ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
282
0
            goto err;
283
0
        }
284
0
    }
285
286
0
    ret->name = OPENSSL_strdup(name);
287
0
    if (ret->name == NULL) {
288
0
        ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE);
289
0
        goto err;
290
0
    }
291
292
0
    if (ct_v1_log_id_from_pkey(ret, public_key) != 1)
293
0
        goto err;
294
295
0
    ret->public_key = public_key;
296
0
    return ret;
297
0
err:
298
0
    CTLOG_free(ret);
299
0
    return NULL;
300
0
}
301
302
CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name)
303
0
{
304
0
    return CTLOG_new_ex(public_key, name, NULL, NULL);
305
0
}
306
307
/* Frees CT log and associated structures */
308
void CTLOG_free(CTLOG *log)
309
0
{
310
0
    if (log != NULL) {
311
0
        OPENSSL_free(log->name);
312
0
        EVP_PKEY_free(log->public_key);
313
0
        OPENSSL_free(log->propq);
314
0
        OPENSSL_free(log);
315
0
    }
316
0
}
317
318
const char *CTLOG_get0_name(const CTLOG *log)
319
0
{
320
0
    return log->name;
321
0
}
322
323
void CTLOG_get0_log_id(const CTLOG *log, const uint8_t **log_id,
324
                       size_t *log_id_len)
325
0
{
326
0
    *log_id = log->log_id;
327
0
    *log_id_len = CT_V1_HASHLEN;
328
0
}
329
330
EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log)
331
0
{
332
0
    return log->public_key;
333
0
}
334
335
/*
336
 * Given a log ID, finds the matching log.
337
 * Returns NULL if no match found.
338
 */
339
const CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store,
340
                                        const uint8_t *log_id,
341
                                        size_t log_id_len)
342
0
{
343
0
    int i;
344
345
0
    for (i = 0; i < sk_CTLOG_num(store->logs); ++i) {
346
0
        const CTLOG *log = sk_CTLOG_value(store->logs, i);
347
0
        if (memcmp(log->log_id, log_id, log_id_len) == 0)
348
0
            return log;
349
0
    }
350
351
0
    return NULL;
352
0
}