CT policy validation
[openssl.git] / crypto / ct / ct_log.c
1 /* Author: Adam Eijdenberg <adam.eijdenberg@gmail.com>. */
2 /* ====================================================================
3  * Copyright (c) 1998-2016 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    openssl-core@openssl.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55
56 #include <stdlib.h>
57 #include <string.h>
58
59 #include <openssl/conf.h>
60 #include <openssl/ct.h>
61 #include <openssl/err.h>
62 #include <openssl/evp.h>
63 #include <openssl/safestack.h>
64
65 #include "internal/cryptlib.h"
66
67 /*
68  * Information about a CT log server.
69  */
70 struct ctlog_st {
71     char *name;
72     uint8_t log_id[CT_V1_HASHLEN];
73     EVP_PKEY *public_key;
74 };
75
76 /*
77  * A store for multiple CTLOG instances.
78  * It takes ownership of any CTLOG instances added to it.
79  */
80 struct ctlog_store_st {
81     STACK_OF(CTLOG) *logs;
82 };
83
84 /* The context when loading a CT log list from a CONF file. */
85 typedef struct ctlog_store_load_ctx_st {
86     CTLOG_STORE *log_store;
87     CONF *conf;
88 } CTLOG_STORE_LOAD_CTX;
89
90 /*
91  * Creates an empty context for loading a CT log store.
92  * It should be populated before use.
93  */
94 static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new();
95
96 /*
97  * Deletes a CT log store load context.
98  * Does not delete any of the fields.
99  */
100 static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx);
101
102 static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new()
103 {
104     CTLOG_STORE_LOAD_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
105
106     if (ctx == NULL) {
107         CTerr(CT_F_CTLOG_STORE_LOAD_CTX_NEW, ERR_R_MALLOC_FAILURE);
108         goto err;
109     }
110
111     return ctx;
112 err:
113     ctlog_store_load_ctx_free(ctx);
114     return NULL;
115 }
116
117 static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx)
118 {
119     OPENSSL_free(ctx);
120 }
121
122 /* Converts a log's public key into a SHA256 log ID */
123 static int ct_v1_log_id_from_pkey(EVP_PKEY *pkey,
124                                   unsigned char log_id[CT_V1_HASHLEN])
125 {
126     int ret = 0;
127     unsigned char *pkey_der = NULL;
128     int pkey_der_len = i2d_PUBKEY(pkey, &pkey_der);
129
130     if (pkey_der_len <= 0) {
131         CTerr(CT_F_CT_V1_LOG_ID_FROM_PKEY, CT_R_LOG_KEY_INVALID);
132         goto err;
133     }
134
135     SHA256(pkey_der, pkey_der_len, log_id);
136     ret = 1;
137 err:
138     OPENSSL_free(pkey_der);
139     return ret;
140 }
141
142 CTLOG_STORE *CTLOG_STORE_new(void)
143 {
144     CTLOG_STORE *ret = OPENSSL_zalloc(sizeof(*ret));
145
146     if (ret == NULL)
147         goto err;
148
149     ret->logs = sk_CTLOG_new_null();
150     if (ret->logs == NULL)
151         goto err;
152
153     return ret;
154 err:
155     CTLOG_STORE_free(ret);
156     return NULL;
157 }
158
159 void CTLOG_STORE_free(CTLOG_STORE *store)
160 {
161     if (store != NULL) {
162         sk_CTLOG_pop_free(store->logs, CTLOG_free);
163         OPENSSL_free(store);
164     }
165 }
166
167 static CTLOG *ctlog_new_from_conf(const CONF *conf, const char *section)
168 {
169     CTLOG *ret = NULL;
170     char *description = NCONF_get_string(conf, section, "description");
171     char *pkey_base64;
172
173     if (description == NULL) {
174         CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_DESCRIPTION);
175         goto end;
176     }
177
178     pkey_base64 = NCONF_get_string(conf, section, "key");
179     if (pkey_base64 == NULL) {
180         CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_KEY);
181         goto end;
182     }
183
184     ret = CTLOG_new_from_base64(pkey_base64, description);
185     if (ret == NULL) {
186         CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_INVALID);
187         goto end;
188     }
189
190 end:
191     return ret;
192 }
193
194 int CTLOG_STORE_load_default_file(CTLOG_STORE *store)
195 {
196     const char *fpath = getenv(CTLOG_FILE_EVP);
197
198     if (fpath == NULL)
199       fpath = CTLOG_FILE;
200
201     return CTLOG_STORE_load_file(store, fpath);
202 }
203
204 static int ctlog_store_load_log(const char *log_name, int log_name_len, void *arg)
205 {
206     CTLOG_STORE_LOAD_CTX *load_ctx = arg;
207     CTLOG *ct_log;
208     /* log_name may not be null-terminated, so fix that before using it */
209     char *tmp = OPENSSL_strndup(log_name, log_name_len);
210
211     ct_log = ctlog_new_from_conf(load_ctx->conf, tmp);
212     OPENSSL_free(tmp);
213     if (ct_log == NULL)
214         return 0;
215
216     sk_CTLOG_push(load_ctx->log_store->logs, ct_log);
217     return 1;
218 }
219
220 int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file)
221 {
222     int ret = -1;
223     char *enabled_logs;
224     CTLOG_STORE_LOAD_CTX* load_ctx = ctlog_store_load_ctx_new();
225
226     load_ctx->log_store = store;
227     load_ctx->conf = NCONF_new(NULL);
228     if (load_ctx->conf == NULL)
229         goto end;
230
231     ret = NCONF_load(load_ctx->conf, file, NULL);
232     if (ret <= 0) {
233         CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID);
234         goto end;
235     }
236
237     enabled_logs = NCONF_get_string(load_ctx->conf, NULL, "enabled_logs");
238     CONF_parse_list(enabled_logs, ',', 1, ctlog_store_load_log, load_ctx);
239
240 end:
241     NCONF_free(load_ctx->conf);
242     ctlog_store_load_ctx_free(load_ctx);
243     return ret;
244 }
245
246 /*
247  * Initialize a new CTLOG object.
248  * Takes ownership of the public key.
249  * Copies the name.
250  */
251 CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name)
252 {
253     CTLOG *ret = CTLOG_new_null();
254
255     if (ret == NULL)
256         goto err;
257
258     ret->name = OPENSSL_strdup(name);
259     if (ret->name == NULL)
260         goto err;
261
262     ret->public_key = public_key;
263     if (ct_v1_log_id_from_pkey(public_key, ret->log_id) != 1)
264         goto err;
265
266     return ret;
267 err:
268     CTLOG_free(ret);
269     return NULL;
270 }
271
272 CTLOG *CTLOG_new_null(void)
273 {
274     CTLOG *ret = OPENSSL_zalloc(sizeof(*ret));
275
276     if (ret == NULL)
277         CTerr(CT_F_CTLOG_NEW_NULL, ERR_R_MALLOC_FAILURE);
278
279     return ret;
280 }
281
282 /* Frees CT log and associated structures */
283 void CTLOG_free(CTLOG *log)
284 {
285     if (log != NULL) {
286         OPENSSL_free(log->name);
287         EVP_PKEY_free(log->public_key);
288         OPENSSL_free(log);
289     }
290 }
291
292 const char *CTLOG_get0_name(CTLOG *log)
293 {
294     return log->name;
295 }
296
297 void CTLOG_get0_log_id(CTLOG *log, uint8_t **log_id, size_t *log_id_len)
298 {
299     *log_id = log->log_id;
300     *log_id_len = CT_V1_HASHLEN;
301 }
302
303 EVP_PKEY *CTLOG_get0_public_key(CTLOG *log)
304 {
305     return log->public_key;
306 }
307
308 /*
309  * Given a log ID, finds the matching log.
310  * Returns NULL if no match found.
311  */
312 CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store,
313                                   const uint8_t *log_id,
314                                   size_t log_id_len)
315 {
316     int i;
317
318     for (i = 0; i < sk_CTLOG_num(store->logs); ++i) {
319         CTLOG *log = sk_CTLOG_value(store->logs, i);
320         if (memcmp(log->log_id, log_id, log_id_len) == 0)
321             return log;
322     }
323
324     return NULL;
325 }