*) 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/trunk@1925979 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stefan Eissing
2025-05-30 12:45:59 +00:00
parent b84e2e2068
commit 2de0d11e9b
5 changed files with 92 additions and 36 deletions

View File

@ -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]

View File

@ -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;
}

View File

@ -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"

View File

@ -1292,17 +1292,59 @@ static int md_add_fallback_cert_files(server_rec *s, apr_pool_t *p,
return DECLINED;
}
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)
{
apr_status_t rv = APR_ENOENT;
int i;
char *cert_name, *pkey_name;
const char *cert_pem, *key_pem;
md_store_t *store = md_reg_store_get(sc->mc->reg);
md_pkey_spec_t *key_spec;
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;
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",
cert_name, pkey_name, servername);
*pcert_pem = cert_pem;
*pkey_pem = key_pem;
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;
apr_status_t rv = APR_ENOENT;
md_srv_conf_t *sc;
md_store_t *store;
char *cert_name, *pkey_name;
const char *cert_pem, *key_pem;
int i;
*pcert_pem = *pkey_pem = NULL;
if (!servername
|| !(protocol = md_protocol_get(c))
@ -1314,33 +1356,31 @@ static int md_answer_challenge(conn_rec *c, const char *servername,
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++) {
tls_alpn01_fnames(c->pool, md_pkeys_spec_get(sc->pks,i),
&pkey_name, &cert_name);
rv = md_store_load(store, MD_SG_CHALLENGES, servername, cert_name, MD_SV_TEXT,
(void**)&cert_pem, c->pool);
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);
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",
cert_name, pkey_name, servername);
*pcert_pem = cert_pem;
*pkey_pem = key_pem;
hook_rv = OK;
break;
}
/* 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);
}

View File

@ -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)) {