diff options
author | Rob Percival <robpercival@google.com> | 2016-02-29 17:33:02 +0000 |
---|---|---|
committer | Rob Percival <robpercival@google.com> | 2016-03-01 20:03:25 +0000 |
commit | 7d054e5ab2aeaead14c0c19b808d62221020b0e1 (patch) | |
tree | 655006eea9d0fe60879b36d09e9046be5a3749de /crypto/ct | |
parent | 7852414967b87400b08bfdf321732cfbd07286e2 (diff) | |
download | openssl-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.in | 8 | ||||
-rw-r--r-- | crypto/ct/build.info | 4 | ||||
-rw-r--r-- | crypto/ct/ct_err.c | 21 | ||||
-rw-r--r-- | crypto/ct/ct_locl.h | 11 | ||||
-rw-r--r-- | crypto/ct/ct_policy.c | 110 | ||||
-rw-r--r-- | crypto/ct/ct_sct.c | 91 | ||||
-rw-r--r-- | crypto/ct/ct_vfy.c | 59 |
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. |