From: Jeremy Harris Date: Sat, 12 Nov 2016 20:16:31 +0000 (+0000) Subject: DANE: Bitrot: Port to OpenSSL >= 1.1.0 X-Git-Tag: exim-4_88_RC5~12 X-Git-Url: https://git.exim.org/users/heiko/exim.git/commitdiff_plain/3376de6c7c6353f76d8e722d7e1896f32eab488c?hp=e3555426308395ef260b0dae4548593ac114aed5 DANE: Bitrot: Port to OpenSSL >= 1.1.0 --- diff --git a/src/src/dane-openssl.c b/src/src/dane-openssl.c index 6c2b1dbde..62778d18f 100644 --- a/src/src/dane-openssl.c +++ b/src/src/dane-openssl.c @@ -20,7 +20,7 @@ #if OPENSSL_VERSION_NUMBER < 0x1000000fL # error "OpenSSL 1.0.0 or higher required" -#else /* remainder of file */ +#endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) # define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509) @@ -39,6 +39,14 @@ # define X509_STORE_CTX_set0_verified_chain(ctx, sk) (ctx)->chain = (sk) # define X509_STORE_CTX_set_error_depth(ctx, val) (ctx)->error_depth = (val) # define X509_STORE_CTX_set_current_cert(ctx, cert) (ctx)->current_cert = (cert) + +# define ASN1_STRING_get0_data ASN1_STRING_data +# define X509_getm_notBefore X509_get_notBefore +# define X509_getm_notAfter X509_get_notAfter + +# define CRYPTO_ONCE_STATIC_INIT 0 +# define CRYPTO_THREAD_run_once run_once +typedef int CRYPTO_ONCE; #endif @@ -57,6 +65,7 @@ #define DANESSL_F_SET_TRUST_ANCHOR 110 #define DANESSL_F_VERIFY_CERT 111 #define DANESSL_F_WRAP_CERT 112 +#define DANESSL_F_DANESSL_VERIFY_CHAIN 113 #define DANESSL_R_BAD_CERT 100 #define DANESSL_R_BAD_CERT_PKEY 101 @@ -293,13 +302,14 @@ return matched; static int push_ext(X509 *cert, X509_EXTENSION *ext) { - if (ext) { - if (X509_add_ext(cert, ext, -1)) - return 1; - X509_EXTENSION_free(ext); - } - DANEerr(DANESSL_F_PUSH_EXT, ERR_R_MALLOC_FAILURE); - return 0; +if (ext) + { + if (X509_add_ext(cert, ext, -1)) + return 1; + X509_EXTENSION_free(ext); + } +DANEerr(DANESSL_F_PUSH_EXT, ERR_R_MALLOC_FAILURE); +return 0; } static int @@ -338,7 +348,7 @@ static int add_akid(X509 *cert, AUTHORITY_KEYID *akid) { int nid = NID_authority_key_identifier; -ASN1_STRING *id; +ASN1_OCTET_STRING *id; unsigned char c = 0; int ret = 0; @@ -349,8 +359,8 @@ int ret = 0; * exempt from any potential (off by default for now in OpenSSL) * self-signature checks! */ -id = (akid && akid->keyid) ? akid->keyid : 0; -if (id && ASN1_STRING_length(id) == 1 && *ASN1_STRING_data(id) == c) +id = akid && akid->keyid ? akid->keyid : 0; +if (id && ASN1_STRING_length(id) == 1 && *ASN1_STRING_get0_data(id) == c) c = 1; if ( (akid = AUTHORITY_KEYID_new()) != 0 @@ -488,10 +498,10 @@ akid = X509_get_ext_d2i(subject, NID_authority_key_identifier, 0, 0); */ if ( !X509_set_version(cert, 2) || !set_serial(cert, akid, subject) - || !X509_set_subject_name(cert, name) || !set_issuer_name(cert, akid) - || !X509_gmtime_adj(X509_get_notBefore(cert), -30 * 86400L) - || !X509_gmtime_adj(X509_get_notAfter(cert), 30 * 86400L) + || !X509_gmtime_adj(X509_getm_notBefore(cert), -30 * 86400L) + || !X509_gmtime_adj(X509_getm_notAfter(cert), 30 * 86400L) + || !X509_set_subject_name(cert, name) || !X509_set_pubkey(cert, newkey) || !add_ext(0, cert, NID_basic_constraints, "CA:TRUE") || (!top && !add_akid(cert, akid)) @@ -719,11 +729,12 @@ if (matched > 0) STACK_OF(X509) * sk = sk_X509_new_null(); if (sk && sk_X509_push(sk, cert)) { - X509_STORE_CTX_set0_verified_chain(ctx, sk); X509_up_ref(cert); + X509_STORE_CTX_set0_verified_chain(ctx, sk); } else { + if (sk) sk_X509_free(sk); DANEerr(DANESSL_F_CHECK_END_ENTITY, ERR_R_MALLOC_FAILURE); return -1; } @@ -780,10 +791,10 @@ for (hosts = dane->hosts; hosts; hosts = hosts->next) return 0; } -static char * -check_name(char *name, int len) +static const char * +check_name(const char *name, int len) { -char *cp = name + len; +const char *cp = name + len; while (len > 0 && !*--cp) --len; /* Ignore trailing NULs */ @@ -804,14 +815,14 @@ if (cp - name != len) /* Guard against internal NULs */ return name; } -static char * +static const char * parse_dns_name(const GENERAL_NAME *gn) { if (gn->type != GEN_DNS) return 0; if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) return 0; -return check_name((char *) ASN1_STRING_data(gn->d.ia5), +return check_name((const char *) ASN1_STRING_get0_data(gn->d.ia5), ASN1_STRING_length(gn->d.ia5)); } @@ -901,7 +912,8 @@ verify_chain(X509_STORE_CTX *ctx) { int (*cb)(int, X509_STORE_CTX *) = X509_STORE_CTX_get_verify_cb(ctx); X509 *cert = X509_STORE_CTX_get0_cert(ctx); -int chain_length = sk_X509_num(X509_STORE_CTX_get0_chain(ctx)); +STACK_OF(X509) * chain = X509_STORE_CTX_get0_chain(ctx); +int chain_length = sk_X509_num(chain); int ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx(); SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, ssl_idx); ssl_dane *dane = SSL_get_ex_data(ssl, dane_idx); @@ -911,6 +923,7 @@ int matched = 0; DEBUG(D_tls) debug_printf("Dane verify_chain\n"); +/* Restore OpenSSL's internal_verify() as the signature check function */ X509_STORE_CTX_set_verify(ctx, dane->verify); if ((matched = name_check(dane, cert)) < 0) @@ -934,17 +947,17 @@ matched = 0; * matched a usage 2 trust anchor. * * XXX: internal_verify() doesn't callback with top certs that are not - * self-issued. This should be fixed in a future OpenSSL. + * self-issued. This is fixed in OpenSSL 1.1.0. */ if (dane->roots && sk_X509_num(dane->roots)) { - X509 *top = sk_X509_value(X509_STORE_CTX_get0_chain(ctx), dane->depth); + X509 *top = sk_X509_value(chain, dane->depth); dane->mdpth = dane->depth; dane->match = top; X509_up_ref(top); -#ifndef NO_CALLBACK_WORKAROUND +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (X509_check_issued(top, top) != X509_V_OK) { X509_STORE_CTX_set_error_depth(ctx, dane->depth); @@ -955,7 +968,7 @@ if (dane->roots && sk_X509_num(dane->roots)) #endif /* Pop synthetic trust-anchor ancestors off the chain! */ while (--chain_length > dane->depth) - X509_free(sk_X509_pop(X509_STORE_CTX_get0_chain(ctx))); + X509_free(sk_X509_pop(chain)); } else { @@ -973,7 +986,7 @@ else if (!matched && issuer_rrs) for (n = chain_length-1; !matched && n >= 0; --n) { - xn = sk_X509_value(X509_STORE_CTX_get0_chain(ctx), n); + xn = sk_X509_value(chain, n); if (n > 0 || X509_check_issued(xn, xn) == X509_V_OK) matched = match(issuer_rrs, xn, n); } @@ -996,7 +1009,8 @@ else } } -return (X509_STORE_CTX_get_verify(ctx))(ctx); +/* Tail recurse into OpenSSL's internal_verify */ +return dane->verify(ctx); } static void @@ -1083,7 +1097,7 @@ if (dane->selectors[DANESSL_USAGE_DANE_EE]) */ X509_STORE_CTX_trusted_stack(ctx, dane->roots); X509_STORE_CTX_set_chain(ctx, dane->chain); - OPENSSL_assert(X509_STORE_CTX_get0_untrusted(ctx) == dane->chain); + OPENSSL_assert(dane->chain == X509_STORE_CTX_get0_untrusted(ctx)); } } @@ -1153,10 +1167,16 @@ for (head = (dane_list) list; head; head = next) } } +static void +ossl_free(void * p) +{ +OPENSSL_free(p); +} + static void dane_mtype_free(void *p) { -list_free(((dane_mtype) p)->data, CRYPTO_free); +list_free(((dane_mtype) p)->data, ossl_free); OPENSSL_free(p); } @@ -1197,7 +1217,7 @@ if (dane_idx < 0 || !(dane = SSL_get_ex_data(ssl, dane_idx))) dane_reset(dane); if (dane->hosts) - list_free(dane->hosts, CRYPTO_free); + list_free(dane->hosts, ossl_free); for (u = 0; u <= DANESSL_USAGE_LAST; ++u) if (dane->selectors[u]) list_free(dane->selectors[u], dane_selector_free); @@ -1218,7 +1238,7 @@ while (*src) dane_host_list elem = (dane_host_list) OPENSSL_malloc(sizeof(*elem)); if (elem == 0) { - list_free(head, CRYPTO_free); + list_free(head, ossl_free); return 0; } elem->value = OPENSSL_strdup(*src++); @@ -1259,28 +1279,36 @@ DANESSL_verify_chain(SSL *ssl, STACK_OF(X509) *chain) { int ret; X509 *cert; -X509_STORE_CTX store_ctx; +X509_STORE_CTX * store_ctx; SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(ssl); X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); int store_ctx_idx = SSL_get_ex_data_X509_STORE_CTX_idx(); cert = sk_X509_value(chain, 0); -if (!X509_STORE_CTX_init(&store_ctx, store, cert, chain)) +if (!(store_ctx = X509_STORE_CTX_new())) + { + DANEerr(DANESSL_F_DANESSL_VERIFY_CHAIN, ERR_R_MALLOC_FAILURE); + return 0; + } +if (!X509_STORE_CTX_init(store_ctx, store, cert, chain)) + { + X509_STORE_CTX_free(store_ctx); return 0; -X509_STORE_CTX_set_ex_data(&store_ctx, store_ctx_idx, ssl); + } +X509_STORE_CTX_set_ex_data(store_ctx, store_ctx_idx, ssl); -X509_STORE_CTX_set_default(&store_ctx, +X509_STORE_CTX_set_default(store_ctx, SSL_is_server(ssl) ? "ssl_client" : "ssl_server"); -X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&store_ctx), +X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx), SSL_get0_param(ssl)); if (SSL_get_verify_callback(ssl)) - X509_STORE_CTX_set_verify_cb(&store_ctx, SSL_get_verify_callback(ssl)); + X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl)); -ret = verify_cert(&store_ctx, NULL); +ret = verify_cert(store_ctx, NULL); -SSL_set_verify_result(ssl, X509_STORE_CTX_get_error(&store_ctx)); -X509_STORE_CTX_cleanup(&store_ctx); +SSL_set_verify_result(ssl, X509_STORE_CTX_get_error(store_ctx)); +X509_STORE_CTX_cleanup(store_ctx); return (ret); } @@ -1449,7 +1477,7 @@ if (!m) { if ((m = (dane_mtype_list) list_alloc(sizeof(*m->value))) == 0) { - list_free(d, CRYPTO_free); + list_free(d, ossl_free); xkfreeret(0); } m->value->data = 0; @@ -1590,31 +1618,6 @@ DANEerr(DANESSL_F_CTX_INIT, DANESSL_R_LIBRARY_INIT); return -1; } -static int -init_once(volatile int *value, int (*init)(void), void (*postinit)(void)) -{ -int wlock = 0; - -CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); -if (*value < 0) - { - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); - CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); - wlock = 1; - if (*value < 0) - { - *value = init(); - if (postinit) - postinit(); - } - } -if (wlock) - CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); -else - CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); -return *value; -} - static void dane_init(void) { @@ -1622,10 +1625,15 @@ dane_init(void) * Store library id in zeroth function slot, used to locate the library * name. This must be done before we load the error strings. */ +err_lib_dane = ERR_get_next_error_library(); + #ifndef OPENSSL_NO_ERR -dane_str_functs[0].error |= ERR_PACK(err_lib_dane, 0, 0); -ERR_load_strings(err_lib_dane, dane_str_functs); -ERR_load_strings(err_lib_dane, dane_str_reasons); +if (err_lib_dane > 0) + { + dane_str_functs[0].error |= ERR_PACK(err_lib_dane, 0, 0); + ERR_load_strings(err_lib_dane, dane_str_functs); + ERR_load_strings(err_lib_dane, dane_str_reasons); + } #endif /* @@ -1650,6 +1658,32 @@ dane_idx = SSL_get_ex_new_index(0, 0, 0, 0, 0); } +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static void +run_once(volatile int * once, void (*init)(void)) +{ +int wlock = 0; + +CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); +if (!*once) + { + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + wlock = 1; + if (!*once) + { + *once = 1; + init(); + } + } +if (wlock) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); +else + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); +} +#endif + + /* @@ -1666,9 +1700,10 @@ Return int DANESSL_library_init(void) { +static CRYPTO_ONCE once = CRYPTO_ONCE_STATIC_INIT; + DEBUG(D_tls) debug_printf("Dane lib-init\n"); -if (err_lib_dane < 0) - init_once(&err_lib_dane, ERR_get_next_error_library, dane_init); +(void) CRYPTO_THREAD_run_once(&once, dane_init); #if defined(LN_sha256) /* No DANE without SHA256 support */ @@ -1680,6 +1715,5 @@ return 0; } -#endif /* OPENSSL_VERSION_NUMBER */ /* vi: aw ai sw=2 */