diff options
author | Rob Percival <robpercival@google.com> | 2016-02-25 13:33:48 +0000 |
---|---|---|
committer | Rich Salz <rsalz@openssl.org> | 2016-03-01 11:59:28 -0500 |
commit | 8c6afbc55cc8e2d036c0af5adbaff82d8117c6b2 (patch) | |
tree | 29f5feb6cf77df46204d65a6dcb6e1af65aedb06 /crypto/ct/ct_log.c | |
parent | 09375d12fb684c6991c06b473664a0630b8b2edf (diff) | |
download | openssl-8c6afbc55cc8e2d036c0af5adbaff82d8117c6b2.tar.gz |
Verify SCT signatures
Tests included in future commit, which adds CT policy validation.
Reviewed-by: Ben Laurie <ben@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
Diffstat (limited to 'crypto/ct/ct_log.c')
-rw-r--r-- | crypto/ct/ct_log.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/crypto/ct/ct_log.c b/crypto/ct/ct_log.c new file mode 100644 index 0000000000..aa3afc4ce3 --- /dev/null +++ b/crypto/ct/ct_log.c @@ -0,0 +1,330 @@ +/* Author: Adam Eijdenberg <adam.eijdenberg@gmail.com>. */ +/* ==================================================================== + * Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#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; +} 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(CTLOG_STORE_LOAD_CTX)); + if (ctx == NULL) { + CTerr(CT_F_CTLOG_STORE_LOAD_CTX_NEW, ERR_R_MALLOC_FAILURE); + goto err; + } + + return ctx; + +err: + CTLOG_STORE_LOAD_CTX_free(ctx); + return NULL; +} + +static void CTLOG_STORE_LOAD_CTX_free(CTLOG_STORE_LOAD_CTX* ctx) +{ + if (ctx == NULL) + return; + + 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_malloc(sizeof(CTLOG_STORE)); + if (ret == NULL) + goto err; + ret->logs = sk_CTLOG_new_null(); + if (ret->logs == NULL) + goto err; + return ret; +err: + CTLOG_STORE_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 CTLOG *CTLOG_new_from_conf(const CONF *conf, const char *section) +{ + CTLOG *ret = NULL; + char *description; + char *pkey_base64; + if (conf == NULL || section == NULL) { + CTerr(CT_F_CTLOG_NEW_FROM_CONF, ERR_R_PASSED_NULL_PARAMETER); + goto end; + } + + description = NCONF_get_string(conf, section, "description"); + + if (description == NULL) { + CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_DESCRIPTION); + goto end; + } + + 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); + goto end; + } + + ret = CTLOG_new_from_base64(pkey_base64, description); + if (ret == NULL) { + CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_INVALID); + goto end; + } + +end: + return ret; +} + +int CTLOG_STORE_load_default_file(CTLOG_STORE *store) +{ + char *fpath = (char *)getenv(CTLOG_FILE_EVP); + if (fpath == NULL) + fpath = CTLOG_FILE; + return CTLOG_STORE_load_file(store, fpath); +} + +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; + + /* log_name may not be null-terminated, so fix that before using it */ + char *tmp = OPENSSL_strndup(log_name, log_name_len); + ct_log = CTLOG_new_from_conf(load_ctx->conf, tmp); + OPENSSL_free(tmp); + if (ct_log == NULL) + return 0; + + sk_CTLOG_push(load_ctx->log_store->logs, ct_log); + return 1; +} + +int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file) +{ + int ret = -1; + char *enabled_logs; + CTLOG_STORE_LOAD_CTX* load_ctx = CTLOG_STORE_LOAD_CTX_new(); + load_ctx->log_store = store; + load_ctx->conf = NCONF_new(NULL); + if (load_ctx->conf == NULL) + goto end; + + ret = NCONF_load(load_ctx->conf, file, NULL); + if (ret <= 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"); + CONF_parse_list(enabled_logs, ',', 1, CTLOG_STORE_load_log, load_ctx); + +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 = NULL; + if (public_key == NULL || name == NULL) { + CTerr(CT_F_CTLOG_NEW, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + ret = CTLOG_new_null(); + if (ret == NULL) + goto err; + ret->name = OPENSSL_strdup(name); + if (ret->name == NULL) + goto err; + ret->public_key = public_key; + if (CT_v1_log_id_from_pkey(public_key, ret->log_id) != 1) + goto err; + return ret; +err: + CTLOG_free(ret); + return NULL; +} + +CTLOG *CTLOG_new_null(void) +{ + CTLOG *ret = OPENSSL_zalloc(sizeof(CTLOG)); + if (ret == NULL) + CTerr(CT_F_CTLOG_NEW_NULL, ERR_R_MALLOC_FAILURE); + return ret; +} + +/* Frees CT log and associated structures */ +void CTLOG_free(CTLOG *log) +{ + if (log != NULL) { + OPENSSL_free(log->name); + log->name = NULL; + + EVP_PKEY_free(log->public_key); + log->public_key = NULL; + + OPENSSL_free(log); + } +} + +const char *CTLOG_get0_name(CTLOG *log) +{ + return log->name; +} + +void CTLOG_get0_log_id(CTLOG *log, 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(CTLOG *log) +{ + return log->public_key; +} + +/* + * Given a log ID, finds the matching log. + * Returns NULL if no match found. + */ +CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store, + const uint8_t *log_id, + size_t log_id_len) +{ + int i; + if (store == NULL) { + CTerr(CT_F_CTLOG_STORE_GET0_LOG_BY_ID, ERR_R_PASSED_NULL_PARAMETER); + goto end; + } + for (i = 0; i < sk_CTLOG_num(store->logs); ++i) { + CTLOG *log = sk_CTLOG_value(store->logs, i); + if (memcmp(log->log_id, log_id, log_id_len) == 0) + return log; + } +end: + return NULL; +} |