summaryrefslogtreecommitdiffstats
path: root/crypto/ct
diff options
context:
space:
mode:
authorRob Percival <robpercival@google.com>2016-02-25 13:33:48 +0000
committerRich Salz <rsalz@openssl.org>2016-03-01 11:59:28 -0500
commit8c6afbc55cc8e2d036c0af5adbaff82d8117c6b2 (patch)
tree29f5feb6cf77df46204d65a6dcb6e1af65aedb06 /crypto/ct
parent09375d12fb684c6991c06b473664a0630b8b2edf (diff)
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')
-rw-r--r--crypto/ct/Makefile.in6
-rw-r--r--crypto/ct/build.info3
-rw-r--r--crypto/ct/ct_b64.c213
-rw-r--r--crypto/ct/ct_err.c22
-rw-r--r--crypto/ct/ct_locl.h40
-rw-r--r--crypto/ct/ct_log.c330
-rw-r--r--crypto/ct/ct_prn.c5
-rw-r--r--crypto/ct/ct_sct.c66
-rw-r--r--crypto/ct/ct_sct_ctx.c267
-rw-r--r--crypto/ct/ct_vfy.c255
10 files changed, 1204 insertions, 3 deletions
diff --git a/crypto/ct/Makefile.in b/crypto/ct/Makefile.in
index 21ff2313ce..de122df863 100644
--- a/crypto/ct/Makefile.in
+++ b/crypto/ct/Makefile.in
@@ -15,8 +15,10 @@ CFLAGS= $(INCLUDES) $(CFLAG) $(SHARED_CFLAG)
GENERAL=Makefile
LIB=$(TOP)/libcrypto.a
-LIBSRC= ct_err.c ct_oct.c ct_prn.c ct_sct.c ct_x509v3.c
-LIBOBJ= ct_err.o ct_oct.o ct_prn.o ct_sct.o ct_x509v3.o
+LIBSRC= 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
+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)
diff --git a/crypto/ct/build.info b/crypto/ct/build.info
index b7766b6ed9..fbf2495813 100644
--- a/crypto/ct/build.info
+++ b/crypto/ct/build.info
@@ -1,2 +1,3 @@
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
diff --git a/crypto/ct/ct_b64.c b/crypto/ct/ct_b64.c
new file mode 100644
index 0000000000..a257b8f0d5
--- /dev/null
+++ b/crypto/ct/ct_b64.c
@@ -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;
+}
diff --git a/crypto/ct/ct_err.c b/crypto/ct/ct_err.c
index 033872e096..6db237b534 100644
--- a/crypto/ct/ct_err.c
+++ b/crypto/ct/ct_err.c
@@ -69,6 +69,15 @@
# define ERR_REASON(reason) ERR_PACK(ERR_LIB_CT,0,reason)
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_I2D_SCT_LIST), "i2d_SCT_LIST"},
{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_LIST), "o2i_SCT_LIST"},
{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_FROM_BASE64), "SCT_new_from_base64"},
{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_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_VERSION), "SCT_set_version"},
{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}
};
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_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_SIGNATURE), "sct invalid signature"},
{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_UNSUPPORTED_VERSION), "sct unsupported version"},
{ERR_REASON(CT_R_UNRECOGNIZED_SIGNATURE_NID),
"unrecognized signature nid"},
{ERR_REASON(CT_R_UNSUPPORTED_ENTRY_TYPE), "unsupported entry type"},
diff --git a/crypto/ct/ct_locl.h b/crypto/ct/ct_locl.h
index 9b76d16207..9409b01a30 100644
--- a/crypto/ct/ct_locl.h
+++ b/crypto/ct/ct_locl.h
@@ -91,8 +91,48 @@ struct sct_st {
size_t sig_len;
/* Log 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?
* Returns 1 if so, 0 otherwise.
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;
+}
diff --git a/crypto/ct/ct_prn.c b/crypto/ct/ct_prn.c
index 73aba7e578..3983c3cb3b 100644
--- a/crypto/ct/ct_prn.c
+++ b/crypto/ct/ct_prn.c
@@ -107,6 +107,11 @@ void SCT_print(const SCT *sct, BIO *out, int indent)
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_hex_string(out, indent + 16, 16, sct->log_id, sct->log_id_len);
diff --git a/crypto/ct/ct_sct.c b/crypto/ct/ct_sct.c
index 81e51f0f61..62cadc9743 100644
--- a/crypto/ct/ct_sct.c
+++ b/crypto/ct/ct_sct.c
@@ -239,6 +239,11 @@ size_t SCT_get0_log_id(const SCT *sct, unsigned char **log_id)
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)
{
return sct->timestamp;
@@ -291,3 +296,64 @@ int SCT_signature_is_complete(const SCT *sct)
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;
+}
diff --git a/crypto/ct/ct_sct_ctx.c b/crypto/ct/ct_sct_ctx.c
new file mode 100644
index 0000000000..4b0da42cd3
--- /dev/null
+++ b/crypto/ct/ct_sct_ctx.c
@@ -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 */
+