Skip to content

Commit 798881a

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 a887a9f commit 798881a

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ Add the moduel to the nginx configuration and configure as described below.
4949

5050
## Example Configuration
5151

52-
5352
```nginx
5453
resolver 127.0.0.1;
5554
@@ -64,7 +63,7 @@ acme_shared_zone 1M;
6463
server {
6564
server_name .example.test;
6665
67-
acme_certificate example .example.test;
66+
acme_certificate example;
6867
6968
ssl_certificate $acme_certificate;
7069
ssl_certificate_key $acme_certificate_key;
@@ -208,14 +207,22 @@ challenge data for all the configured certificate issuers.
208207

209208
### acme_certificate
210209

211-
**Syntax:** acme_certificate `issuer` `identifier` ... [ `key` = `alg[:size]` | `file` ]
210+
**Syntax:** acme_certificate `issuer` [`identifier` ...] [ `key` = `alg[:size]` | `file` ]
212211

213212
**Default:** -
214213

215214
**Context:** server
216215

217216
Defines a certificate with the list of `identifier`s requested from
218217
issuer `issuer`.
218+
219+
The explicit list of identifiers can be omitted. In this case the identifiers
220+
will be taken from the [server_name] directive in the same `server` block.
221+
Not all the values accepted by [server_name] are valid certificate identifiers:
222+
regular expressions and wildcards are not supported.
223+
224+
[server_name]: https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
225+
219226
The `key` parameter sets the type of generated private key or a
220227
path to an existing file. Supported key algorithms and sizes:
221228
`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,
@@ -278,9 +278,8 @@ extern "C" fn cmd_add_certificate(
278278
}
279279
}
280280

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

285284
ascf.order = Some(order);
286285

@@ -435,6 +434,26 @@ impl AcmeMainConfig {
435434
continue;
436435
};
437436

437+
// An empty list of identifers should be filled from the `server_name` directive values.
438+
// At this point, the server names list should be fully initialized.
439+
if order.identifiers.is_empty() {
440+
let server_names = unsafe { cscfp.server_names.as_slice() };
441+
442+
if let Err(err) = order.add_server_names(cf, server_names) {
443+
ngx_log_error!(NGX_LOG_EMERG, cf.log, "\"acme_certificate\": {err}");
444+
return Err(Status::NGX_ERROR);
445+
}
446+
447+
if order.identifiers.is_empty() {
448+
ngx_log_error!(
449+
NGX_LOG_EMERG,
450+
cf.log,
451+
"\"acme_certificate\": no identifiers found in \"server_name\""
452+
);
453+
return Err(Status::NGX_ERROR);
454+
}
455+
}
456+
438457
if let Some(issuer) = self.issuer_mut(&ascf.issuer) {
439458
issuer.add_certificate_order(cf, order)?;
440459
} 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

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

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

0 commit comments

Comments
 (0)