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