Verify SCT signatures
authorRob Percival <robpercival@google.com>
Thu, 25 Feb 2016 13:33:48 +0000 (13:33 +0000)
committerRich Salz <rsalz@openssl.org>
Tue, 1 Mar 2016 16:59:28 +0000 (11:59 -0500)
Tests included in future commit, which adds CT policy validation.

Reviewed-by: Ben Laurie <ben@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
15 files changed:
crypto/ct/Makefile.in
crypto/ct/build.info
crypto/ct/ct_b64.c [new file with mode: 0644]
crypto/ct/ct_err.c
crypto/ct/ct_locl.h
crypto/ct/ct_log.c [new file with mode: 0644]
crypto/ct/ct_prn.c
crypto/ct/ct_sct.c
crypto/ct/ct_sct_ctx.c [new file with mode: 0644]
crypto/ct/ct_vfy.c [new file with mode: 0644]
crypto/include/internal/cryptlib.h
include/openssl/ct.h
include/openssl/ossl_typ.h
test/ct/log_list.conf [new file with mode: 0644]
util/libeay.num

index 21ff231..de122df 100644 (file)
@@ -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)
 
index b7766b6..fbf2495 100644 (file)
@@ -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 (file)
index 0000000..a257b8f
--- /dev/null
@@ -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;
+}
index 033872e..6db237b 100644 (file)
 # 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"},
index 9b76d16..9409b01 100644 (file)
@@ -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 (file)
index 0000000..aa3afc4
--- /dev/null
@@ -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;
+}
index 73aba7e..3983c3c 100644 (file)
@@ -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);
 
index 81e51f0..62cadc9 100644 (file)
@@ -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 (file)
index 0000000..4b0da42
--- /dev/null
@@ -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;
+}
diff --git a/crypto/ct/ct_vfy.c b/crypto/ct/ct_vfy.c
new file mode 100644 (file)
index 0000000..41fdcae
--- /dev/null
@@ -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;
+}
index 9e620e6..22caf93 100644 (file)
@@ -94,15 +94,18 @@ DEFINE_LHASH_OF(MEM);
 #  define X509_CERT_DIR           OPENSSLDIR "/certs"
 #  define X509_CERT_FILE          OPENSSLDIR "/cert.pem"
 #  define X509_PRIVATE_DIR        OPENSSLDIR "/private"
+#  define CTLOG_FILE              OPENSSLDIR "/log_list.conf"
 # else
 #  define X509_CERT_AREA          "SSLROOT:[000000]"
 #  define X509_CERT_DIR           "SSLCERTS:"
 #  define X509_CERT_FILE          "SSLCERTS:cert.pem"
 #  define X509_PRIVATE_DIR        "SSLPRIVATE:"
+#  define CTLOG_FILE              "SSLCERTS:log_list.conf"
 # endif
 
 # define X509_CERT_DIR_EVP        "SSL_CERT_DIR"
 # define X509_CERT_FILE_EVP       "SSL_CERT_FILE"
+# define CTLOG_FILE_EVP           "CTLOG_FILE"
 
 /* size of string representations */
 # define DECIMAL_SIZE(type)      ((sizeof(type)*8+2)/3+1)
index 520174f..de130c4 100644 (file)
@@ -83,7 +83,15 @@ typedef enum {
     SCT_VERSION_V1 = 0
 } 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(CTLOG)
 
 /*****************
  * SCT functions *
@@ -95,6 +103,17 @@ DEFINE_STACK_OF(SCT)
  */
 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.
  */
@@ -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);
 
+/*
+ * 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).
  */
@@ -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);
 
+/*
+ * 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|.
  * 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,
                     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 *
  *********************************/
@@ -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);
 
+/********************
+ * 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 */
 /*
  * 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. */
 
 /* 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_I2D_SCT_LIST                                106
 # 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_LIST                                111
 # 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_FROM_BASE64                         127
 # define CT_F_SCT_SET0_LOG_ID                             101
 # define CT_F_SCT_SET1_EXTENSIONS                         114
 # 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_VERSION                             104
 # define CT_F_SCT_SIGNATURE_IS_VALID                      113
+# define CT_F_SCT_VERIFY                                  128
+# define CT_F_SCT_VERIFY_V1                               129
 
 /* Reason codes. */
+# define CT_R_BASE64_DECODE_ERROR                         108
 # 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_SIGNATURE                       107
 # 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_UNSUPPORTED_VERSION                     115
 # define CT_R_UNRECOGNIZED_SIGNATURE_NID                  101
 # define CT_R_UNSUPPORTED_ENTRY_TYPE                      102
 # define CT_R_UNSUPPORTED_VERSION                         103
index 536ffa2..0132966 100644 (file)
@@ -201,6 +201,9 @@ typedef struct ocsp_response_st OCSP_RESPONSE;
 typedef struct ocsp_responder_id_st OCSP_RESPID;
 
 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 && \
     defined(INTMAX_MAX) && defined(UINTMAX_MAX)
diff --git a/test/ct/log_list.conf b/test/ct/log_list.conf
new file mode 100644 (file)
index 0000000..4b68e53
--- /dev/null
@@ -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
+
index ea14ebd..2484fd2 100755 (executable)
@@ -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_new                      5271   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: