diff options
Diffstat (limited to 'openssl-1.1.0h/crypto/ct/ct_log.c')
-rw-r--r-- | openssl-1.1.0h/crypto/ct/ct_log.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/openssl-1.1.0h/crypto/ct/ct_log.c b/openssl-1.1.0h/crypto/ct/ct_log.c new file mode 100644 index 0000000..d442322 --- /dev/null +++ b/openssl-1.1.0h/crypto/ct/ct_log.c @@ -0,0 +1,306 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <string.h> + +#include <openssl/conf.h> +#include <openssl/ct.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/safestack.h> + +#include "internal/cryptlib.h" + +/* + * Information about a CT log server. + */ +struct ctlog_st { + char *name; + uint8_t log_id[CT_V1_HASHLEN]; + EVP_PKEY *public_key; +}; + +/* + * A store for multiple CTLOG instances. + * It takes ownership of any CTLOG instances added to it. + */ +struct ctlog_store_st { + STACK_OF(CTLOG) *logs; +}; + +/* The context when loading a CT log list from a CONF file. */ +typedef struct ctlog_store_load_ctx_st { + CTLOG_STORE *log_store; + CONF *conf; + size_t invalid_log_entries; +} CTLOG_STORE_LOAD_CTX; + +/* + * Creates an empty context for loading a CT log store. + * It should be populated before use. + */ +static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new(); + +/* + * Deletes a CT log store load context. + * Does not delete any of the fields. + */ +static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx); + +static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new() +{ + CTLOG_STORE_LOAD_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx == NULL) + CTerr(CT_F_CTLOG_STORE_LOAD_CTX_NEW, ERR_R_MALLOC_FAILURE); + + return ctx; +} + +static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx) +{ + OPENSSL_free(ctx); +} + +/* Converts a log's public key into a SHA256 log ID */ +static int ct_v1_log_id_from_pkey(EVP_PKEY *pkey, + unsigned char log_id[CT_V1_HASHLEN]) +{ + int ret = 0; + unsigned char *pkey_der = NULL; + int pkey_der_len = i2d_PUBKEY(pkey, &pkey_der); + + if (pkey_der_len <= 0) { + CTerr(CT_F_CT_V1_LOG_ID_FROM_PKEY, CT_R_LOG_KEY_INVALID); + goto err; + } + + SHA256(pkey_der, pkey_der_len, log_id); + ret = 1; +err: + OPENSSL_free(pkey_der); + return ret; +} + +CTLOG_STORE *CTLOG_STORE_new(void) +{ + CTLOG_STORE *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) { + CTerr(CT_F_CTLOG_STORE_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->logs = sk_CTLOG_new_null(); + if (ret->logs == NULL) + goto err; + + return ret; +err: + OPENSSL_free(ret); + return NULL; +} + +void CTLOG_STORE_free(CTLOG_STORE *store) +{ + if (store != NULL) { + sk_CTLOG_pop_free(store->logs, CTLOG_free); + OPENSSL_free(store); + } +} + +static int ctlog_new_from_conf(CTLOG **ct_log, const CONF *conf, const char *section) +{ + const char *description = NCONF_get_string(conf, section, "description"); + char *pkey_base64; + + if (description == NULL) { + CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_DESCRIPTION); + return 0; + } + + pkey_base64 = NCONF_get_string(conf, section, "key"); + if (pkey_base64 == NULL) { + CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_KEY); + return 0; + } + + return CTLOG_new_from_base64(ct_log, pkey_base64, description); +} + +int CTLOG_STORE_load_default_file(CTLOG_STORE *store) +{ + const char *fpath = getenv(CTLOG_FILE_EVP); + + if (fpath == NULL) + fpath = CTLOG_FILE; + + return CTLOG_STORE_load_file(store, fpath); +} + +/* + * Called by CONF_parse_list, which stops if this returns <= 0, + * Otherwise, one bad log entry would stop loading of any of + * the following log entries. + * It may stop parsing and returns -1 on any internal (malloc) error. + */ +static int ctlog_store_load_log(const char *log_name, int log_name_len, + void *arg) +{ + CTLOG_STORE_LOAD_CTX *load_ctx = arg; + CTLOG *ct_log = NULL; + /* log_name may not be null-terminated, so fix that before using it */ + char *tmp; + int ret = 0; + + /* log_name will be NULL for empty list entries */ + if (log_name == NULL) + return 1; + + tmp = OPENSSL_strndup(log_name, log_name_len); + if (tmp == NULL) + goto mem_err; + + ret = ctlog_new_from_conf(&ct_log, load_ctx->conf, tmp); + OPENSSL_free(tmp); + + if (ret < 0) { + /* Propagate any internal error */ + return ret; + } + if (ret == 0) { + /* If we can't load this log, record that fact and skip it */ + ++load_ctx->invalid_log_entries; + return 1; + } + + if (!sk_CTLOG_push(load_ctx->log_store->logs, ct_log)) { + goto mem_err; + } + return 1; + +mem_err: + CTLOG_free(ct_log); + CTerr(CT_F_CTLOG_STORE_LOAD_LOG, ERR_R_MALLOC_FAILURE); + return -1; +} + +int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file) +{ + int ret = 0; + char *enabled_logs; + CTLOG_STORE_LOAD_CTX* load_ctx = ctlog_store_load_ctx_new(); + + if (load_ctx == NULL) + return 0; + load_ctx->log_store = store; + load_ctx->conf = NCONF_new(NULL); + if (load_ctx->conf == NULL) + goto end; + + if (NCONF_load(load_ctx->conf, file, NULL) <= 0) { + CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID); + goto end; + } + + enabled_logs = NCONF_get_string(load_ctx->conf, NULL, "enabled_logs"); + if (enabled_logs == NULL) { + CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID); + goto end; + } + + if (!CONF_parse_list(enabled_logs, ',', 1, ctlog_store_load_log, load_ctx) || + load_ctx->invalid_log_entries > 0) { + CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID); + goto end; + } + + ret = 1; +end: + NCONF_free(load_ctx->conf); + ctlog_store_load_ctx_free(load_ctx); + return ret; +} + +/* + * Initialize a new CTLOG object. + * Takes ownership of the public key. + * Copies the name. + */ +CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name) +{ + CTLOG *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) { + CTerr(CT_F_CTLOG_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->name = OPENSSL_strdup(name); + if (ret->name == NULL) { + CTerr(CT_F_CTLOG_NEW, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (ct_v1_log_id_from_pkey(public_key, ret->log_id) != 1) + goto err; + + ret->public_key = public_key; + return ret; +err: + CTLOG_free(ret); + return NULL; +} + +/* Frees CT log and associated structures */ +void CTLOG_free(CTLOG *log) +{ + if (log != NULL) { + OPENSSL_free(log->name); + EVP_PKEY_free(log->public_key); + OPENSSL_free(log); + } +} + +const char *CTLOG_get0_name(const CTLOG *log) +{ + return log->name; +} + +void CTLOG_get0_log_id(const CTLOG *log, const uint8_t **log_id, + size_t *log_id_len) +{ + *log_id = log->log_id; + *log_id_len = CT_V1_HASHLEN; +} + +EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log) +{ + return log->public_key; +} + +/* + * Given a log ID, finds the matching log. + * Returns NULL if no match found. + */ +const CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store, + const uint8_t *log_id, + size_t log_id_len) +{ + int i; + + for (i = 0; i < sk_CTLOG_num(store->logs); ++i) { + const CTLOG *log = sk_CTLOG_value(store->logs, i); + if (memcmp(log->log_id, log_id, log_id_len) == 0) + return log; + } + + return NULL; +} |