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 */ 24struct 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 */ 36struct 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. */ 43typedef 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 */ 53static 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 */ 59static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx); 60 61static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new(void) 62{ 63 CTLOG_STORE_LOAD_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 64 65 if (ctx == NULL) 66 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 67 68 return ctx; 69} 70 71static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx) 72{ 73 OPENSSL_free(ctx); 74} 75 76/* Converts a log's public key into a SHA256 log ID */ 77static int ct_v1_log_id_from_pkey(CTLOG *log, EVP_PKEY *pkey) 78{ 79 int ret = 0; 80 unsigned char *pkey_der = NULL; 81 int pkey_der_len = i2d_PUBKEY(pkey, &pkey_der); 82 unsigned int len; 83 EVP_MD *sha256 = NULL; 84 85 if (pkey_der_len <= 0) { 86 ERR_raise(ERR_LIB_CT, CT_R_LOG_KEY_INVALID); 87 goto err; 88 } 89 sha256 = EVP_MD_fetch(log->libctx, "SHA2-256", log->propq); 90 if (sha256 == NULL) { 91 ERR_raise(ERR_LIB_CT, ERR_R_EVP_LIB); 92 goto err; 93 } 94 95 ret = EVP_Digest(pkey_der, pkey_der_len, log->log_id, &len, sha256, 96 NULL); 97err: 98 EVP_MD_free(sha256); 99 OPENSSL_free(pkey_der); 100 return ret; 101} 102 103CTLOG_STORE *CTLOG_STORE_new_ex(OSSL_LIB_CTX *libctx, const char *propq) 104{ 105 CTLOG_STORE *ret = OPENSSL_zalloc(sizeof(*ret)); 106 107 if (ret == NULL) { 108 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 109 return NULL; 110 } 111 112 ret->libctx = libctx; 113 if (propq != NULL) { 114 ret->propq = OPENSSL_strdup(propq); 115 if (ret->propq == NULL) { 116 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 117 goto err; 118 } 119 } 120 121 ret->logs = sk_CTLOG_new_null(); 122 if (ret->logs == NULL) { 123 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 124 goto err; 125 } 126 127 return ret; 128err: 129 CTLOG_STORE_free(ret); 130 return NULL; 131} 132 133CTLOG_STORE *CTLOG_STORE_new(void) 134{ 135 return CTLOG_STORE_new_ex(NULL, NULL); 136} 137 138void CTLOG_STORE_free(CTLOG_STORE *store) 139{ 140 if (store != NULL) { 141 OPENSSL_free(store->propq); 142 sk_CTLOG_pop_free(store->logs, CTLOG_free); 143 OPENSSL_free(store); 144 } 145} 146 147static int ctlog_new_from_conf(CTLOG_STORE *store, CTLOG **ct_log, 148 const CONF *conf, const char *section) 149{ 150 const char *description = NCONF_get_string(conf, section, "description"); 151 char *pkey_base64; 152 153 if (description == NULL) { 154 ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_MISSING_DESCRIPTION); 155 return 0; 156 } 157 158 pkey_base64 = NCONF_get_string(conf, section, "key"); 159 if (pkey_base64 == NULL) { 160 ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_MISSING_KEY); 161 return 0; 162 } 163 164 return CTLOG_new_from_base64_ex(ct_log, pkey_base64, description, 165 store->libctx, store->propq); 166} 167 168int CTLOG_STORE_load_default_file(CTLOG_STORE *store) 169{ 170 const char *fpath = ossl_safe_getenv(CTLOG_FILE_EVP); 171 172 if (fpath == NULL) 173 fpath = CTLOG_FILE; 174 175 return CTLOG_STORE_load_file(store, fpath); 176} 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 */ 184static int ctlog_store_load_log(const char *log_name, int log_name_len, 185 void *arg) 186{ 187 CTLOG_STORE_LOAD_CTX *load_ctx = arg; 188 CTLOG *ct_log = NULL; 189 /* log_name may not be null-terminated, so fix that before using it */ 190 char *tmp; 191 int ret = 0; 192 193 /* log_name will be NULL for empty list entries */ 194 if (log_name == NULL) 195 return 1; 196 197 tmp = OPENSSL_strndup(log_name, log_name_len); 198 if (tmp == NULL) 199 goto mem_err; 200 201 ret = ctlog_new_from_conf(load_ctx->log_store, &ct_log, load_ctx->conf, tmp); 202 OPENSSL_free(tmp); 203 204 if (ret < 0) { 205 /* Propagate any internal error */ 206 return ret; 207 } 208 if (ret == 0) { 209 /* If we can't load this log, record that fact and skip it */ 210 ++load_ctx->invalid_log_entries; 211 return 1; 212 } 213 214 if (!sk_CTLOG_push(load_ctx->log_store->logs, ct_log)) { 215 goto mem_err; 216 } 217 return 1; 218 219mem_err: 220 CTLOG_free(ct_log); 221 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 222 return -1; 223} 224 225int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file) 226{ 227 int ret = 0; 228 char *enabled_logs; 229 CTLOG_STORE_LOAD_CTX* load_ctx = ctlog_store_load_ctx_new(); 230 231 if (load_ctx == NULL) 232 return 0; 233 load_ctx->log_store = store; 234 load_ctx->conf = NCONF_new(NULL); 235 if (load_ctx->conf == NULL) 236 goto end; 237 238 if (NCONF_load(load_ctx->conf, file, NULL) <= 0) { 239 ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_INVALID); 240 goto end; 241 } 242 243 enabled_logs = NCONF_get_string(load_ctx->conf, NULL, "enabled_logs"); 244 if (enabled_logs == NULL) { 245 ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_INVALID); 246 goto end; 247 } 248 249 if (!CONF_parse_list(enabled_logs, ',', 1, ctlog_store_load_log, load_ctx) || 250 load_ctx->invalid_log_entries > 0) { 251 ERR_raise(ERR_LIB_CT, CT_R_LOG_CONF_INVALID); 252 goto end; 253 } 254 255 ret = 1; 256end: 257 NCONF_free(load_ctx->conf); 258 ctlog_store_load_ctx_free(load_ctx); 259 return ret; 260} 261 262/* 263 * Initialize a new CTLOG object. 264 * Takes ownership of the public key. 265 * Copies the name. 266 */ 267CTLOG *CTLOG_new_ex(EVP_PKEY *public_key, const char *name, OSSL_LIB_CTX *libctx, 268 const char *propq) 269{ 270 CTLOG *ret = OPENSSL_zalloc(sizeof(*ret)); 271 272 if (ret == NULL) { 273 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 274 return NULL; 275 } 276 277 ret->libctx = libctx; 278 if (propq != NULL) { 279 ret->propq = OPENSSL_strdup(propq); 280 if (ret->propq == NULL) { 281 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 282 goto err; 283 } 284 } 285 286 ret->name = OPENSSL_strdup(name); 287 if (ret->name == NULL) { 288 ERR_raise(ERR_LIB_CT, ERR_R_MALLOC_FAILURE); 289 goto err; 290 } 291 292 if (ct_v1_log_id_from_pkey(ret, public_key) != 1) 293 goto err; 294 295 ret->public_key = public_key; 296 return ret; 297err: 298 CTLOG_free(ret); 299 return NULL; 300} 301 302CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name) 303{ 304 return CTLOG_new_ex(public_key, name, NULL, NULL); 305} 306 307/* Frees CT log and associated structures */ 308void CTLOG_free(CTLOG *log) 309{ 310 if (log != NULL) { 311 OPENSSL_free(log->name); 312 EVP_PKEY_free(log->public_key); 313 OPENSSL_free(log->propq); 314 OPENSSL_free(log); 315 } 316} 317 318const char *CTLOG_get0_name(const CTLOG *log) 319{ 320 return log->name; 321} 322 323void CTLOG_get0_log_id(const CTLOG *log, const uint8_t **log_id, 324 size_t *log_id_len) 325{ 326 *log_id = log->log_id; 327 *log_id_len = CT_V1_HASHLEN; 328} 329 330EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log) 331{ 332 return log->public_key; 333} 334 335/* 336 * Given a log ID, finds the matching log. 337 * Returns NULL if no match found. 338 */ 339const CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store, 340 const uint8_t *log_id, 341 size_t log_id_len) 342{ 343 int i; 344 345 for (i = 0; i < sk_CTLOG_num(store->logs); ++i) { 346 const CTLOG *log = sk_CTLOG_value(store->logs, i); 347 if (memcmp(log->log_id, log_id, log_id_len) == 0) 348 return log; 349 } 350 351 return NULL; 352} 353