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