From d4b2bfbadecd64de298d37ef6eb90a829da01a6a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 3 Apr 2020 16:25:18 +0100 Subject: [PATCH] Make the CT code library context aware Add the new functions CTLOG_STORE_new_with_libctx(), CTLOG_new_with_libctx() and CTLOG_new_from_base64_with_libctx() to pass in the library context/property query string to use a library context is to be used. We also add the function CT_POLICY_EVAL_CTX_new_with_libctx() to enable the creation of a CT_POLICY_EVAL_CTX to be associated with a libctx and property query string. Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/11483) --- crypto/ct/ct_b64.c | 19 ++++++++--- crypto/ct/ct_local.h | 8 ++++- crypto/ct/ct_log.c | 74 ++++++++++++++++++++++++++++++++++-------- crypto/ct/ct_policy.c | 20 ++++++++++-- crypto/ct/ct_sct.c | 2 +- crypto/ct/ct_sct_ctx.c | 28 ++++++++++++---- crypto/ct/ct_vfy.c | 3 +- include/openssl/ct.h | 44 ++++++++++++++++++++++--- util/libcrypto.num | 4 +++ 9 files changed, 168 insertions(+), 34 deletions(-) diff --git a/crypto/ct/ct_b64.c b/crypto/ct/ct_b64.c index f080088289..2e00cf3e15 100644 --- a/crypto/ct/ct_b64.c +++ b/crypto/ct/ct_b64.c @@ -132,7 +132,9 @@ SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64, * 0 on decoding failure, or invalid parameter if any * -1 on internal (malloc) failure */ -int CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *name) +int CTLOG_new_from_base64_with_libctx(CTLOG **ct_log, const char *pkey_base64, + const char *name, OPENSSL_CTX *libctx, + const char *propq) { unsigned char *pkey_der = NULL; int pkey_der_len; @@ -140,13 +142,13 @@ int CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *n EVP_PKEY *pkey = NULL; if (ct_log == NULL) { - CTerr(CT_F_CTLOG_NEW_FROM_BASE64, ERR_R_PASSED_INVALID_ARGUMENT); + CTerr(0, ERR_R_PASSED_INVALID_ARGUMENT); return 0; } 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); + CTerr(0, CT_R_LOG_CONF_INVALID_KEY); return 0; } @@ -154,11 +156,11 @@ int CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *n pkey = d2i_PUBKEY(NULL, &p, pkey_der_len); OPENSSL_free(pkey_der); if (pkey == NULL) { - CTerr(CT_F_CTLOG_NEW_FROM_BASE64, CT_R_LOG_CONF_INVALID_KEY); + CTerr(0, CT_R_LOG_CONF_INVALID_KEY); return 0; } - *ct_log = CTLOG_new(pkey, name); + *ct_log = CTLOG_new_with_libctx(pkey, name, libctx, propq); if (*ct_log == NULL) { EVP_PKEY_free(pkey); return 0; @@ -166,3 +168,10 @@ int CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *n return 1; } + +int CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, + const char *name) +{ + return CTLOG_new_from_base64_with_libctx(ct_log, pkey_base64, name, NULL, + NULL); +} diff --git a/crypto/ct/ct_local.h b/crypto/ct/ct_local.h index 456217db28..0df2f37fba 100644 --- a/crypto/ct/ct_local.h +++ b/crypto/ct/ct_local.h @@ -100,6 +100,9 @@ struct sct_ctx_st { size_t prederlen; /* milliseconds since epoch (to check that the SCT isn't from the future) */ uint64_t epoch_time_in_ms; + + OPENSSL_CTX *libctx; + char *propq; }; /* Context when evaluating whether a Certificate Transparency policy is met */ @@ -109,12 +112,15 @@ struct ct_policy_eval_ctx_st { CTLOG_STORE *log_store; /* milliseconds since epoch (to check that SCTs aren't from the future) */ uint64_t epoch_time_in_ms; + + OPENSSL_CTX *libctx; + char *propq; }; /* * Creates a new context for verifying an SCT. */ -SCT_CTX *SCT_CTX_new(void); +SCT_CTX *SCT_CTX_new(OPENSSL_CTX *ctx, const char *propq); /* * Deletes an SCT verification context. */ diff --git a/crypto/ct/ct_log.c b/crypto/ct/ct_log.c index 695221cba0..3da71c3247 100644 --- a/crypto/ct/ct_log.c +++ b/crypto/ct/ct_log.c @@ -22,6 +22,8 @@ * Information about a CT log server. */ struct ctlog_st { + OPENSSL_CTX *libctx; + char *propq; char *name; uint8_t log_id[CT_V1_HASHLEN]; EVP_PKEY *public_key; @@ -32,6 +34,8 @@ struct ctlog_st { * It takes ownership of any CTLOG instances added to it. */ struct ctlog_store_st { + OPENSSL_CTX *libctx; + char *propq; STACK_OF(CTLOG) *logs; }; @@ -70,53 +74,78 @@ static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* 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]) +static int ct_v1_log_id_from_pkey(CTLOG *log, EVP_PKEY *pkey) { int ret = 0; unsigned char *pkey_der = NULL; int pkey_der_len = i2d_PUBKEY(pkey, &pkey_der); unsigned int len; + EVP_MD *sha256 = NULL; if (pkey_der_len <= 0) { CTerr(CT_F_CT_V1_LOG_ID_FROM_PKEY, CT_R_LOG_KEY_INVALID); goto err; } + sha256 = EVP_MD_fetch(log->libctx, "SHA2-256", log->propq); + if (sha256 == NULL) { + CTerr(CT_F_CT_V1_LOG_ID_FROM_PKEY, ERR_LIB_EVP); + goto err; + } - ret = EVP_Digest(pkey_der, pkey_der_len, log_id, &len, EVP_sha256(), NULL); + ret = EVP_Digest(pkey_der, pkey_der_len, log->log_id, &len, sha256, + NULL); err: + EVP_MD_free(sha256); OPENSSL_free(pkey_der); return ret; } -CTLOG_STORE *CTLOG_STORE_new(void) +CTLOG_STORE *CTLOG_STORE_new_with_libctx(OPENSSL_CTX *libctx, const char *propq) { CTLOG_STORE *ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { - CTerr(CT_F_CTLOG_STORE_NEW, ERR_R_MALLOC_FAILURE); + CTerr(0, ERR_R_MALLOC_FAILURE); return NULL; } + ret->libctx = libctx; + if (propq != NULL) { + ret->propq = OPENSSL_strdup(propq); + if (ret->propq == NULL) { + CTerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } + } + ret->logs = sk_CTLOG_new_null(); - if (ret->logs == NULL) + if (ret->logs == NULL) { + CTerr(0, ERR_R_MALLOC_FAILURE); goto err; + } return ret; err: - OPENSSL_free(ret); + CTLOG_STORE_free(ret); return NULL; } +CTLOG_STORE *CTLOG_STORE_new(void) +{ + return CTLOG_STORE_new_with_libctx(NULL, NULL); +} + void CTLOG_STORE_free(CTLOG_STORE *store) { if (store != NULL) { + OPENSSL_free(store->propq); sk_CTLOG_pop_free(store->logs, CTLOG_free); OPENSSL_free(store); } } -static int ctlog_new_from_conf(CTLOG **ct_log, const CONF *conf, const char *section) +static int ctlog_new_from_conf(CTLOG_STORE *store, CTLOG **ct_log, + const CONF *conf, const char *section) { const char *description = NCONF_get_string(conf, section, "description"); char *pkey_base64; @@ -132,7 +161,8 @@ static int ctlog_new_from_conf(CTLOG **ct_log, const CONF *conf, const char *sec return 0; } - return CTLOG_new_from_base64(ct_log, pkey_base64, description); + return CTLOG_new_from_base64_with_libctx(ct_log, pkey_base64, description, + store->libctx, store->propq); } int CTLOG_STORE_load_default_file(CTLOG_STORE *store) @@ -168,7 +198,7 @@ static int ctlog_store_load_log(const char *log_name, int log_name_len, if (tmp == NULL) goto mem_err; - ret = ctlog_new_from_conf(&ct_log, load_ctx->conf, tmp); + ret = ctlog_new_from_conf(load_ctx->log_store, &ct_log, load_ctx->conf, tmp); OPENSSL_free(tmp); if (ret < 0) { @@ -234,22 +264,32 @@ end: * Takes ownership of the public key. * Copies the name. */ -CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name) +CTLOG *CTLOG_new_with_libctx(EVP_PKEY *public_key, const char *name, + OPENSSL_CTX *libctx, const char *propq) { CTLOG *ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { - CTerr(CT_F_CTLOG_NEW, ERR_R_MALLOC_FAILURE); + CTerr(0, ERR_R_MALLOC_FAILURE); return NULL; } + ret->libctx = libctx; + if (propq != NULL) { + ret->name = OPENSSL_strdup(propq); + if (ret->propq == NULL) { + CTerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } + } + ret->name = OPENSSL_strdup(name); if (ret->name == NULL) { - CTerr(CT_F_CTLOG_NEW, ERR_R_MALLOC_FAILURE); + CTerr(0, ERR_R_MALLOC_FAILURE); goto err; } - if (ct_v1_log_id_from_pkey(public_key, ret->log_id) != 1) + if (ct_v1_log_id_from_pkey(ret, public_key) != 1) goto err; ret->public_key = public_key; @@ -259,12 +299,18 @@ err: return NULL; } +CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name) +{ + return CTLOG_new_with_libctx(public_key, name, NULL, NULL); +} + /* Frees CT log and associated structures */ void CTLOG_free(CTLOG *log) { if (log != NULL) { OPENSSL_free(log->name); EVP_PKEY_free(log->public_key); + OPENSSL_free(log->propq); OPENSSL_free(log); } } diff --git a/crypto/ct/ct_policy.c b/crypto/ct/ct_policy.c index 0305970a94..568d8e6d64 100644 --- a/crypto/ct/ct_policy.c +++ b/crypto/ct/ct_policy.c @@ -25,15 +25,25 @@ */ static const time_t SCT_CLOCK_DRIFT_TOLERANCE = 300; -CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void) +CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new_with_libctx(OPENSSL_CTX *libctx, + const char *propq) { 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); + CTerr(0, ERR_R_MALLOC_FAILURE); return NULL; } + ctx->libctx = libctx; + if (propq != NULL) { + ctx->propq = OPENSSL_strdup(propq); + if (ctx->propq == NULL) { + CTerr(0, ERR_R_MALLOC_FAILURE); + return NULL; + } + } + /* time(NULL) shouldn't ever fail, so don't bother checking for -1. */ ctx->epoch_time_in_ms = (uint64_t)(time(NULL) + SCT_CLOCK_DRIFT_TOLERANCE) * 1000; @@ -41,12 +51,18 @@ CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void) return ctx; } +CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void) +{ + return CT_POLICY_EVAL_CTX_new_with_libctx(NULL, NULL); +} + void CT_POLICY_EVAL_CTX_free(CT_POLICY_EVAL_CTX *ctx) { if (ctx == NULL) return; X509_free(ctx->cert); X509_free(ctx->issuer); + OPENSSL_free(ctx->propq); OPENSSL_free(ctx); } diff --git a/crypto/ct/ct_sct.c b/crypto/ct/ct_sct.c index bd510d9edb..aecaf9e11e 100644 --- a/crypto/ct/ct_sct.c +++ b/crypto/ct/ct_sct.c @@ -312,7 +312,7 @@ int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx) return 0; } - sctx = SCT_CTX_new(); + sctx = SCT_CTX_new(ctx->libctx, ctx->propq); if (sctx == NULL) goto err; diff --git a/crypto/ct/ct_sct_ctx.c b/crypto/ct/ct_sct_ctx.c index aa9d2d75ef..f8ed6b8d4c 100644 --- a/crypto/ct/ct_sct_ctx.c +++ b/crypto/ct/ct_sct_ctx.c @@ -20,13 +20,23 @@ #include "ct_local.h" -SCT_CTX *SCT_CTX_new(void) +SCT_CTX *SCT_CTX_new(OPENSSL_CTX *libctx, const char *propq) { SCT_CTX *sctx = OPENSSL_zalloc(sizeof(*sctx)); if (sctx == NULL) CTerr(CT_F_SCT_CTX_NEW, ERR_R_MALLOC_FAILURE); + sctx->libctx = libctx; + if (propq != NULL) { + sctx->propq = OPENSSL_strdup(propq); + if (sctx->propq == NULL) { + CTerr(CT_F_SCT_CTX_NEW, ERR_R_MALLOC_FAILURE); + OPENSSL_free(sctx); + return NULL; + } + } + return sctx; } @@ -39,6 +49,7 @@ void SCT_CTX_free(SCT_CTX *sctx) OPENSSL_free(sctx->ihash); OPENSSL_free(sctx->certder); OPENSSL_free(sctx->preder); + OPENSSL_free(sctx->propq); OPENSSL_free(sctx); } @@ -191,13 +202,17 @@ err: return 0; } -__owur static int ct_public_key_hash(X509_PUBKEY *pkey, unsigned char **hash, - size_t *hash_len) +__owur static int ct_public_key_hash(SCT_CTX *sctx, X509_PUBKEY *pkey, + unsigned char **hash, size_t *hash_len) { int ret = 0; unsigned char *md = NULL, *der = NULL; int der_len; unsigned int md_len; + EVP_MD *sha256 = EVP_MD_fetch(sctx->libctx, "SHA2-256", sctx->propq); + + if (sha256 == NULL) + goto err; /* Reuse buffer if possible */ if (*hash != NULL && *hash_len >= SHA256_DIGEST_LENGTH) { @@ -213,7 +228,7 @@ __owur static int ct_public_key_hash(X509_PUBKEY *pkey, unsigned char **hash, if (der_len <= 0) goto err; - if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha256(), NULL)) + if (!EVP_Digest(der, der_len, md, &md_len, sha256, NULL)) goto err; if (md != *hash) { @@ -225,6 +240,7 @@ __owur static int ct_public_key_hash(X509_PUBKEY *pkey, unsigned char **hash, md = NULL; ret = 1; err: + EVP_MD_free(sha256); OPENSSL_free(md); OPENSSL_free(der); return ret; @@ -237,7 +253,7 @@ int SCT_CTX_set1_issuer(SCT_CTX *sctx, const X509 *issuer) int SCT_CTX_set1_issuer_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey) { - return ct_public_key_hash(pubkey, &sctx->ihash, &sctx->ihashlen); + return ct_public_key_hash(sctx, pubkey, &sctx->ihash, &sctx->ihashlen); } int SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey) @@ -247,7 +263,7 @@ int SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey) if (pkey == NULL) return 0; - if (!ct_public_key_hash(pubkey, &sctx->pkeyhash, &sctx->pkeyhashlen)) { + if (!ct_public_key_hash(sctx, pubkey, &sctx->pkeyhash, &sctx->pkeyhashlen)) { EVP_PKEY_free(pkey); return 0; } diff --git a/crypto/ct/ct_vfy.c b/crypto/ct/ct_vfy.c index f206edd061..1a14324139 100644 --- a/crypto/ct/ct_vfy.c +++ b/crypto/ct/ct_vfy.c @@ -122,7 +122,8 @@ int SCT_CTX_verify(const SCT_CTX *sctx, const SCT *sct) if (ctx == NULL) goto end; - if (!EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, sctx->pkey)) + if (!EVP_DigestVerifyInit_ex(ctx, NULL, "SHA2-256", sctx->propq, sctx->pkey, + sctx->libctx)) goto end; if (!sct_ctx_update(ctx, sctx, sct)) diff --git a/include/openssl/ct.h b/include/openssl/ct.h index b7c211d920..489f1ad472 100644 --- a/include/openssl/ct.h +++ b/include/openssl/ct.h @@ -69,10 +69,18 @@ DEFINE_STACK_OF(CTLOG) ******************************************/ /* - * Creates a new, empty policy evaluation context. + * Creates a new, empty policy evaluation context associated with the given + * library context and property query string. * The caller is responsible for calling CT_POLICY_EVAL_CTX_free when finished * with the CT_POLICY_EVAL_CTX. */ +CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new_with_libctx(OPENSSL_CTX *libctx, + const char *propq); + +/* + * The same as CT_POLICY_EVAL_CTX_new_with_libctx() but the default library + * context and property query string is used. + */ CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void); /* Deletes a policy evaluation context and anything it owns. */ @@ -409,19 +417,39 @@ SCT *o2i_SCT(SCT **psct, const unsigned char **in, size_t len); ********************/ /* - * Creates a new CT log instance with the given |public_key| and |name|. + * Creates a new CT log instance with the given |public_key| and |name| and + * associates it with the give library context |libctx| and property query + * string |propq|. * Takes ownership of |public_key| but copies |name|. * Returns NULL if malloc fails or if |public_key| cannot be converted to DER. * Should be deleted by the caller using CTLOG_free when no longer needed. */ +CTLOG *CTLOG_new_with_libctx(EVP_PKEY *public_key, const char *name, + OPENSSL_CTX *libctx, const char *propq); + +/* + * The same as CTLOG_new_with_libctx except that the default library context and + * property query string are used. + */ CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name); /* * Creates a new CTLOG instance with the base64-encoded SubjectPublicKeyInfo DER - * in |pkey_base64|. The |name| is a string to help users identify this log. + * in |pkey_base64| and associated with the given library context |libctx| and + * property query string |propq|. The |name| is a string to help users identify + * this log. * Returns 1 on success, 0 on failure. * Should be deleted by the caller using CTLOG_free when no longer needed. */ +int CTLOG_new_from_base64_with_libctx(CTLOG **ct_log, const char *pkey_base64, + const char *name, OPENSSL_CTX *libctx, + const char *propq); + +/* + * The same as CTLOG_new_from_base64_with_libctx() except that the default + * library context and property query string are used. + * Returns 1 on success, 0 on failure. + */ int CTLOG_new_from_base64(CTLOG ** ct_log, const char *pkey_base64, const char *name); @@ -443,7 +471,15 @@ EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log); **************************/ /* - * Creates a new CT log store. + * Creates a new CT log store and associates it with the given libctx and + * property query string. + * Should be deleted by the caller using CTLOG_STORE_free when no longer needed. + */ +CTLOG_STORE *CTLOG_STORE_new_with_libctx(OPENSSL_CTX *libctx, const char *propq); + +/* + * Same as CTLOG_STORE_new_with_libctx except that the default libctx and + * property query string are used. * Should be deleted by the caller using CTLOG_STORE_free when no longer needed. */ CTLOG_STORE *CTLOG_STORE_new(void); diff --git a/util/libcrypto.num b/util/libcrypto.num index 60050c1830..71d08750be 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5041,3 +5041,7 @@ EVP_PKEY_is_a ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_can_sign ? 3_0_0 EXIST::FUNCTION: evp_pkey_get_EC_KEY_curve_nid ? 3_0_0 EXIST::FUNCTION:EC X509_STORE_CTX_new_with_libctx ? 3_0_0 EXIST::FUNCTION: +CT_POLICY_EVAL_CTX_new_with_libctx ? 3_0_0 EXIST::FUNCTION:CT +CTLOG_new_with_libctx ? 3_0_0 EXIST::FUNCTION:CT +CTLOG_new_from_base64_with_libctx ? 3_0_0 EXIST::FUNCTION:CT +CTLOG_STORE_new_with_libctx ? 3_0_0 EXIST::FUNCTION:CT -- 2.34.1