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>
This commit is contained in:
Rob Percival 2016-02-25 13:33:48 +00:00 committed by Rich Salz
parent 09375d12fb
commit 8c6afbc55c
15 changed files with 1439 additions and 3 deletions

View file

@ -15,8 +15,10 @@ CFLAGS= $(INCLUDES) $(CFLAG) $(SHARED_CFLAG)
GENERAL=Makefile GENERAL=Makefile
LIB=$(TOP)/libcrypto.a LIB=$(TOP)/libcrypto.a
LIBSRC= ct_err.c ct_oct.c ct_prn.c ct_sct.c ct_x509v3.c LIBSRC= ct_b64.c ct_err.c ct_log.c ct_oct.c ct_prn.c ct_sct.c ct_sct_ctx.c \
LIBOBJ= ct_err.o ct_oct.o ct_prn.o ct_sct.o ct_x509v3.o ct_vfy.c ct_x509v3.c
LIBOBJ= ct_b64.o ct_err.o ct_log.o ct_oct.o ct_prn.o ct_sct.o ct_sct_ctx.o \
ct_vfy.o ct_x509v3.o
SRC= $(LIBSRC) SRC= $(LIBSRC)

View file

@ -1,2 +1,3 @@
LIBS=../../libcrypto LIBS=../../libcrypto
SOURCE[../../libcrypto]= ct_err.c ct_oct.c ct_prn.c ct_sct.c ct_x509v3.c SOURCE[../../libcrypto]= ct_b64.c ct_err.c ct_log.c ct_oct.c ct_prn.c ct_sct.c \
ct_sct_ctx.c ct_vfy.c ct_x509v3.c

213
crypto/ct/ct_b64.c Normal file
View file

@ -0,0 +1,213 @@
/*
* Written by Rob Stradling (rob@comodo.com) and Stephen Henson
* (steve@openssl.org) for the OpenSSL project 2014.
*/
/* ====================================================================
* Copyright (c) 2014 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
* licensing@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 <limits.h>
#include <string.h>
#include <openssl/ct.h>
#include <openssl/err.h>
#include <openssl/evp.h>
/*
* TODO(robpercival): These macros are getting duplicated all over the place.
* Is there a single place they should be defined for re-use?
* Also, is there a good reason they aren't functions?
*/
#define n2s(c,s) ((s=(((unsigned int)((c)[0]))<<8) | \
(((unsigned int)((c)[1])))), \
c+=2)
/*
* Decodes the base64 string |in| into |out|.
* A new string will be malloc'd and assigned to |out|. This will be owned by
* the caller. Do not provide a pre-allocated string in |out|.
*/
static int CT_base64_decode(const char *in, unsigned char **out)
{
size_t inlen;
int outlen;
unsigned char *outbuf = NULL;
if (in == NULL || out == NULL) {
CTerr(CT_F_CT_BASE64_DECODE, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
inlen = strlen(in);
if (inlen == 0) {
*out = NULL;
return 0;
}
outlen = (inlen / 4) * 3;
outbuf = OPENSSL_malloc(outlen);
if (outbuf == NULL) {
CTerr(CT_F_CT_BASE64_DECODE, ERR_R_MALLOC_FAILURE);
goto err;
}
outlen = EVP_DecodeBlock(outbuf, (unsigned char *)in, inlen);
if (outlen < 0) {
OPENSSL_free(outbuf);
CTerr(CT_F_CT_BASE64_DECODE, CT_R_BASE64_DECODE_ERROR);
goto err;
}
*out = outbuf;
return outlen;
err:
OPENSSL_free(outbuf);
return -1;
}
SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64,
ct_log_entry_type_t entry_type, uint64_t timestamp,
const char *extensions_base64,
const char *signature_base64)
{
SCT *sct;
unsigned char *dec = NULL;
int declen;
if (logid_base64 == NULL ||
extensions_base64 == NULL ||
signature_base64 == NULL) {
CTerr(CT_F_SCT_NEW_FROM_BASE64, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
sct = SCT_new();
if (sct == NULL) {
CTerr(CT_F_SCT_NEW_FROM_BASE64, ERR_R_MALLOC_FAILURE);
return NULL;
}
/*
* RFC6962 section 4.1 says we "MUST NOT expect this to be 0", but we
* can only construct SCT versions that have been defined.
*/
if (!SCT_set_version(sct, version)) {
CTerr(CT_F_SCT_NEW_FROM_BASE64, CT_R_SCT_UNSUPPORTED_VERSION);
goto err;
}
declen = CT_base64_decode(logid_base64, &dec);
if (declen < 0) {
CTerr(CT_F_SCT_NEW_FROM_BASE64, X509_R_BASE64_DECODE_ERROR);
goto err;
}
if (!SCT_set0_log_id(sct, dec, declen))
goto err;
dec = NULL;
declen = CT_base64_decode(extensions_base64, &dec);
if (declen < 0) {
CTerr(CT_F_SCT_NEW_FROM_BASE64, X509_R_BASE64_DECODE_ERROR);
goto err;
}
SCT_set0_extensions(sct, dec, declen);
dec = NULL;
declen = CT_base64_decode(signature_base64, &dec);
if (declen < 0) {
CTerr(CT_F_SCT_NEW_FROM_BASE64, X509_R_BASE64_DECODE_ERROR);
goto err;
}
if (o2i_SCT_signature(sct, (const unsigned char **)&dec, declen) <= 0)
goto err;
SCT_set_timestamp(sct, timestamp);
if (!SCT_set_log_entry_type(sct, entry_type))
goto err;
return sct;
err:
OPENSSL_free(dec);
SCT_free(sct);
return NULL;
}
CTLOG *CTLOG_new_from_base64(const char *pkey_base64, const char *name)
{
unsigned char *pkey_der;
int pkey_der_len;
EVP_PKEY *pkey = NULL;
CTLOG *log = NULL;
pkey_der_len = CT_base64_decode(pkey_base64, &pkey_der);
if (pkey_der_len <= 0) {
CTerr(CT_F_CTLOG_NEW_FROM_BASE64, CT_R_LOG_CONF_INVALID_KEY);
return NULL;
}
pkey = d2i_PUBKEY(NULL, (const unsigned char **)&pkey_der, pkey_der_len);
if (pkey == NULL) {
CTerr(CT_F_CTLOG_NEW_FROM_BASE64, CT_R_LOG_CONF_INVALID_KEY);
return NULL;
}
log = CTLOG_new(pkey, name);
if (log == NULL) {
EVP_PKEY_free(pkey);
return NULL;
}
return log;
}

View file

@ -69,6 +69,15 @@
# define ERR_REASON(reason) ERR_PACK(ERR_LIB_CT,0,reason) # define ERR_REASON(reason) ERR_PACK(ERR_LIB_CT,0,reason)
static ERR_STRING_DATA CT_str_functs[] = { static ERR_STRING_DATA CT_str_functs[] = {
{ERR_FUNC(CT_F_CTLOG_NEW), "CTLOG_new"},
{ERR_FUNC(CT_F_CTLOG_NEW_FROM_BASE64), "CTLOG_new_from_base64"},
{ERR_FUNC(CT_F_CTLOG_NEW_FROM_CONF), "CTLOG_new_from_conf"},
{ERR_FUNC(CT_F_CTLOG_NEW_NULL), "CTLOG_new_null"},
{ERR_FUNC(CT_F_CTLOG_STORE_GET0_LOG_BY_ID), "CTLOG_STORE_get0_log_by_id"},
{ERR_FUNC(CT_F_CTLOG_STORE_LOAD_CTX_NEW), "CTLOG_STORE_LOAD_CTX_new"},
{ERR_FUNC(CT_F_CTLOG_STORE_LOAD_FILE), "CTLOG_STORE_load_file"},
{ERR_FUNC(CT_F_CT_BASE64_DECODE), "CT_base64_decode"},
{ERR_FUNC(CT_F_CT_V1_LOG_ID_FROM_PKEY), "CT_v1_log_id_from_pkey"},
{ERR_FUNC(CT_F_D2I_SCT_LIST), "d2i_SCT_LIST"}, {ERR_FUNC(CT_F_D2I_SCT_LIST), "d2i_SCT_LIST"},
{ERR_FUNC(CT_F_I2D_SCT_LIST), "i2d_SCT_LIST"}, {ERR_FUNC(CT_F_I2D_SCT_LIST), "i2d_SCT_LIST"},
{ERR_FUNC(CT_F_I2O_SCT), "i2o_SCT"}, {ERR_FUNC(CT_F_I2O_SCT), "i2o_SCT"},
@ -77,7 +86,9 @@ static ERR_STRING_DATA CT_str_functs[] = {
{ERR_FUNC(CT_F_O2I_SCT), "o2i_SCT"}, {ERR_FUNC(CT_F_O2I_SCT), "o2i_SCT"},
{ERR_FUNC(CT_F_O2I_SCT_LIST), "o2i_SCT_LIST"}, {ERR_FUNC(CT_F_O2I_SCT_LIST), "o2i_SCT_LIST"},
{ERR_FUNC(CT_F_O2I_SCT_SIGNATURE), "o2i_SCT_signature"}, {ERR_FUNC(CT_F_O2I_SCT_SIGNATURE), "o2i_SCT_signature"},
{ERR_FUNC(CT_F_SCT_CTX_NEW), "SCT_CTX_new"},
{ERR_FUNC(CT_F_SCT_NEW), "SCT_new"}, {ERR_FUNC(CT_F_SCT_NEW), "SCT_new"},
{ERR_FUNC(CT_F_SCT_NEW_FROM_BASE64), "SCT_new_from_base64"},
{ERR_FUNC(CT_F_SCT_SET0_LOG_ID), "SCT_set0_log_id"}, {ERR_FUNC(CT_F_SCT_SET0_LOG_ID), "SCT_set0_log_id"},
{ERR_FUNC(CT_F_SCT_SET1_EXTENSIONS), "SCT_set1_extensions"}, {ERR_FUNC(CT_F_SCT_SET1_EXTENSIONS), "SCT_set1_extensions"},
{ERR_FUNC(CT_F_SCT_SET1_LOG_ID), "SCT_set1_log_id"}, {ERR_FUNC(CT_F_SCT_SET1_LOG_ID), "SCT_set1_log_id"},
@ -86,15 +97,26 @@ static ERR_STRING_DATA CT_str_functs[] = {
{ERR_FUNC(CT_F_SCT_SET_SIGNATURE_NID), "SCT_set_signature_nid"}, {ERR_FUNC(CT_F_SCT_SET_SIGNATURE_NID), "SCT_set_signature_nid"},
{ERR_FUNC(CT_F_SCT_SET_VERSION), "SCT_set_version"}, {ERR_FUNC(CT_F_SCT_SET_VERSION), "SCT_set_version"},
{ERR_FUNC(CT_F_SCT_SIGNATURE_IS_VALID), "SCT_signature_is_valid"}, {ERR_FUNC(CT_F_SCT_SIGNATURE_IS_VALID), "SCT_signature_is_valid"},
{ERR_FUNC(CT_F_SCT_VERIFY), "SCT_verify"},
{ERR_FUNC(CT_F_SCT_VERIFY_V1), "SCT_verify_v1"},
{0, NULL} {0, NULL}
}; };
static ERR_STRING_DATA CT_str_reasons[] = { static ERR_STRING_DATA CT_str_reasons[] = {
{ERR_REASON(CT_R_BASE64_DECODE_ERROR), "base64 decode error"},
{ERR_REASON(CT_R_INVALID_LOG_ID_LENGTH), "invalid log id length"}, {ERR_REASON(CT_R_INVALID_LOG_ID_LENGTH), "invalid log id length"},
{ERR_REASON(CT_R_LOG_CONF_INVALID), "log conf invalid"},
{ERR_REASON(CT_R_LOG_CONF_INVALID_KEY), "log conf invalid key"},
{ERR_REASON(CT_R_LOG_CONF_MISSING_DESCRIPTION),
"log conf missing description"},
{ERR_REASON(CT_R_LOG_CONF_MISSING_KEY), "log conf missing key"},
{ERR_REASON(CT_R_LOG_KEY_INVALID), "log key invalid"},
{ERR_REASON(CT_R_SCT_INVALID), "sct invalid"}, {ERR_REASON(CT_R_SCT_INVALID), "sct invalid"},
{ERR_REASON(CT_R_SCT_INVALID_SIGNATURE), "sct invalid signature"}, {ERR_REASON(CT_R_SCT_INVALID_SIGNATURE), "sct invalid signature"},
{ERR_REASON(CT_R_SCT_LIST_INVALID), "sct list invalid"}, {ERR_REASON(CT_R_SCT_LIST_INVALID), "sct list invalid"},
{ERR_REASON(CT_R_SCT_LOG_ID_MISMATCH), "sct log id mismatch"},
{ERR_REASON(CT_R_SCT_NOT_SET), "sct not set"}, {ERR_REASON(CT_R_SCT_NOT_SET), "sct not set"},
{ERR_REASON(CT_R_SCT_UNSUPPORTED_VERSION), "sct unsupported version"},
{ERR_REASON(CT_R_UNRECOGNIZED_SIGNATURE_NID), {ERR_REASON(CT_R_UNRECOGNIZED_SIGNATURE_NID),
"unrecognized signature nid"}, "unrecognized signature nid"},
{ERR_REASON(CT_R_UNSUPPORTED_ENTRY_TYPE), "unsupported entry type"}, {ERR_REASON(CT_R_UNSUPPORTED_ENTRY_TYPE), "unsupported entry type"},

View file

@ -91,8 +91,48 @@ struct sct_st {
size_t sig_len; size_t sig_len;
/* Log entry type */ /* Log entry type */
ct_log_entry_type_t entry_type; ct_log_entry_type_t entry_type;
/* Where this SCT was found, e.g. certificate, OCSP response, etc. */
sct_source_t source;
/* The CT log that produced this SCT. */
CTLOG *log;
}; };
/* Miscellaneous data that is useful when verifying an SCT */
struct sct_ctx_st {
/* Public key */
EVP_PKEY *pkey;
/* Hash of public key */
unsigned char *pkeyhash;
size_t pkeyhashlen;
/* For pre-certificate: issuer public key hash */
unsigned char *ihash;
size_t ihashlen;
/* certificate encoding */
unsigned char *certder;
size_t certderlen;
/* pre-certificate encoding */
unsigned char *preder;
size_t prederlen;
};
/*
* Creates a new context for verifying an SCT.
*/
SCT_CTX *SCT_CTX_new(void);
/*
* Deletes an SCT verification context.
*/
void SCT_CTX_free(SCT_CTX *sctx);
/* Sets the certificate that the SCT is related to */
int SCT_CTX_set1_cert(SCT_CTX *sctx, X509 *cert, X509 *presigner);
/* Sets the issuer of the certificate that the SCT is related to */
int SCT_CTX_set1_issuer(SCT_CTX *sctx, const X509 *issuer);
/* Sets the public key of the issuer of the certificate that the SCT relates to */
int SCT_CTX_set1_issuer_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey);
/* Sets the public key of the CT log that the SCT is from */
int SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey);
/* /*
* Does this SCT have the minimum fields populated to be usuable? * Does this SCT have the minimum fields populated to be usuable?
* Returns 1 if so, 0 otherwise. * Returns 1 if so, 0 otherwise.

330
crypto/ct/ct_log.c Normal file
View file

@ -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;
}

View file

@ -107,6 +107,11 @@ void SCT_print(const SCT *sct, BIO *out, int indent)
BIO_printf(out, "v1 (0x0)"); BIO_printf(out, "v1 (0x0)");
if (sct->log != NULL) {
BIO_printf(out, "\n%*sLog : %s", indent + 4, "",
SCT_get0_log_name(sct));
}
BIO_printf(out, "\n%*sLog ID : ", indent + 4, ""); BIO_printf(out, "\n%*sLog ID : ", indent + 4, "");
BIO_hex_string(out, indent + 16, 16, sct->log_id, sct->log_id_len); BIO_hex_string(out, indent + 16, 16, sct->log_id, sct->log_id_len);

View file

@ -239,6 +239,11 @@ size_t SCT_get0_log_id(const SCT *sct, unsigned char **log_id)
return sct->log_id_len; return sct->log_id_len;
} }
const char *SCT_get0_log_name(const SCT *sct)
{
return CTLOG_get0_name(sct->log);
}
uint64_t SCT_get_timestamp(const SCT *sct) uint64_t SCT_get_timestamp(const SCT *sct)
{ {
return sct->timestamp; return sct->timestamp;
@ -291,3 +296,64 @@ int SCT_signature_is_complete(const SCT *sct)
sct->sig != NULL && sct->sig_len > 0; sct->sig != NULL && sct->sig_len > 0;
} }
sct_source_t SCT_get_source(const SCT *sct)
{
return sct->source;
}
int SCT_set_source(SCT *sct, sct_source_t source)
{
sct->source = source;
switch (source) {
case SCT_SOURCE_TLS_EXTENSION:
case SCT_SOURCE_OCSP_STAPLED_RESPONSE:
return SCT_set_log_entry_type(sct, CT_LOG_ENTRY_TYPE_X509);
case SCT_SOURCE_X509V3_EXTENSION:
return SCT_set_log_entry_type(sct, CT_LOG_ENTRY_TYPE_PRECERT);
default: /* if we aren't sure, leave the log entry type alone */
return 1;
}
}
int SCT_LIST_set_source(const STACK_OF(SCT) *scts, sct_source_t source)
{
int i, ret = 1;
for (i = 0; i < sk_SCT_num(scts); ++i) {
ret = SCT_set_source(sk_SCT_value(scts, i), source);
if (ret != 1)
break;
}
return ret;
}
CTLOG *SCT_get0_log(const SCT *sct)
{
return sct->log;
}
int SCT_set0_log(SCT *sct, const CTLOG_STORE *ct_logs)
{
sct->log =
CTLOG_STORE_get0_log_by_id(ct_logs, sct->log_id, sct->log_id_len);
return sct->log != NULL;
}
int SCT_LIST_set0_logs(STACK_OF(SCT) *sct_list, const CTLOG_STORE *ct_logs)
{
int sct_logs_found = 0;
int i;
for (i = 0; i < sk_SCT_num(sct_list); ++i) {
SCT *sct = sk_SCT_value(sct_list, i);
if (sct->log == NULL)
SCT_set0_log(sct, ct_logs);
if (sct->log != NULL)
++sct_logs_found;
}
return sct_logs_found;
}

267
crypto/ct/ct_sct_ctx.c Normal file
View file

@ -0,0 +1,267 @@
/*
* Written by Rob Stradling (rob@comodo.com) and Stephen Henson
* (steve@openssl.org) for the OpenSSL project 2014.
*/
/* ====================================================================
* Copyright (c) 2014 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
* licensing@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).
*
*/
#ifdef OPENSSL_NO_CT
# error "CT is disabled"
#endif
#include <stddef.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/obj_mac.h>
#include <openssl/x509.h>
#include "ct_locl.h"
SCT_CTX *SCT_CTX_new(void)
{
SCT_CTX *sctx = OPENSSL_zalloc(sizeof(SCT_CTX));
if (sctx == NULL)
CTerr(CT_F_SCT_CTX_NEW, ERR_R_MALLOC_FAILURE);
return sctx;
}
void SCT_CTX_free(SCT_CTX *sctx)
{
if (sctx == NULL)
return;
EVP_PKEY_free(sctx->pkey);
OPENSSL_free(sctx->pkeyhash);
OPENSSL_free(sctx->ihash);
OPENSSL_free(sctx->certder);
OPENSSL_free(sctx->preder);
OPENSSL_free(sctx);
}
/* retrieve extension index checking for duplicates */
static int sct_get_ext(X509 *cert, int nid)
{
int rv = X509_get_ext_by_NID(cert, nid, -1);
if (rv >= 0 && X509_get_ext_by_NID(cert, nid, rv) >= 0)
return -2;
return rv;
}
/*
* modify certificate by deleting extensions, copying issuer
* and AKID if necessary.
*/
static int sct_cert_fixup(X509 *cert, X509 *presigner)
{
int preidx, certidx;
if (presigner == NULL)
return 1;
preidx = sct_get_ext(presigner, NID_authority_key_identifier);
certidx = sct_get_ext(cert, NID_authority_key_identifier);
/* Invalid certificate if duplicate */
if (preidx == -2 || certidx == -2)
return 0;
/* AKID must be present in both certificate or absent in both */
if (preidx >= 0 && certidx == -1)
return 0;
if (preidx == -1 && certidx >= 0)
return 0;
/* Copy issuer name */
if (!X509_set_issuer_name(cert, X509_get_issuer_name(presigner)))
return 0;
if (preidx != -1) {
/* Retrieve and copy AKID encoding */
X509_EXTENSION *preext = X509_get_ext(presigner, preidx);
X509_EXTENSION *certext = X509_get_ext(cert, certidx);
ASN1_OCTET_STRING *preextdata;
/* Should never happen */
if (preext == NULL || certext == NULL)
return 0;
preextdata = X509_EXTENSION_get_data(preext);
if (preextdata == NULL || !X509_EXTENSION_set_data(certext, preextdata))
return 0;
}
return 1;
}
int SCT_CTX_set1_cert(SCT_CTX *sctx, X509 *cert, X509 *presigner)
{
unsigned char *certder = NULL, *preder = NULL;
X509 *pretmp = NULL;
int certderlen = 0, prederlen = 0;
int idx = -1, idxp = -1;
idxp = sct_get_ext(cert, NID_ct_precert_poison);
/* Duplicate poison */
if (idxp == -2)
goto err;
/* If no poison store encoding */
if (idxp == -1) {
/* If presigner must have poison */
if (presigner)
goto err;
certderlen = i2d_X509(cert, &certder);
if (certderlen < 0)
goto err;
}
/* See if have precert scts extension */
idx = X509_get_ext_by_NID(cert, NID_ct_precert_scts, -1);
/* Duplicate scts */
if (idx == -2)
goto err;
if (idx >= 0) {
/* Can't have both poison and scts */
if (idxp >= 0)
goto err;
} else
idx = idxp;
if (idx >= 0) {
X509_EXTENSION *ext;
/*
* Take a copy of certificate so we don't modify passed version
*/
pretmp = X509_dup(cert);
if (pretmp == NULL)
goto err;
ext = X509_delete_ext(pretmp, idx);
X509_EXTENSION_free(ext);
if (!sct_cert_fixup(pretmp, presigner))
goto err;
prederlen = i2d_re_X509_tbs(pretmp, &preder);
if (prederlen <= 0)
goto err;
}
X509_free(pretmp);
OPENSSL_free(sctx->certder);
sctx->certder = certder;
sctx->certderlen = certderlen;
OPENSSL_free(sctx->preder);
sctx->preder = preder;
sctx->prederlen = prederlen;
return 1;
err:
OPENSSL_free(certder);
OPENSSL_free(preder);
X509_free(pretmp);
return 0;
}
static int CT_public_key_hash(X509_PUBKEY *pkey, unsigned char **hash,
size_t *hash_len)
{
int ret = -1;
unsigned char *md = NULL, *der = NULL;
int der_len;
unsigned int md_len;
if (pkey == NULL)
goto err;
/* Reuse buffer if possible */
if (*hash != NULL && *hash_len >= SHA256_DIGEST_LENGTH) {
md = *hash;
} else {
md = OPENSSL_malloc(SHA256_DIGEST_LENGTH);
if (md == NULL)
goto err;
}
/* Calculate key hash */
der_len = i2d_X509_PUBKEY(pkey, &der);
if (der_len <= 0)
goto err;
if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha256(), NULL))
goto err;
if (md != *hash) {
OPENSSL_free(*hash);
*hash = md;
*hash_len = SHA256_DIGEST_LENGTH;
}
md = NULL;
ret = 1;
err:
OPENSSL_free(md);
OPENSSL_free(der);
return ret;
}
int SCT_CTX_set1_issuer(SCT_CTX *sctx, const X509 *issuer)
{
return CT_public_key_hash(X509_get_X509_PUBKEY(issuer), &sctx->ihash,
&sctx->ihashlen);
}
int SCT_CTX_set1_issuer_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey)
{
return CT_public_key_hash(pubkey, &sctx->ihash, &sctx->ihashlen);
}
int SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey)
{
EVP_PKEY *pkey = X509_PUBKEY_get(pubkey);
if (pkey == NULL)
return 0;
if (!CT_public_key_hash(pubkey, &sctx->pkeyhash, &sctx->pkeyhashlen)) {
EVP_PKEY_free(pkey);
return 0;
}
EVP_PKEY_free(sctx->pkey);
sctx->pkey = pkey;
return 1;
}

255
crypto/ct/ct_vfy.c Normal file
View file

@ -0,0 +1,255 @@
/*
* Written by Rob Stradling (rob@comodo.com) and Stephen Henson
* (steve@openssl.org) for the OpenSSL project 2014.
*/
/* ====================================================================
* Copyright (c) 2014 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
* licensing@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 <string.h>
#include <openssl/ct.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include "ct_locl.h"
#define n2s(c,s) ((s=(((unsigned int)((c)[0]))<< 8)| \
(((unsigned int)((c)[1])) )),c+=2)
#define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \
c[1]=(unsigned char)(((s) )&0xff)),c+=2)
#define l2n3(l,c) ((c[0]=(unsigned char)(((l)>>16)&0xff), \
c[1]=(unsigned char)(((l)>> 8)&0xff), \
c[2]=(unsigned char)(((l) )&0xff)),c+=3)
#define n2l8(c,l) (l =((uint64_t)(*((c)++)))<<56, \
l|=((uint64_t)(*((c)++)))<<48, \
l|=((uint64_t)(*((c)++)))<<40, \
l|=((uint64_t)(*((c)++)))<<32, \
l|=((uint64_t)(*((c)++)))<<24, \
l|=((uint64_t)(*((c)++)))<<16, \
l|=((uint64_t)(*((c)++)))<< 8, \
l|=((uint64_t)(*((c)++))))
#define l2n8(l,c) (*((c)++)=(unsigned char)(((l)>>56)&0xff), \
*((c)++)=(unsigned char)(((l)>>48)&0xff), \
*((c)++)=(unsigned char)(((l)>>40)&0xff), \
*((c)++)=(unsigned char)(((l)>>32)&0xff), \
*((c)++)=(unsigned char)(((l)>>24)&0xff), \
*((c)++)=(unsigned char)(((l)>>16)&0xff), \
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
*((c)++)=(unsigned char)(((l) )&0xff))
typedef enum sct_signature_type_t {
SIGNATURE_TYPE_NOT_SET = -1,
SIGNATURE_TYPE_CERT_TIMESTAMP,
SIGNATURE_TYPE_TREE_HASH
} SCT_SIGNATURE_TYPE;
/*
* Update encoding for SCT signature verification/generation to supplied
* EVP_MD_CTX.
*/
static int sct_ctx_update(EVP_MD_CTX *ctx, const SCT_CTX *sctx, const SCT *sct)
{
unsigned char tmpbuf[12];
unsigned char *p, *der;
size_t derlen;
/*
* digitally-signed struct { (1 byte) Version sct_version; (1 byte)
* SignatureType signature_type = certificate_timestamp; (8 bytes) uint64
* timestamp; (2 bytes) LogEntryType entry_type; (? bytes)
* select(entry_type) { case x509_entry: ASN.1Cert; case precert_entry:
* PreCert; } signed_entry; (2 bytes + sct->ext_len) CtExtensions
* extensions;
*/
if (sct->entry_type == CT_LOG_ENTRY_TYPE_NOT_SET)
return 0;
if (sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && sctx->ihash == NULL)
return 0;
p = tmpbuf;
*p++ = sct->version;
*p++ = SIGNATURE_TYPE_CERT_TIMESTAMP;
l2n8(sct->timestamp, p);
s2n(sct->entry_type, p);
if (!EVP_DigestUpdate(ctx, tmpbuf, p - tmpbuf))
return 0;
if (sct->entry_type == CT_LOG_ENTRY_TYPE_X509) {
der = sctx->certder;
derlen = sctx->certderlen;
} else {
if (!EVP_DigestUpdate(ctx, sctx->ihash, sctx->ihashlen))
return 0;
der = sctx->preder;
derlen = sctx->prederlen;
}
/* If no encoding available, fatal error */
if (der == NULL)
return 0;
/* Include length first */
p = tmpbuf;
l2n3(derlen, p);
if (!EVP_DigestUpdate(ctx, tmpbuf, 3))
return 0;
if (!EVP_DigestUpdate(ctx, der, derlen))
return 0;
/* Add any extensions */
p = tmpbuf;
s2n(sct->ext_len, p);
if (!EVP_DigestUpdate(ctx, tmpbuf, 2))
return 0;
if (sct->ext_len && !EVP_DigestUpdate(ctx, sct->ext, sct->ext_len))
return 0;
return 1;
}
int SCT_verify(const SCT_CTX *sctx, const SCT *sct)
{
EVP_MD_CTX *ctx = NULL;
int ret = -1;
if (!SCT_is_complete(sct) || sctx->pkey == NULL ||
sct->entry_type == CT_LOG_ENTRY_TYPE_NOT_SET ||
(sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && sctx->ihash == NULL)) {
CTerr(CT_F_SCT_VERIFY, CT_R_SCT_NOT_SET);
return -1;
}
if (sct->version != SCT_VERSION_V1) {
CTerr(CT_F_SCT_VERIFY, CT_R_SCT_UNSUPPORTED_VERSION);
return 0;
}
if (sct->log_id_len != sctx->pkeyhashlen ||
memcmp(sct->log_id, sctx->pkeyhash, sctx->pkeyhashlen) != 0) {
CTerr(CT_F_SCT_VERIFY, CT_R_SCT_LOG_ID_MISMATCH);
return 0;
}
ctx = EVP_MD_CTX_new();
if (ctx == NULL)
goto end;
if (!EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, sctx->pkey))
goto end;
if (!sct_ctx_update(ctx, sctx, sct))
goto end;
/* Verify signature */
ret = EVP_DigestVerifyFinal(ctx, sct->sig, sct->sig_len);
/* If ret < 0 some other error: fall through without setting error */
if (ret == 0)
CTerr(CT_F_SCT_VERIFY, CT_R_SCT_INVALID_SIGNATURE);
end:
EVP_MD_CTX_free(ctx);
return ret;
}
int SCT_verify_v1(SCT *sct, X509 *cert, X509 *preissuer,
X509_PUBKEY *log_pubkey, X509 *issuer_cert)
{
int ret = 0;
SCT_CTX *sctx = NULL;
if (sct == NULL || cert == NULL || log_pubkey == NULL ||
(sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && issuer_cert == NULL)) {
CTerr(CT_F_SCT_VERIFY_V1, ERR_R_PASSED_NULL_PARAMETER);
return -1;
} else if (!SCT_is_complete(sct)) {
CTerr(CT_F_SCT_VERIFY_V1, CT_R_SCT_NOT_SET);
return -1;
} else if (sct->version != 0) {
CTerr(CT_F_SCT_VERIFY_V1, CT_R_SCT_UNSUPPORTED_VERSION);
return 0;
}
sctx = SCT_CTX_new();
if (sctx == NULL)
goto done;
ret = SCT_CTX_set1_pubkey(sctx, log_pubkey);
if (ret <= 0)
goto done;
ret = SCT_CTX_set1_cert(sctx, cert, preissuer);
if (ret <= 0)
goto done;
if (sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT) {
ret = SCT_CTX_set1_issuer(sctx, issuer_cert);
if (ret <= 0)
goto done;
}
ret = SCT_verify(sctx, sct);
done:
if (sctx != NULL)
SCT_CTX_free(sctx);
return ret;
}

View file

@ -94,15 +94,18 @@ DEFINE_LHASH_OF(MEM);
# define X509_CERT_DIR OPENSSLDIR "/certs" # define X509_CERT_DIR OPENSSLDIR "/certs"
# define X509_CERT_FILE OPENSSLDIR "/cert.pem" # define X509_CERT_FILE OPENSSLDIR "/cert.pem"
# define X509_PRIVATE_DIR OPENSSLDIR "/private" # define X509_PRIVATE_DIR OPENSSLDIR "/private"
# define CTLOG_FILE OPENSSLDIR "/log_list.conf"
# else # else
# define X509_CERT_AREA "SSLROOT:[000000]" # define X509_CERT_AREA "SSLROOT:[000000]"
# define X509_CERT_DIR "SSLCERTS:" # define X509_CERT_DIR "SSLCERTS:"
# define X509_CERT_FILE "SSLCERTS:cert.pem" # define X509_CERT_FILE "SSLCERTS:cert.pem"
# define X509_PRIVATE_DIR "SSLPRIVATE:" # define X509_PRIVATE_DIR "SSLPRIVATE:"
# define CTLOG_FILE "SSLCERTS:log_list.conf"
# endif # endif
# define X509_CERT_DIR_EVP "SSL_CERT_DIR" # define X509_CERT_DIR_EVP "SSL_CERT_DIR"
# define X509_CERT_FILE_EVP "SSL_CERT_FILE" # define X509_CERT_FILE_EVP "SSL_CERT_FILE"
# define CTLOG_FILE_EVP "CTLOG_FILE"
/* size of string representations */ /* size of string representations */
# define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1) # define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1)

View file

@ -83,7 +83,15 @@ typedef enum {
SCT_VERSION_V1 = 0 SCT_VERSION_V1 = 0
} sct_version_t; } sct_version_t;
typedef enum {
SCT_SOURCE_UNKNOWN,
SCT_SOURCE_TLS_EXTENSION,
SCT_SOURCE_X509V3_EXTENSION,
SCT_SOURCE_OCSP_STAPLED_RESPONSE
} sct_source_t;
DEFINE_STACK_OF(SCT) DEFINE_STACK_OF(SCT)
DEFINE_STACK_OF(CTLOG)
/***************** /*****************
* SCT functions * * SCT functions *
@ -95,6 +103,17 @@ DEFINE_STACK_OF(SCT)
*/ */
SCT *SCT_new(void); SCT *SCT_new(void);
/*
* Creates a new SCT from some base64-encoded strings.
* The caller is responsible for calling SCT_free when finished with the SCT.
*/
SCT *SCT_new_from_base64(unsigned char version,
const char *logid_base64,
ct_log_entry_type_t entry_type,
uint64_t timestamp,
const char *extensions_base64,
const char *signature_base64);
/* /*
* Frees the SCT and the underlying data structures. * Frees the SCT and the underlying data structures.
*/ */
@ -149,6 +168,13 @@ int SCT_set0_log_id(SCT *sct, unsigned char *log_id, size_t log_id_len);
*/ */
int SCT_set1_log_id(SCT *sct, const unsigned char *log_id, size_t log_id_len); int SCT_set1_log_id(SCT *sct, const unsigned char *log_id, size_t log_id_len);
/*
* Gets the name of the log that an SCT came from.
* Ownership of the log name remains with the SCT.
* Returns the log name, or NULL if it is not known.
*/
const char *SCT_get0_log_name(const SCT *sct);
/* /*
* Returns the timestamp for the SCT (epoch time in milliseconds). * Returns the timestamp for the SCT (epoch time in milliseconds).
*/ */
@ -213,6 +239,42 @@ void SCT_set0_signature(SCT *sct, unsigned char *sig, size_t sig_len);
*/ */
int SCT_set1_signature(SCT *sct, const unsigned char *sig, size_t sig_len); int SCT_set1_signature(SCT *sct, const unsigned char *sig, size_t sig_len);
/*
* The origin of this SCT, e.g. TLS extension, OCSP response, etc.
*/
sct_source_t SCT_get_source(const SCT *sct);
/*
* Set the origin of this SCT, e.g. TLS extension, OCSP response, etc.
* Returns 1 on success, 0 otherwise.
*/
int SCT_set_source(SCT *sct, sct_source_t source);
/*
* Sets the source of all of the SCTs to the same value.
* Returns 1 on success.
*/
int SCT_LIST_set_source(const STACK_OF(SCT) *scts, sct_source_t source);
/*
* Gets information about the log the SCT came from, if set.
*/
CTLOG *SCT_get0_log(const SCT *sct);
/*
* Looks up information about the log the SCT came from using a CT log store.
* Returns 1 if information about the log is found, 0 otherwise.
* The information can be accessed via SCT_get0_log.
*/
int SCT_set0_log(SCT *sct, const CTLOG_STORE* ct_logs);
/*
* Looks up information about the logs the SCTs came from using a CT log store.
* Returns the number of SCTs that now have a log set.
* If any SCTs already have a log set, they will be skipped.
*/
int SCT_LIST_set0_logs(STACK_OF(SCT) *sct_list, const CTLOG_STORE *ct_logs);
/* /*
* Pretty-prints an |sct| to |out|. * Pretty-prints an |sct| to |out|.
* It will be indented by the number of spaces specified by |indent|. * It will be indented by the number of spaces specified by |indent|.
@ -227,6 +289,21 @@ void SCT_print(const SCT *sct, BIO *out, int indent);
void SCT_LIST_print(const STACK_OF(SCT) *sct_list, BIO *out, int indent, void SCT_LIST_print(const STACK_OF(SCT) *sct_list, BIO *out, int indent,
const char *separator); const char *separator);
/*
* Verifies an SCT with the given context.
* Returns 1 if the SCT verifies successfully, 0 if it cannot be verified and a
* negative integer if an error occurs.
*/
int SCT_verify(const SCT_CTX *sctx, const SCT *sct);
/*
* Verifies an SCT against the provided data.
* Returns 1 if the SCT verifies successfully, 0 if it cannot be verified and a
* negative integer if an error occurs.
*/
int SCT_verify_v1(SCT *sct, X509 *cert, X509 *preissuer,
X509_PUBKEY *log_pubkey, X509 *issuer_cert);
/********************************* /*********************************
* SCT parsing and serialisation * * SCT parsing and serialisation *
*********************************/ *********************************/
@ -328,6 +405,77 @@ int i2o_SCT_signature(const SCT *sct, unsigned char **out);
*/ */
int o2i_SCT_signature(SCT *sct, const unsigned char **in, size_t len); int o2i_SCT_signature(SCT *sct, const unsigned char **in, size_t len);
/********************
* CT log functions *
********************/
/*
* Creates a new CT log instance with the given |public_key| and |name|.
* Should be deleted by the caller using CTLOG_free when no longer needed.
*/
CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name);
/*
* Creates a new, blank CT log instance.
* Should be deleted by the caller using CTLOG_free when no longer needed.
*/
CTLOG *CTLOG_new_null(void);
/*
* Creates a new CT log instance with the given base64 public_key and |name|.
* Should be deleted by the caller using CTLOG_free when no longer needed.
*/
CTLOG *CTLOG_new_from_base64(const char *pkey_base64, const char *name);
/*
* Deletes a CT log instance and its fields.
*/
void CTLOG_free(CTLOG *log);
/* Gets the name of the CT log */
const char *CTLOG_get0_name(CTLOG *log);
/* Gets the ID of the CT log */
void CTLOG_get0_log_id(CTLOG *log, uint8_t **log_id, size_t *log_id_len);
/* Gets the public key of the CT log */
EVP_PKEY *CTLOG_get0_public_key(CTLOG *log);
/**************************
* CT log store functions *
**************************/
/*
* Creates a new CT log store.
* Should be deleted by the caller using CTLOG_STORE_free when no longer needed.
*/
CTLOG_STORE *CTLOG_STORE_new(void);
/*
* Deletes a CT log store and all of the CT log instances held within.
*/
void CTLOG_STORE_free(CTLOG_STORE *store);
/*
* Finds a CT log in the store based on its log ID.
* Returns the CT log, or NULL if no match is found.
*/
CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store,
const uint8_t *log_id,
size_t log_id_len);
/*
* Loads a CT log list into a |store| from a |file|.
* Returns 1 if loading is successful, or a non-positive integer otherwise.
*/
int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file);
/*
* Loads the default CT log list into a |store|.
* See internal/cryptlib.h for the environment variable and file path that are
* consulted to find the default file.
* Returns 1 if loading is successful, or a non-positive integer otherwise.
*/
int CTLOG_STORE_load_default_file(CTLOG_STORE *store);
/* BEGIN ERROR CODES */ /* BEGIN ERROR CODES */
/* /*
* The following lines are auto generated by the script mkerr.pl. Any changes * The following lines are auto generated by the script mkerr.pl. Any changes
@ -338,6 +486,15 @@ void ERR_load_CT_strings(void);
/* Error codes for the CT functions. */ /* Error codes for the CT functions. */
/* Function codes. */ /* Function codes. */
# define CT_F_CTLOG_NEW 117
# define CT_F_CTLOG_NEW_FROM_BASE64 118
# define CT_F_CTLOG_NEW_FROM_CONF 119
# define CT_F_CTLOG_NEW_NULL 120
# define CT_F_CTLOG_STORE_GET0_LOG_BY_ID 121
# define CT_F_CTLOG_STORE_LOAD_CTX_NEW 122
# define CT_F_CTLOG_STORE_LOAD_FILE 123
# define CT_F_CT_BASE64_DECODE 124
# define CT_F_CT_V1_LOG_ID_FROM_PKEY 125
# define CT_F_D2I_SCT_LIST 105 # define CT_F_D2I_SCT_LIST 105
# define CT_F_I2D_SCT_LIST 106 # define CT_F_I2D_SCT_LIST 106
# define CT_F_I2O_SCT 107 # define CT_F_I2O_SCT 107
@ -346,7 +503,9 @@ void ERR_load_CT_strings(void);
# define CT_F_O2I_SCT 110 # define CT_F_O2I_SCT 110
# define CT_F_O2I_SCT_LIST 111 # define CT_F_O2I_SCT_LIST 111
# define CT_F_O2I_SCT_SIGNATURE 112 # define CT_F_O2I_SCT_SIGNATURE 112
# define CT_F_SCT_CTX_NEW 126
# define CT_F_SCT_NEW 100 # define CT_F_SCT_NEW 100
# define CT_F_SCT_NEW_FROM_BASE64 127
# define CT_F_SCT_SET0_LOG_ID 101 # define CT_F_SCT_SET0_LOG_ID 101
# define CT_F_SCT_SET1_EXTENSIONS 114 # define CT_F_SCT_SET1_EXTENSIONS 114
# define CT_F_SCT_SET1_LOG_ID 115 # define CT_F_SCT_SET1_LOG_ID 115
@ -355,13 +514,23 @@ void ERR_load_CT_strings(void);
# define CT_F_SCT_SET_SIGNATURE_NID 103 # define CT_F_SCT_SET_SIGNATURE_NID 103
# define CT_F_SCT_SET_VERSION 104 # define CT_F_SCT_SET_VERSION 104
# define CT_F_SCT_SIGNATURE_IS_VALID 113 # define CT_F_SCT_SIGNATURE_IS_VALID 113
# define CT_F_SCT_VERIFY 128
# define CT_F_SCT_VERIFY_V1 129
/* Reason codes. */ /* Reason codes. */
# define CT_R_BASE64_DECODE_ERROR 108
# define CT_R_INVALID_LOG_ID_LENGTH 100 # define CT_R_INVALID_LOG_ID_LENGTH 100
# define CT_R_LOG_CONF_INVALID 109
# define CT_R_LOG_CONF_INVALID_KEY 110
# define CT_R_LOG_CONF_MISSING_DESCRIPTION 111
# define CT_R_LOG_CONF_MISSING_KEY 112
# define CT_R_LOG_KEY_INVALID 113
# define CT_R_SCT_INVALID 104 # define CT_R_SCT_INVALID 104
# define CT_R_SCT_INVALID_SIGNATURE 107 # define CT_R_SCT_INVALID_SIGNATURE 107
# define CT_R_SCT_LIST_INVALID 105 # define CT_R_SCT_LIST_INVALID 105
# define CT_R_SCT_LOG_ID_MISMATCH 114
# define CT_R_SCT_NOT_SET 106 # define CT_R_SCT_NOT_SET 106
# define CT_R_SCT_UNSUPPORTED_VERSION 115
# define CT_R_UNRECOGNIZED_SIGNATURE_NID 101 # define CT_R_UNRECOGNIZED_SIGNATURE_NID 101
# define CT_R_UNSUPPORTED_ENTRY_TYPE 102 # define CT_R_UNSUPPORTED_ENTRY_TYPE 102
# define CT_R_UNSUPPORTED_VERSION 103 # define CT_R_UNSUPPORTED_VERSION 103

View file

@ -201,6 +201,9 @@ typedef struct ocsp_response_st OCSP_RESPONSE;
typedef struct ocsp_responder_id_st OCSP_RESPID; typedef struct ocsp_responder_id_st OCSP_RESPID;
typedef struct sct_st SCT; typedef struct sct_st SCT;
typedef struct sct_ctx_st SCT_CTX;
typedef struct ctlog_st CTLOG;
typedef struct ctlog_store_st CTLOG_STORE;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
defined(INTMAX_MAX) && defined(UINTMAX_MAX) defined(INTMAX_MAX) && defined(UINTMAX_MAX)

38
test/ct/log_list.conf Normal file
View file

@ -0,0 +1,38 @@
enabled_logs=test,pilot,aviator,rocketeer,digicert,certly,izempe,symantec,venafi
[test]
description = https://github.com/google/certificate-transparency/tree/99218b6445906a81f219d84e9c6d2683e13e4e58/test/testdata
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmXg8sUUzwBYaWrRb+V0IopzQ6o3UyEJ04r5ZrRXGdpYM8K+hB0pXrGRLI0eeWz+3skXrS0IO83AhA3GpRL6s6w==
[pilot]
description = Google Pilot Log
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==
[aviator]
description = Google Aviator log
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==
[rocketeer]
description = Google Rocketeer log
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==
[digicert]
description = DigiCert Log Server
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==
[certly]
description = Certly.IO log
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==
[izempe]
description = Izempe log
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==
[symantec]
description = Symantec log
key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==
[venafi]
description = Venafi log
key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB

View file

@ -4766,3 +4766,25 @@ ASYNC_WAIT_CTX_get_changed_fds 5269 1_1_0 EXIST::FUNCTION:
ASYNC_WAIT_CTX_set_wait_fd 5270 1_1_0 EXIST::FUNCTION: ASYNC_WAIT_CTX_set_wait_fd 5270 1_1_0 EXIST::FUNCTION:
ASYNC_WAIT_CTX_new 5271 1_1_0 EXIST::FUNCTION: ASYNC_WAIT_CTX_new 5271 1_1_0 EXIST::FUNCTION:
ASYNC_get_wait_ctx 5272 1_1_0 EXIST::FUNCTION: ASYNC_get_wait_ctx 5272 1_1_0 EXIST::FUNCTION:
SCT_verify 5273 1_1_0 EXIST::FUNCTION:
CTLOG_STORE_free 5274 1_1_0 EXIST::FUNCTION:
CTLOG_STORE_new 5275 1_1_0 EXIST::FUNCTION:
SCT_verify_v1 5276 1_1_0 EXIST::FUNCTION:
SCT_get0_log 5277 1_1_0 EXIST::FUNCTION:
CTLOG_new_from_base64 5278 1_1_0 EXIST::FUNCTION:
CTLOG_get0_name 5279 1_1_0 EXIST::FUNCTION:
CTLOG_get0_public_key 5280 1_1_0 EXIST::FUNCTION:
CTLOG_get0_log_id 5281 1_1_0 EXIST::FUNCTION:
SCT_new_from_base64 5282 1_1_0 EXIST::FUNCTION:
SCT_get_source 5283 1_1_0 EXIST::FUNCTION:
CTLOG_STORE_load_file 5284 1_1_0 EXIST::FUNCTION:
CTLOG_new_null 5285 1_1_0 EXIST::FUNCTION:
SCT_LIST_set_source 5286 1_1_0 EXIST::FUNCTION:
CTLOG_free 5287 1_1_0 EXIST::FUNCTION:
SCT_get0_log_name 5288 1_1_0 EXIST::FUNCTION:
SCT_set0_log 5289 1_1_0 EXIST::FUNCTION:
SCT_set_source 5290 1_1_0 EXIST::FUNCTION:
SCT_LIST_set0_logs 5291 1_1_0 EXIST::FUNCTION:
CTLOG_STORE_get0_log_by_id 5292 1_1_0 EXIST::FUNCTION:
CTLOG_STORE_load_default_file 5293 1_1_0 EXIST::FUNCTION:
CTLOG_new 5294 1_1_0 EXIST::FUNCTION: