Skip to content

Commit 1f9da84

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 40d8919 commit 1f9da84

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;
@@ -62,7 +62,7 @@ pub static mut NGX_HTTP_ACME_COMMANDS: [ngx_command_t; 4] = [
6262
},
6363
ngx_command_t {
6464
name: ngx_string!("acme_certificate"),
65-
type_: (NGX_HTTP_SRV_CONF | NGX_CONF_2MORE) as ngx_uint_t,
65+
type_: (NGX_HTTP_SRV_CONF | NGX_CONF_1MORE) as ngx_uint_t,
6666
set: Some(cmd_add_certificate),
6767
conf: NGX_HTTP_SRV_CONF_OFFSET,
6868
offset: 0,
@@ -295,9 +295,8 @@ extern "C" fn cmd_add_certificate(
295295
}
296296
}
297297

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

302301
ascf.order = Some(order);
303302

@@ -448,6 +447,26 @@ impl AcmeMainConfig {
448447
continue;
449448
};
450449

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