Skip to content

Commit e07b7a2

Browse files
committed
*) mod_md: update to v2.5.1
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1923592 13f79535-47bb-0310-9956-ffa450edef68
1 parent 0ba38c2 commit e07b7a2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+863
-383
lines changed

changes-entries/md_v2.5.1.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
*) mod_md: update to version 2.5.1
2+
- Added support for ACME profiles with new directives MDProfile and
3+
MDProfileMandatory.
4+
- When installing a custom CA file via `MDCACertificateFile`, also set the
5+
libcurl option CURLSSLOPT_NO_REVOKE that suppresses complains by Schannel
6+
(when curl is linked with it) about missing CRL/OCSP in certificates.
7+
- Fixed handling of corrupted httpd.json and added test 300_30 for it.
8+
File is removed on error and written again. Fixes #369.
9+
- Added explanation in log for how to proceed when md_store.json could not be
10+
parsed and prevented the server start.
11+
- restored fixed to #336 and #337 which got lost in a sync with Apache svn
12+
- Add Issue Name/Uris to certificate information in md-status handler
13+
- MDomains with static certificate files have MDRenewMode "manual", unless
14+
"always" is configured.

docs/manual/mod/mod_md.xml

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
ACME protocol (<a href="https://tools.ietf.org/html/rfc8555">RFC 8555</a>).
3838
Certificates will be renewed by the module ahead of their expiration to account
3939
for disruption in internet services. There are ways to monitor the status of all
40-
certififcates managed this way and configurations that will run your own
40+
certificates managed this way and configurations that will run your own
4141
notification commands on renewal, expiration and errors.
4242
</p><p>
4343
Second, mod_md offers an alternate OCSP Stapling implementation. This works with
@@ -495,7 +495,7 @@ MDomain example2.org auto
495495
For testing, CAs commonly offer a second service URL.
496496
The 'test' service does not give certificates valid in a browser,
497497
but are more relaxed in regard to rate limits.
498-
This allows for verfication of your own setup before switching
498+
This allows for verification of your own setup before switching
499499
to the production service URL.
500500
</p>
501501
<example><title>LE Test Setup</title>
@@ -1299,7 +1299,7 @@ MDMessageCmd /etc/apache/md-message
12991299

13001300
<directivesynopsis>
13011301
<name>MDCertificateCheck</name>
1302-
<description>Set name and URL pattern for a certificate monitoring sitSet name and URL pattern for a certificate monitoring sitee</description>
1302+
<description>Set name and URL pattern for a certificate monitoring site.</description>
13031303
<syntax>MDCertificateCheck <var>name</var> <var>url</var></syntax>
13041304
<contextlist>
13051305
<context>server config</context>
@@ -1311,20 +1311,6 @@ MDMessageCmd /etc/apache/md-message
13111311
</usage>
13121312
</directivesynopsis>
13131313

1314-
<directivesynopsis>
1315-
<name>MDActivationDelay</name>
1316-
<description>How long to delay activation of new certificates</description>
1317-
<syntax>MDActivationDelay <var>duration</var></syntax>
1318-
<contextlist>
1319-
<context>server config</context>
1320-
</contextlist>
1321-
<compatibility>Available in version 2.4.42 and later</compatibility>
1322-
<usage>
1323-
<p>
1324-
</p>
1325-
</usage>
1326-
</directivesynopsis>
1327-
13281314
<directivesynopsis>
13291315
<name>MDContactEmail</name>
13301316
<description>Email address used for account registration</description>
@@ -1369,7 +1355,7 @@ MDMessageCmd /etc/apache/md-message
13691355
<p>
13701356
You can configure those globally or for a specific MDomain. Since
13711357
these values allow anyone to register under the same account, it is
1372-
adivsable to give the configuration file restricted permissions,
1358+
advisable to give the configuration file restricted permissions,
13731359
e.g. root only.
13741360
</p>
13751361
<p>
@@ -1537,4 +1523,61 @@ MDMessageCmd /etc/apache/md-message
15371523
</usage>
15381524
</directivesynopsis>
15391525

1526+
<directivesynopsis>
1527+
<name>MDProfile</name>
1528+
<description>Use a specific ACME profile from the CA</description>
1529+
<syntax>MDProfile name</syntax>
1530+
<contextlist>
1531+
<context>server config</context>
1532+
</contextlist>
1533+
<compatibility>Available in version 2.4.64 and later</compatibility>
1534+
<usage>
1535+
<p>
1536+
This about a non-standard ACME extension by Let's Encrypt.
1537+
</p><p>
1538+
Lets Encrypt announced they will add Certificate Profiles
1539+
support in their CA during 2025, beginning with their staging
1540+
servers. This, among some other details, let's you select the
1541+
lifetime of the certificates you get. The "default" profile
1542+
will keep the 90 days and a "tlsserver" profile will issue
1543+
certificates with only 6 days of validity.
1544+
</p><p>
1545+
If you do not change your mod_md configuration, you will
1546+
continue to get the 90 days certificates. Should you believe
1547+
that a shorter lifetime is beneficial for you (and take the
1548+
risk that the renewal time is way shorter),
1549+
you can configure the profile to use via 'MDProfile tlsserver'.
1550+
</p><p>
1551+
The profile names are defined by the CA. If a profile you
1552+
configure is not available, no profile will be used and
1553+
the certificate will be issue according to what the CA
1554+
considers default.
1555+
</p><p>
1556+
See <directive module="mod_md">MDProfileMandatory</directive>
1557+
on how to disable defaults for profiles.
1558+
</p>
1559+
</usage>
1560+
</directivesynopsis>
1561+
1562+
<directivesynopsis>
1563+
<name>MDProfileMandatory</name>
1564+
<description>Control if an MDProfile is mandatory.</description>
1565+
<syntax>MDProfileMandatory on|off</syntax>
1566+
<default>MDProfileMandatory off</default>
1567+
<contextlist>
1568+
<context>server config</context>
1569+
</contextlist>
1570+
<usage>
1571+
<p>
1572+
Controls if a <directive module="mod_md">MDProfile</directive>
1573+
you configure is mandatory or not. When mandatory and the CA
1574+
does not offer a configured profile, the certificate
1575+
renewal will fail.
1576+
</p><p>
1577+
When not mandatory and a profile is not offered by the CA,
1578+
renewals will be performed without specifying a profile and
1579+
the CA will issue a certificates according to its defaults.
1580+
</p>
1581+
</usage>
1582+
</directivesynopsis>
15401583
</modulesynopsis>

modules/md/md.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ struct md_t {
9292
struct apr_array_header_t *pkey_files; /* != NULL iff privkeys explicitly configured */
9393
const char *ca_eab_kid; /* optional KEYID for external account binding */
9494
const char *ca_eab_hmac; /* optional HMAC for external account binding */
95+
const char *profile; /* optional cert profile to order */
96+
int profile_mandatory; /* if profile, when given, is mandatory */
9597

9698
const char *state_descr; /* description of state of NULL */
9799

@@ -154,6 +156,8 @@ struct md_t {
154156
#define MD_KEY_HTTPS "https"
155157
#define MD_KEY_ID "id"
156158
#define MD_KEY_IDENTIFIER "identifier"
159+
#define MD_KEY_ISSUER_NAME "issuer-name"
160+
#define MD_KEY_ISSUER_URI "issuer-uri"
157161
#define MD_KEY_KEY "key"
158162
#define MD_KEY_KID "kid"
159163
#define MD_KEY_KEYAUTHZ "keyAuthorization"
@@ -175,6 +179,8 @@ struct md_t {
175179
#define MD_KEY_PKEY "privkey"
176180
#define MD_KEY_PKEY_FILES "pkey-files"
177181
#define MD_KEY_PROBLEM "problem"
182+
#define MD_KEY_PROFILE "profile"
183+
#define MD_KEY_PROFILE_MANDATORY "profile-mandatory"
178184
#define MD_KEY_PROTO "proto"
179185
#define MD_KEY_READY "ready"
180186
#define MD_KEY_REGISTRATION "registration"

modules/md/md_acme.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,15 @@ typedef struct {
664664
md_result_t *result;
665665
} update_dir_ctx;
666666

667+
static int collect_profiles(void *baton, const char* key, md_json_t *json)
668+
{
669+
update_dir_ctx *ctx = baton;
670+
(void)json;
671+
APR_ARRAY_PUSH(ctx->acme->api.v2.profiles, const char *) =
672+
apr_pstrdup(ctx->acme->p, key);
673+
return 1;
674+
}
675+
667676
static apr_status_t update_directory(const md_http_response_t *res, void *data)
668677
{
669678
md_http_request_t *req = res->req;
@@ -728,6 +737,20 @@ static apr_status_t update_directory(const md_http_response_t *res, void *data)
728737
acme->new_nonce_fn = acmev2_new_nonce;
729738
acme->req_init_fn = acmev2_req_init;
730739
acme->post_new_account_fn = acmev2_POST_new_account;
740+
741+
if (md_json_has_key(json, "meta", "profiles", NULL)) {
742+
acme->api.v2.profiles = apr_array_make(acme->p, 5, sizeof(const char*));
743+
md_json_iterkey(collect_profiles, data, json, "meta", "profiles", NULL);
744+
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, rv, req->pool,
745+
"found %d profiles in ACME directory meta",
746+
acme->api.v2.profiles->nelts);
747+
}
748+
else {
749+
acme->api.v2.profiles = NULL;
750+
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, rv, req->pool,
751+
"no profiles in ACME directory meta");
752+
753+
}
731754
}
732755
else if ((s = md_json_dups(acme->p, json, "new-authz", NULL))) {
733756
acme->api.v1.new_authz = s;

modules/md/md_acme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ struct md_acme_t {
118118
const char *key_change;
119119
const char *revoke_cert;
120120
const char *new_nonce;
121+
struct apr_array_header_t *profiles;
121122
} v2;
122123
} api;
123124
const char *ca_agreement;

modules/md/md_acme_drive.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,9 @@ static apr_status_t acme_renew(md_proto_driver_t *d, md_result_t *result)
765765
if (!ad->domains) {
766766
ad->domains = md_dns_make_minimal(d->p, ad->md->domains);
767767
}
768-
768+
ad->profile = ad->md->profile;
769+
ad->profile_mandatory = ad->md->profile_mandatory;
770+
769771
md_result_activity_printf(result, "Contacting ACME server for %s at %s",
770772
d->md->name, ca_effective);
771773
if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, ca_effective,

modules/md/md_acme_drive.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ typedef struct md_acme_driver_t {
2929
md_t *md;
3030
struct apr_array_header_t *domains;
3131
apr_array_header_t *ca_challenges;
32+
const char *profile;
33+
int profile_mandatory;
3234

3335
int complete;
3436
apr_array_header_t *creds; /* the new md_credentials_t */

modules/md/md_acme_order.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,14 @@ typedef struct {
263263
md_acme_order_t *order;
264264
md_acme_t *acme;
265265
const char *name;
266+
const char *profile;
266267
apr_array_header_t *domains;
267268
md_result_t *result;
268269
} order_ctx_t;
269270

270-
#define ORDER_CTX_INIT(ctx, p, o, a, n, d, r) \
271+
#define ORDER_CTX_INIT(ctx, p, o, a, n, d, pf, r) \
271272
(ctx)->p = (p); (ctx)->order = (o); (ctx)->acme = (a); \
272-
(ctx)->name = (n); (ctx)->domains = d; (ctx)->result = r
273+
(ctx)->name = (n); (ctx)->domains = d; (ctx)->profile = pf; (ctx)->result = r
273274

274275
static apr_status_t identifier_to_json(void *value, md_json_t *json, apr_pool_t *p, void *baton)
275276
{
@@ -289,6 +290,8 @@ static apr_status_t on_init_order_register(md_acme_req_t *req, void *baton)
289290

290291
jpayload = md_json_create(req->p);
291292
md_json_seta(ctx->domains, identifier_to_json, NULL, jpayload, "identifiers", NULL);
293+
if (ctx->profile)
294+
md_json_sets(ctx->profile, jpayload, "profile", NULL);
292295

293296
return md_acme_req_body_init(req, jpayload);
294297
}
@@ -321,13 +324,14 @@ static apr_status_t on_order_upd(md_acme_t *acme, apr_pool_t *p, const apr_table
321324
}
322325

323326
apr_status_t md_acme_order_register(md_acme_order_t **porder, md_acme_t *acme, apr_pool_t *p,
324-
const char *name, apr_array_header_t *domains)
327+
const char *name, apr_array_header_t *domains,
328+
const char *profile)
325329
{
326330
order_ctx_t ctx;
327331
apr_status_t rv;
328332

329333
assert(MD_ACME_VERSION_MAJOR(acme->version) > 1);
330-
ORDER_CTX_INIT(&ctx, p, NULL, acme, name, domains, NULL);
334+
ORDER_CTX_INIT(&ctx, p, NULL, acme, name, domains, profile, NULL);
331335
rv = md_acme_POST(acme, acme->api.v2.new_order, on_init_order_register, on_order_upd, NULL, NULL, &ctx);
332336
*porder = (APR_SUCCESS == rv)? ctx.order : NULL;
333337
return rv;
@@ -340,7 +344,7 @@ apr_status_t md_acme_order_update(md_acme_order_t *order, md_acme_t *acme,
340344
apr_status_t rv;
341345

342346
assert(MD_ACME_VERSION_MAJOR(acme->version) > 1);
343-
ORDER_CTX_INIT(&ctx, p, order, acme, NULL, NULL, result);
347+
ORDER_CTX_INIT(&ctx, p, order, acme, NULL, NULL, NULL, result);
344348
rv = md_acme_GET(acme, order->url, NULL, on_order_upd, NULL, NULL, &ctx);
345349
if (APR_SUCCESS != rv && APR_SUCCESS != acme->last->status) {
346350
md_result_dup(result, acme->last);
@@ -380,7 +384,7 @@ apr_status_t md_acme_order_await_ready(md_acme_order_t *order, md_acme_t *acme,
380384
apr_status_t rv;
381385

382386
assert(MD_ACME_VERSION_MAJOR(acme->version) > 1);
383-
ORDER_CTX_INIT(&ctx, p, order, acme, md->name, NULL, result);
387+
ORDER_CTX_INIT(&ctx, p, order, acme, md->name, NULL, NULL, result);
384388

385389
md_result_activity_setn(result, "Waiting for order to become ready");
386390
rv = md_util_try(await_ready, &ctx, 0, timeout, 0, 0, 1);
@@ -423,7 +427,7 @@ apr_status_t md_acme_order_await_valid(md_acme_order_t *order, md_acme_t *acme,
423427
apr_status_t rv;
424428

425429
assert(MD_ACME_VERSION_MAJOR(acme->version) > 1);
426-
ORDER_CTX_INIT(&ctx, p, order, acme, md->name, NULL, result);
430+
ORDER_CTX_INIT(&ctx, p, order, acme, md->name, NULL, NULL, result);
427431

428432
md_result_activity_setn(result, "Waiting for finalized order to become valid");
429433
rv = md_util_try(await_valid, &ctx, 0, timeout, 0, 0, 1);
@@ -552,7 +556,7 @@ apr_status_t md_acme_order_monitor_authzs(md_acme_order_t *order, md_acme_t *acm
552556
order_ctx_t ctx;
553557
apr_status_t rv;
554558

555-
ORDER_CTX_INIT(&ctx, p, order, acme, md->name, NULL, result);
559+
ORDER_CTX_INIT(&ctx, p, order, acme, md->name, NULL, NULL, result);
556560

557561
md_result_activity_printf(result, "Monitoring challenge status for %s", md->name);
558562
rv = md_util_try(check_challenges, &ctx, 0, timeout, 0, 0, 1);

modules/md/md_acme_order.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ apr_status_t md_acme_order_monitor_authzs(md_acme_order_t *order, md_acme_t *acm
7676
/* ACMEv2 only ************************************************************************************/
7777

7878
apr_status_t md_acme_order_register(md_acme_order_t **porder, md_acme_t *acme, apr_pool_t *p,
79-
const char *name, struct apr_array_header_t *domains);
79+
const char *name, struct apr_array_header_t *domains,
80+
const char *profile);
8081

8182
apr_status_t md_acme_order_update(md_acme_order_t *order, md_acme_t *acme,
8283
struct md_result_t *result, apr_pool_t *p);

modules/md/md_acmev2_drive.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static apr_status_t ad_setup_order(md_proto_driver_t *d, md_result_t *result, in
5656
md_acme_driver_t *ad = d->baton;
5757
apr_status_t rv;
5858
md_t *md = ad->md;
59+
const char *profile = NULL;
5960

6061
assert(ad->md);
6162
assert(ad->acme);
@@ -77,7 +78,33 @@ static apr_status_t ad_setup_order(md_proto_driver_t *d, md_result_t *result, in
7778
}
7879

7980
md_result_activity_setn(result, "Creating new order");
80-
rv = md_acme_order_register(&ad->order, ad->acme, d->p, d->md->name, ad->domains);
81+
if (ad->profile) {
82+
if(ad->acme->api.v2.profiles) {
83+
int i;
84+
for (i = 0; !profile && i < ad->acme->api.v2.profiles->nelts; ++i) {
85+
const char *s = APR_ARRAY_IDX(ad->acme->api.v2.profiles, i, const char*);
86+
if (!apr_strnatcasecmp(s, ad->profile))
87+
profile = s;
88+
}
89+
}
90+
if (profile)
91+
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p,
92+
"%s: ordering ACME profile '%s'", md->name, profile);
93+
else if (ad->profile_mandatory) {
94+
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p,
95+
"%s: mandatory ACME profile '%s' is not offered by CA",
96+
md->name, ad->profile);
97+
rv = APR_EINVAL;
98+
goto leave;
99+
}
100+
else {
101+
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p,
102+
"%s: ACME profile '%s' is not offered by CA, continuing without",
103+
md->name, ad->profile);
104+
}
105+
}
106+
107+
rv = md_acme_order_register(&ad->order, ad->acme, d->p, d->md->name, ad->domains, profile);
81108
if (APR_SUCCESS !=rv) goto leave;
82109
rv = md_acme_order_save(d->store, d->p, MD_SG_STAGING, d->md->name, ad->order, 0);
83110
if (APR_SUCCESS != rv) {

0 commit comments

Comments
 (0)