From: Stefan Eissing Date: Tue, 3 Jun 2025 08:20:55 +0000 (+0000) Subject: Merge modules/md/md_version.h X-Git-Tag: 2.4.64-rc1-candidate~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7d4342f93ec03d47b18ef441187003cf5b28fae;p=thirdparty%2Fapache%2Fhttpd.git Merge modules/md/md_version.h *) mod_md: update to version 2.5.2 - Fixed TLS-ALPN-01 challenges when multiple `MDPrivateKeys` are specified with EC keys before RSA ones. Fixes #377. [Stefan Eissing] - Fixed missing newlines in the status page output. [Andreas Groth] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1926084 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/changes-entries/md_v2.5.2.txt b/changes-entries/md_v2.5.2.txt new file mode 100644 index 0000000000..1b4922b8be --- /dev/null +++ b/changes-entries/md_v2.5.2.txt @@ -0,0 +1,4 @@ + *) mod_md: update to version 2.5.2 + - Fixed TLS-ALPN-01 challenges when multiple `MDPrivateKeys` are specified + with EC keys before RSA ones. Fixes #377. [Stefan Eissing] + - Fixed missing newlines in the status page output. [Andreas Groth] diff --git a/modules/md/md_crypt.c b/modules/md/md_crypt.c index 77feb55a85..e56a2c0c9b 100644 --- a/modules/md/md_crypt.c +++ b/modules/md/md_crypt.c @@ -69,6 +69,10 @@ #define MD_HAVE_CT 0 #endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define MD_OPENSSL_10x +#endif + static int initialized; struct md_pkey_t { @@ -257,9 +261,9 @@ static apr_time_t md_asn1_time_get(const ASN1_TIME* time) #endif } -apr_time_t md_asn1_generalized_time_get(void *ASN1_GENERALIZEDTIME) +apr_time_t md_asn1_generalized_time_get(void *asn1_gtime) { - return md_asn1_time_get(ASN1_GENERALIZEDTIME); + return md_asn1_time_get(asn1_gtime); } /**************************************************************************************************/ @@ -566,7 +570,7 @@ static md_pkey_spec_t PkeySpecDef = { MD_PKEY_TYPE_DEFAULT, {{ 0 }} }; md_pkey_spec_t *md_pkeys_spec_get(const md_pkeys_spec_t *pks, int index) { if (md_pkeys_spec_is_empty(pks)) { - return index == 1? &PkeySpecDef : NULL; + return index == 0? &PkeySpecDef : NULL; } else if (pks && index >= 0 && index < pks->specs->nelts) { return APR_ARRAY_IDX(pks->specs, index, md_pkey_spec_t*); @@ -803,7 +807,11 @@ static apr_status_t check_EC_curve(int nid, apr_pool_t *p) { int rv = APR_ENOENT; nc = EC_get_builtin_curves(NULL, 0); +#ifdef MD_OPENSSL_10x + if (NULL == (curves = OPENSSL_malloc((int)(sizeof(*curves) * nc))) || +#else if (NULL == (curves = OPENSSL_malloc(sizeof(*curves) * nc)) || +#endif nc != EC_get_builtin_curves(curves, nc)) { rv = APR_EGENERAL; md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, @@ -1515,7 +1523,11 @@ apr_status_t md_cert_read_chain(apr_array_header_t *chain, apr_pool_t *p, md_cert_t *cert; int added = 0; +#ifdef MD_OPENSSL_10x + if (NULL == (bf = BIO_new_mem_buf((char *)pem, (int)pem_len))) { +#else if (NULL == (bf = BIO_new_mem_buf(pem, (int)pem_len))) { +#endif rv = APR_ENOMEM; goto cleanup; } diff --git a/modules/md/md_version.h b/modules/md/md_version.h index 609cc93ec3..5b02ed369a 100644 --- a/modules/md/md_version.h +++ b/modules/md/md_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the md module as c string */ -#define MOD_MD_VERSION "2.5.1" +#define MOD_MD_VERSION "2.5.2" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_MD_VERSION_NUM 0x020501 +#define MOD_MD_VERSION_NUM 0x020502 #define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory" #define MD_TAILSCALE_DEF_URL "file://localhost/var/run/tailscale/tailscaled.sock" diff --git a/modules/md/mod_md.c b/modules/md/mod_md.c index c34aeb2909..8b83b4e678 100644 --- a/modules/md/mod_md.c +++ b/modules/md/mod_md.c @@ -1292,55 +1292,95 @@ static int md_add_fallback_cert_files(server_rec *s, apr_pool_t *p, return DECLINED; } -static int md_answer_challenge(conn_rec *c, const char *servername, - const char **pcert_pem, const char **pkey_pem) +static int md_get_challenge_cert(conn_rec *c, const char *servername, + md_srv_conf_t *sc, + md_pkey_type_t key_type, + const char **pcert_pem, + const char **pkey_pem) { - const char *protocol; - int hook_rv = DECLINED; apr_status_t rv = APR_ENOENT; - md_srv_conf_t *sc; - md_store_t *store; + int i; char *cert_name, *pkey_name; const char *cert_pem, *key_pem; - int i; + md_store_t *store = md_reg_store_get(sc->mc->reg); + md_pkey_spec_t *key_spec; - if (!servername - || !(protocol = md_protocol_get(c)) - || strcmp(PROTO_ACME_TLS_1, protocol)) { - goto cleanup; - } - sc = md_config_get(c->base_server); - if (!sc || !sc->mc->reg) goto cleanup; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, - "Answer challenge[tls-alpn-01] for %s", servername); - store = md_reg_store_get(sc->mc->reg); + for (i = 0; i < md_pkeys_spec_count(sc->pks); i++) { + key_spec = md_pkeys_spec_get(sc->pks, i); + if (key_spec->type != key_type) + continue; - for (i = 0; i < md_pkeys_spec_count( sc->pks ); i++) { - tls_alpn01_fnames(c->pool, md_pkeys_spec_get(sc->pks,i), - &pkey_name, &cert_name); + tls_alpn01_fnames(c->pool, key_spec, &pkey_name, &cert_name); rv = md_store_load(store, MD_SG_CHALLENGES, servername, cert_name, MD_SV_TEXT, (void**)&cert_pem, c->pool); + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, + "Load challenge: cert %s", cert_name); if (APR_STATUS_IS_ENOENT(rv)) continue; if (APR_SUCCESS != rv) goto cleanup; rv = md_store_load(store, MD_SG_CHALLENGES, servername, pkey_name, MD_SV_TEXT, (void**)&key_pem, c->pool); + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, + "Load challenge: key %s", pkey_name); if (APR_STATUS_IS_ENOENT(rv)) continue; if (APR_SUCCESS != rv) goto cleanup; ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, - "Found challenge cert %s, key %s for %s", + "Found challenge: cert %s, key %s for %s", cert_name, pkey_name, servername); *pcert_pem = cert_pem; *pkey_pem = key_pem; - hook_rv = OK; - break; + return OK; + } +cleanup: + return DECLINED; +} + +static int md_answer_challenge(conn_rec *c, const char *servername, + const char **pcert_pem, const char **pkey_pem) +{ + const char *protocol; + int hook_rv = DECLINED; + md_srv_conf_t *sc; + + *pcert_pem = *pkey_pem = NULL; + + if (!servername + || !(protocol = md_protocol_get(c)) + || strcmp(PROTO_ACME_TLS_1, protocol)) { + goto cleanup; } + sc = md_config_get(c->base_server); + if (!sc || !sc->mc->reg) goto cleanup; + + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, + "Answer challenge[tls-alpn-01] for %s", servername); + + /* A challenge for TLS-ALPN-01 used to have a single certificate, + * overriding the single fallback certificate already installed in + * the connections SSL* instance. + * Since the addition of `MDPrivateKeys`, there can be more than one, + * but the server API for a challenge cert can return only one. This + * is a short coming of the API. + * This means we cannot override all fallback certificates present, just + * a single one. If there is an RSA cert in fallback, we need to override + * that, because the ACME server has a preference for that (at least LE + * has). So we look for an RSA challenge cert first. + * The fallback is an EC cert and that works since without RSA challenges, + * there should also be no RSA fallbacks. + * Bit of a mess. */ + hook_rv = md_get_challenge_cert(c, servername, sc, MD_PKEY_TYPE_DEFAULT, + pcert_pem, pkey_pem); + if (hook_rv == DECLINED) + hook_rv = md_get_challenge_cert(c, servername, sc, MD_PKEY_TYPE_RSA, + pcert_pem, pkey_pem); + if (hook_rv == DECLINED) + hook_rv = md_get_challenge_cert(c, servername, sc, MD_PKEY_TYPE_EC, + pcert_pem, pkey_pem); if (DECLINED == hook_rv) { - ap_log_cerror(APLOG_MARK, APLOG_INFO, rv, c, APLOGNO(10080) + ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, APLOGNO(10080) "%s: unknown tls-alpn-01 challenge host", servername); } diff --git a/modules/md/mod_md_status.c b/modules/md/mod_md_status.c index 033628f267..72cff4180f 100644 --- a/modules/md/mod_md_status.c +++ b/modules/md/mod_md_status.c @@ -543,7 +543,7 @@ static void si_val_activity(status_ctx *ctx, md_json_t *mdj, const status_info * apr_brigade_puts(ctx->bb, NULL, NULL, "Pending"); } else { - apr_brigade_printf(ctx->bb, NULL, NULL, "%s: %s", ctx->prefix, "Pending"); + apr_brigade_printf(ctx->bb, NULL, NULL, "%s: %s", ctx->prefix, "Pending\n"); } } else if (MD_RENEW_MANUAL == md_json_getl(mdj, MD_KEY_RENEW_MODE, NULL)) { @@ -551,7 +551,7 @@ static void si_val_activity(status_ctx *ctx, md_json_t *mdj, const status_info * apr_brigade_puts(ctx->bb, NULL, NULL, "Manual renew"); } else { - apr_brigade_printf(ctx->bb, NULL, NULL, "%s: %s", ctx->prefix, "Manual renew"); + apr_brigade_printf(ctx->bb, NULL, NULL, "%s: %s", ctx->prefix, "Manual renew\n"); } } if (!HTML_STATUS(ctx)) {