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