From: Stefan Eissing Date: Wed, 1 Sep 2021 13:22:19 +0000 (+0000) Subject: Merge r1892782 from trunk: X-Git-Tag: candidate-2.4.49~3^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=569bf29a287b60b978ff27702e1376d23fcaf1fc;p=thirdparty%2Fapache%2Fhttpd.git Merge r1892782 from trunk: * mod_md: Certificate/keys pairs are verified as matching before a renewal is accepted as successful or a staged renewal is replacing the existing certificates. This avoid potential mess ups in the md store file system to render the active certificates non-working. [@mkauf] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1892783 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/changes-entries/md_check_keys.txt b/changes-entries/md_check_keys.txt new file mode 100644 index 00000000000..259c96c8559 --- /dev/null +++ b/changes-entries/md_check_keys.txt @@ -0,0 +1,4 @@ + * mod_md: Certificate/keys pairs are verified as matching before a renewal is accepted + as successful or a staged renewal is replacing the existing certificates. + This avoid potential mess ups in the md store file system to render the active + certificates non-working. [@mkauf] diff --git a/modules/md/md_acme_drive.c b/modules/md/md_acme_drive.c index 4956a06aab8..5e3b48cf91e 100644 --- a/modules/md/md_acme_drive.c +++ b/modules/md/md_acme_drive.c @@ -767,6 +767,27 @@ static apr_status_t acme_renew(md_proto_driver_t *d, md_result_t *result) } if (!md_array_is_empty(ad->cred->chain)) { + + if (!ad->cred->pkey) { + rv = md_pkey_load(d->store, MD_SG_STAGING, d->md->name, ad->cred->spec, &ad->cred->pkey, d->p); + if (APR_SUCCESS != rv) { + md_result_printf(result, rv, "Loading the private key."); + goto out; + } + } + + if (ad->cred->pkey) { + rv = md_check_cert_and_pkey(ad->cred->chain, ad->cred->pkey); + if (APR_SUCCESS != rv) { + md_result_printf(result, rv, "Certificate and private key do not match."); + + /* Delete the order */ + md_acme_order_purge(d->store, d->p, MD_SG_STAGING, d->md->name, d->env); + + goto out; + } + } + rv = md_pubcert_save(d->store, d->p, MD_SG_STAGING, d->md->name, ad->cred->spec, ad->cred->chain, 0); if (APR_SUCCESS != rv) { @@ -901,6 +922,10 @@ static apr_status_t acme_preload(md_proto_driver_t *d, md_store_group_t load_gro md_result_printf(result, rv, "no certificate in staged credentials #%d", i); goto leave; } + if (APR_SUCCESS != (rv = md_check_cert_and_pkey(creds->chain, creds->pkey))) { + md_result_printf(result, rv, "certificate and private key do not match in staged credentials #%d", i); + goto leave; + } APR_ARRAY_PUSH(all_creds, md_credentials_t*) = creds; } diff --git a/modules/md/md_crypt.c b/modules/md/md_crypt.c index 13c7edde5b9..55826be8601 100644 --- a/modules/md/md_crypt.c +++ b/modules/md/md_crypt.c @@ -2014,3 +2014,19 @@ cleanup: return rv; } +apr_status_t md_check_cert_and_pkey(struct apr_array_header_t *certs, md_pkey_t *pkey) +{ + const md_cert_t *cert; + + if (certs->nelts == 0) { + return APR_ENOENT; + } + + cert = APR_ARRAY_IDX(certs, 0, const md_cert_t*); + + if (1 != X509_check_private_key(cert->x509, pkey->pkey)) { + return APR_EGENERAL; + } + + return APR_SUCCESS; +} diff --git a/modules/md/md_crypt.h b/modules/md/md_crypt.h index 3aa03fc5a8b..85e45e4e449 100644 --- a/modules/md/md_crypt.h +++ b/modules/md/md_crypt.h @@ -218,6 +218,9 @@ apr_status_t md_cert_get_ct_scts(apr_array_header_t *scts, apr_pool_t *p, const apr_status_t md_cert_get_ocsp_responder_url(const char **purl, apr_pool_t *p, const md_cert_t *cert); +apr_status_t md_check_cert_and_pkey(struct apr_array_header_t *certs, md_pkey_t *pkey); + + /**************************************************************************************************/ /* X509 certificate transparency */ diff --git a/modules/md/md_version.h b/modules/md/md_version.h index 53377b840d0..f76ed708c24 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.4.4" +#define MOD_MD_VERSION "2.4.5" /** * @macro