Coverage Report

Created: 2022-08-24 06:31

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