aboutsummaryrefslogtreecommitdiff
path: root/crypto/ct
diff options
context:
space:
mode:
authorRob Percival <robpercival@google.com>2016-02-29 17:33:02 +0000
committerRob Percival <robpercival@google.com>2016-03-01 20:03:25 +0000
commit7d054e5ab2aeaead14c0c19b808d62221020b0e1 (patch)
tree655006eea9d0fe60879b36d09e9046be5a3749de /crypto/ct
parent7852414967b87400b08bfdf321732cfbd07286e2 (diff)
downloadopenssl-7d054e5ab2aeaead14c0c19b808d62221020b0e1.zip
openssl-7d054e5ab2aeaead14c0c19b808d62221020b0e1.tar.gz
openssl-7d054e5ab2aeaead14c0c19b808d62221020b0e1.tar.bz2
CT policy validation
Specifies a callback that will, in the future, be used by the SSL code to decide whether to abort a connection on Certificate Transparency grounds. 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.in8
-rw-r--r--crypto/ct/build.info4
-rw-r--r--crypto/ct/ct_err.c21
-rw-r--r--crypto/ct/ct_locl.h11
-rw-r--r--crypto/ct/ct_policy.c110
-rw-r--r--crypto/ct/ct_sct.c91
-rw-r--r--crypto/ct/ct_vfy.c59
7 files changed, 298 insertions, 6 deletions
diff --git a/crypto/ct/Makefile.in b/crypto/ct/Makefile.in
index de122df..0daec36 100644
--- a/crypto/ct/Makefile.in
+++ b/crypto/ct/Makefile.in
@@ -15,10 +15,10 @@ CFLAGS= $(INCLUDES) $(CFLAG) $(SHARED_CFLAG)
GENERAL=Makefile
LIB=$(TOP)/libcrypto.a
-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
+LIBSRC= ct_b64.c ct_err.c ct_log.c ct_oct.c ct_policy.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_policy.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 fbf2495..3ca0e31 100644
--- a/crypto/ct/build.info
+++ b/crypto/ct/build.info
@@ -1,3 +1,3 @@
LIBS=../../libcrypto
-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
+SOURCE[../../libcrypto]= ct_b64.c ct_err.c ct_log.c ct_oct.c ct_policy.c \
+ ct_prn.c ct_sct.c ct_sct_ctx.c ct_vfy.c ct_x509v3.c
diff --git a/crypto/ct/ct_err.c b/crypto/ct/ct_err.c
index 6db237b..c55677c 100644
--- a/crypto/ct/ct_err.c
+++ b/crypto/ct/ct_err.c
@@ -77,7 +77,23 @@ static ERR_STRING_DATA CT_str_functs[] = {
{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_POLICY_EVAL_CTX_GET0_CERT),
+ "CT_POLICY_EVAL_CTX_get0_cert"},
+ {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_GET0_ISSUER),
+ "CT_POLICY_EVAL_CTX_get0_issuer"},
+ {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_GET0_LOG_STORE),
+ "CT_POLICY_EVAL_CTX_get0_log_store"},
+ {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_NEW), "CT_POLICY_EVAL_CTX_new"},
+ {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_SET0_CERT),
+ "CT_POLICY_EVAL_CTX_set0_cert"},
+ {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_SET0_ISSUER),
+ "CT_POLICY_EVAL_CTX_set0_issuer"},
+ {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_SET0_LOG_STORE),
+ "CT_POLICY_EVAL_CTX_set0_log_store"},
{ERR_FUNC(CT_F_CT_V1_LOG_ID_FROM_PKEY), "CT_v1_log_id_from_pkey"},
+ {ERR_FUNC(CT_F_CT_VERIFY_AT_LEAST_ONE_GOOD_SCT),
+ "CT_verify_at_least_one_good_sct"},
+ {ERR_FUNC(CT_F_CT_VERIFY_NO_BAD_SCTS), "CT_verify_no_bad_scts"},
{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"},
@@ -87,6 +103,7 @@ static ERR_STRING_DATA CT_str_functs[] = {
{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_LIST_VALIDATE), "SCT_LIST_validate"},
{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"},
@@ -97,6 +114,7 @@ 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_VALIDATE), "SCT_validate"},
{ERR_FUNC(CT_F_SCT_VERIFY), "SCT_verify"},
{ERR_FUNC(CT_F_SCT_VERIFY_V1), "SCT_verify_v1"},
{0, NULL}
@@ -111,12 +129,15 @@ static ERR_STRING_DATA CT_str_reasons[] = {
"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_NOT_ENOUGH_SCTS), "not enough scts"},
{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_SCT_VALIDATION_STATUS_NOT_SET),
+ "sct validation status not set"},
{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 fce234d..b82fabc 100644
--- a/crypto/ct/ct_locl.h
+++ b/crypto/ct/ct_locl.h
@@ -127,6 +127,8 @@ struct sct_st {
sct_source_t source;
/* The CT log that produced this SCT. */
CTLOG *log;
+ /* The result of the last attempt to validate this SCT. */
+ sct_validation_status_t validation_status;
};
/* Miscellaneous data that is useful when verifying an SCT */
@@ -147,6 +149,15 @@ struct sct_ctx_st {
size_t prederlen;
};
+/* Context when evaluating whether a Certificate Transparency policy is met */
+struct ct_policy_eval_ctx_st {
+ X509 *cert;
+ X509 *issuer;
+ CTLOG_STORE *log_store;
+ STACK_OF(SCT) *good_scts;
+ STACK_OF(SCT) *bad_scts;
+};
+
/*
* Creates a new context for verifying an SCT.
*/
diff --git a/crypto/ct/ct_policy.c b/crypto/ct/ct_policy.c
new file mode 100644
index 0000000..1236411
--- /dev/null
+++ b/crypto/ct/ct_policy.c
@@ -0,0 +1,110 @@
+/*
+* Implementations of Certificate Transparency SCT policies.
+* Written by Rob Percival (robpercival@google.com) for the OpenSSL project.
+*/
+/* ====================================================================
+* Copyright (c) 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
+* 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.
+* ====================================================================
+*/
+
+#ifdef OPENSSL_NO_CT
+# error "CT is disabled"
+#endif
+
+#include <openssl/ct.h>
+#include <openssl/err.h>
+
+#include "ct_locl.h"
+
+CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void)
+{
+ CT_POLICY_EVAL_CTX *ctx = OPENSSL_zalloc(sizeof(CT_POLICY_EVAL_CTX));
+
+ if (ctx == NULL) {
+ CTerr(CT_F_CT_POLICY_EVAL_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void CT_POLICY_EVAL_CTX_free(CT_POLICY_EVAL_CTX *ctx)
+{
+ OPENSSL_free(ctx);
+}
+
+void CT_POLICY_EVAL_CTX_set0_cert(CT_POLICY_EVAL_CTX *ctx, X509 *cert)
+{
+ ctx->cert = cert;
+}
+
+void CT_POLICY_EVAL_CTX_set0_issuer(CT_POLICY_EVAL_CTX *ctx, X509 *issuer)
+{
+ ctx->issuer = issuer;
+}
+
+void CT_POLICY_EVAL_CTX_set0_log_store(CT_POLICY_EVAL_CTX *ctx,
+ CTLOG_STORE *log_store)
+{
+ ctx->log_store = log_store;
+}
+
+X509* CT_POLICY_EVAL_CTX_get0_cert(CT_POLICY_EVAL_CTX *ctx)
+{
+ return ctx->cert;
+}
+
+X509* CT_POLICY_EVAL_CTX_get0_issuer(CT_POLICY_EVAL_CTX *ctx)
+{
+ return ctx->issuer;
+}
+
+CTLOG_STORE *CT_POLICY_EVAL_CTX_get0_log_store(CT_POLICY_EVAL_CTX *ctx)
+{
+ return ctx->log_store;
+}
+
diff --git a/crypto/ct/ct_sct.c b/crypto/ct/ct_sct.c
index e75061d..35f8152 100644
--- a/crypto/ct/ct_sct.c
+++ b/crypto/ct/ct_sct.c
@@ -356,3 +356,94 @@ int SCT_LIST_set0_logs(STACK_OF(SCT) *sct_list, const CTLOG_STORE *ct_logs)
return sct_logs_found;
}
+
+sct_validation_status_t SCT_get_validation_status(const SCT *sct)
+{
+ return sct->validation_status;
+}
+
+int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx)
+{
+ int is_sct_valid = -1;
+ SCT_CTX *sctx = NULL;
+ X509_PUBKEY *pub = NULL, *log_pkey = NULL;
+
+ switch (sct->version) {
+ case SCT_VERSION_V1:
+ if (sct->log == NULL)
+ sct->log = CTLOG_STORE_get0_log_by_id(ctx->log_store,
+ sct->log_id,
+ CT_V1_HASHLEN);
+ break;
+ default:
+ sct->validation_status = SCT_VALIDATION_STATUS_UNKNOWN_VERSION;
+ goto end;
+ }
+
+ if (sct->log == NULL) {
+ sct->validation_status = SCT_VALIDATION_STATUS_UNKNOWN_LOG;
+ goto end;
+ }
+
+ sctx = SCT_CTX_new();
+ if (sctx == NULL)
+ goto err;
+
+ if (X509_PUBKEY_set(&log_pkey, CTLOG_get0_public_key(sct->log)) != 1)
+ goto err;
+ if (SCT_CTX_set1_pubkey(sctx, log_pkey) != 1)
+ goto err;
+
+ if (SCT_get_log_entry_type(sct) == CT_LOG_ENTRY_TYPE_PRECERT) {
+ EVP_PKEY *issuer_pkey;
+
+ if (ctx->issuer == NULL) {
+ sct->validation_status = SCT_VALIDATION_STATUS_UNVERIFIED;
+ goto end;
+ }
+
+ issuer_pkey = X509_get_pubkey(ctx->issuer);
+
+ if (X509_PUBKEY_set(&pub, issuer_pkey) != 1)
+ goto err;
+ if (SCT_CTX_set1_issuer_pubkey(sctx, pub) != 1)
+ goto err;
+ }
+
+ if (SCT_CTX_set1_cert(sctx, ctx->cert, NULL) != 1)
+ goto err;
+
+ sct->validation_status = SCT_verify(sctx, sct) == 1 ?
+ SCT_VALIDATION_STATUS_VALID : SCT_VALIDATION_STATUS_INVALID;
+
+end:
+ is_sct_valid = sct->validation_status == SCT_VALIDATION_STATUS_VALID;
+err:
+ X509_PUBKEY_free(pub);
+ X509_PUBKEY_free(log_pkey);
+ SCT_CTX_free(sctx);
+
+ return is_sct_valid;
+}
+
+int SCT_LIST_validate(const STACK_OF(SCT) *scts, CT_POLICY_EVAL_CTX *ctx)
+{
+ int are_scts_valid = 1;
+ int sct_count = scts != NULL ? sk_SCT_num(scts) : 0;
+ int i;
+
+ for (i = 0; i < sct_count; ++i) {
+ int is_sct_valid = -1;
+ SCT *sct = sk_SCT_value(scts, i);
+
+ if (sct == NULL)
+ continue;
+
+ is_sct_valid = SCT_validate(sct, ctx);
+ if (is_sct_valid < 0)
+ return is_sct_valid;
+ are_scts_valid &= is_sct_valid;
+ }
+
+ return are_scts_valid;
+}
diff --git a/crypto/ct/ct_vfy.c b/crypto/ct/ct_vfy.c
index 5705312..2366783 100644
--- a/crypto/ct/ct_vfy.c
+++ b/crypto/ct/ct_vfy.c
@@ -71,6 +71,65 @@ typedef enum sct_signature_type_t {
SIGNATURE_TYPE_TREE_HASH
} SCT_SIGNATURE_TYPE;
+int CT_verify_no_bad_scts(const CT_POLICY_EVAL_CTX *ctx,
+ const STACK_OF(SCT) *scts, void *arg)
+{
+ int sct_count = scts != NULL ? sk_SCT_num(scts) : 0;
+ int i;
+
+ for (i = 0; i < sct_count; ++i) {
+ SCT *sct = sk_SCT_value(scts, i);
+
+ switch (SCT_get_validation_status(sct)) {
+ case SCT_VALIDATION_STATUS_INVALID:
+ return 0;
+ case SCT_VALIDATION_STATUS_NOT_SET:
+ CTerr(CT_F_CT_VERIFY_NO_BAD_SCTS,
+ CT_R_SCT_VALIDATION_STATUS_NOT_SET);
+ return -1;
+ default:
+ /* Ignore other validation statuses. */
+ break;
+ }
+ }
+
+ return 1;
+}
+
+int CT_verify_at_least_one_good_sct(const CT_POLICY_EVAL_CTX *ctx,
+ const STACK_OF(SCT) *scts, void *arg)
+{
+ int sct_count = scts != NULL ? sk_SCT_num(scts) : 0;
+ int valid_scts = 0;
+ int i;
+
+ for (i = 0; i < sct_count; ++i) {
+ SCT *sct = sk_SCT_value(scts, i);
+
+ switch (SCT_get_validation_status(sct)) {
+ case SCT_VALIDATION_STATUS_VALID:
+ ++valid_scts;
+ break;
+ case SCT_VALIDATION_STATUS_INVALID:
+ return 0;
+ case SCT_VALIDATION_STATUS_NOT_SET:
+ CTerr(CT_F_CT_VERIFY_AT_LEAST_ONE_GOOD_SCT,
+ CT_R_SCT_VALIDATION_STATUS_NOT_SET);
+ return -1;
+ default:
+ /* Ignore other validation statuses. */
+ break;
+ }
+ }
+
+ if (valid_scts == 0) {
+ CTerr(CT_F_CT_VERIFY_AT_LEAST_ONE_GOOD_SCT, CT_R_NOT_ENOUGH_SCTS);
+ return 0;
+ }
+
+ return 1;
+}
+
/*
* Update encoding for SCT signature verification/generation to supplied
* EVP_MD_CTX.