Skip to content

Commit 52151fc

Browse files
committed
ACME: allow empty list of identifiers in "acme_certificate".
The empty list is interpreted as an instruction to fetch the identifiers from the server_name directive in the same server block.
1 parent 2fe9e86 commit 52151fc

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ server {
6464
listen 443 ssl;
6565
server_name .example.test;
6666
67-
acme_certificate example .example.test;
67+
acme_certificate example;
6868
6969
ssl_certificate $acme_certificate;
7070
ssl_certificate_key $acme_certificate_key;
@@ -218,14 +218,22 @@ challenge data for all the configured certificate issuers.
218218

219219
### acme_certificate
220220

221-
**Syntax:** acme_certificate `issuer` `identifier` ... [ `key` = `alg[:size]` | `file` ]
221+
**Syntax:** acme_certificate `issuer` [`identifier` ...] [ `key` = `alg[:size]` | `file` ]
222222

223223
**Default:** -
224224

225225
**Context:** server
226226

227227
Defines a certificate with the list of `identifier`s requested from
228228
issuer `issuer`.
229+
230+
The explicit list of identifiers can be omitted. In this case the identifiers
231+
will be taken from the [server_name] directive in the same `server` block.
232+
Not all the values accepted by [server_name] are valid certificate identifiers:
233+
regular expressions and wildcards are not supported.
234+
235+
[server_name]: https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
236+
229237
The `key` parameter sets the type of generated private key or a
230238
path to an existing file. Supported key algorithms and sizes:
231239
`ecdsa:256` (default), `ecdsa:384`,

src/conf.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::{mem, ptr};
33

44
use nginx_sys::{
55
ngx_command_t, ngx_conf_parse, ngx_conf_t, ngx_http_core_srv_conf_t, ngx_str_t, ngx_uint_t,
6-
NGX_CONF_2MORE, NGX_CONF_BLOCK, NGX_CONF_FLAG, NGX_CONF_TAKE1, NGX_HTTP_MAIN_CONF,
6+
NGX_CONF_1MORE, NGX_CONF_BLOCK, NGX_CONF_FLAG, NGX_CONF_TAKE1, NGX_HTTP_MAIN_CONF,
77
NGX_HTTP_MAIN_CONF_OFFSET, NGX_HTTP_SRV_CONF, NGX_HTTP_SRV_CONF_OFFSET, NGX_LOG_EMERG,
88
};
99
use ngx::collections::Vec;
@@ -60,7 +60,7 @@ pub static mut NGX_HTTP_ACME_COMMANDS: [ngx_command_t; 4] = [
6060
},
6161
ngx_command_t {
6262
name: ngx_string!("acme_certificate"),
63-
type_: (NGX_HTTP_SRV_CONF | NGX_CONF_2MORE) as ngx_uint_t,
63+
type_: (NGX_HTTP_SRV_CONF | NGX_CONF_1MORE) as ngx_uint_t,
6464
set: Some(cmd_add_certificate),
6565
conf: NGX_HTTP_SRV_CONF_OFFSET,
6666
offset: 0,
@@ -293,9 +293,8 @@ extern "C" fn cmd_add_certificate(
293293
}
294294
}
295295

296-
if order.identifiers.is_empty() {
297-
return c"no identifiers".as_ptr().cast_mut();
298-
}
296+
// If we haven't found any identifiers in the arguments, we will populate the list from the
297+
// `server_name` values later, when the server names list is fully initialized.
299298

300299
ascf.order = Some(order);
301300

@@ -446,6 +445,26 @@ impl AcmeMainConfig {
446445
continue;
447446
};
448447

448+
// An empty list of identifers should be filled from the `server_name` directive values.
449+
// At this point, the server names list should be fully initialized.
450+
if order.identifiers.is_empty() {
451+
let server_names = unsafe { cscfp.server_names.as_slice() };
452+
453+
if let Err(err) = order.add_server_names(cf, server_names) {
454+
ngx_log_error!(NGX_LOG_EMERG, cf.log, "\"acme_certificate\": {err}");
455+
return Err(Status::NGX_ERROR);
456+
}
457+
458+
if order.identifiers.is_empty() {
459+
ngx_log_error!(
460+
NGX_LOG_EMERG,
461+
cf.log,
462+
"\"acme_certificate\": no identifiers found in \"server_name\""
463+
);
464+
return Err(Status::NGX_ERROR);
465+
}
466+
}
467+
449468
if let Some(issuer) = self.issuer_mut(&ascf.issuer) {
450469
issuer.add_certificate_order(cf, order)?;
451470
} else {

src/conf/order.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ use core::hash::{self, Hash, Hasher};
33
use core::net::IpAddr;
44
use core::str::Utf8Error;
55

6-
use nginx_sys::ngx_str_t;
6+
use nginx_sys::{ngx_conf_t, ngx_http_server_name_t, ngx_str_t};
77
use ngx::allocator::{AllocError, Allocator, TryCloneIn};
88
use ngx::collections::Vec;
99
use ngx::core::{NgxString, Pool, Status};
10+
use ngx::ngx_log_error;
1011
use siphasher::sip::SipHasher;
1112
use thiserror::Error;
1213

@@ -146,6 +147,34 @@ impl CertificateOrder<ngx_str_t, Pool> {
146147
Ok(())
147148
}
148149

150+
pub fn add_server_names(
151+
&mut self,
152+
cf: &mut ngx_conf_t,
153+
server_names: &[ngx_http_server_name_t],
154+
) -> Result<(), IdentifierError> {
155+
for server_name in server_names {
156+
if !server_name.regex.is_null() {
157+
ngx_log_error!(
158+
nginx_sys::NGX_LOG_WARN,
159+
cf.log,
160+
"\"acme_certificate\": unsupported regular expression in server_name: {}",
161+
server_name.name
162+
);
163+
continue;
164+
}
165+
166+
// A valid server_name entry that we want to ignore.
167+
// We'll fail properly later if that's the only entry.
168+
if server_name.name.is_empty() {
169+
continue;
170+
}
171+
172+
self.try_add_identifier(&server_name.name)?;
173+
}
174+
175+
Ok(())
176+
}
177+
149178
pub fn try_add_identifier(&mut self, value: &ngx_str_t) -> Result<(), IdentifierError> {
150179
if value.is_empty() {
151180
return Err(IdentifierError::Empty);

0 commit comments

Comments
 (0)