]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge modules/md/md_version.h
authorStefan Eissing <icing@apache.org>
Tue, 3 Jun 2025 08:20:55 +0000 (08:20 +0000)
committerStefan Eissing <icing@apache.org>
Tue, 3 Jun 2025 08:20:55 +0000 (08:20 +0000)
  *) 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

changes-entries/md_v2.5.2.txt [new file with mode: 0644]
modules/md/md_crypt.c
modules/md/md_version.h
modules/md/mod_md.c
modules/md/mod_md_status.c

diff --git a/changes-entries/md_v2.5.2.txt b/changes-entries/md_v2.5.2.txt
new file mode 100644 (file)
index 0000000..1b4922b
--- /dev/null
@@ -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]
index 77feb55a850209675b61bde3764e1b7b974d174e..e56a2c0c9b73b2b68567d2e03d51e6a1a3adc518 100644 (file)
 #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;
     }
index 609cc93ec3d1343669672a366d2eb2e4b0a0a622..5b02ed369a8dd9c4f142bba7f794c3338a03bf98 100644 (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"
index c34aeb2909a162a1f7166297ba913935147013ab..8b83b4e67869096043a3113a7d446019be3af5e3 100644 (file)
@@ -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);
     }
 
index 033628f267f1f37560e6aa5ca3fa8c05c8b4f730..72cff4180fce48abfefab36bed691bb50858698b 100644 (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)) {