Skip to content

Commit ea6a17f

Browse files
committed
ACME: allow "acme_certificate server_name ...".
The parameter allows fetching the list of identifiers from the server_name directive in the same server block.
1 parent 927381c commit ea6a17f

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ challenge data for all the configured certificate issuers.
159159

160160
### `acme_certificate`
161161

162-
Syntax: `acme_certificate issuer=_issuer_name_ [key=alg[:size]|file] [identifiers...];`\
162+
Syntax: `acme_certificate issuer=_issuer_name_ [key=alg[:size]|file] [server_name] [identifiers...];`\
163163
Context: `server`
164164

165165
Defines a certificate with the list of _identifiers_ requested from issuer
@@ -169,6 +169,11 @@ The `key` parameter sets the type of generated private key or a path to an
169169
existing file. Supported key algorithms and sizes:
170170
`ecdsa:256` (default), `ecdsa:384`, `ecdsa:521`, `rsa:2048`..`rsa:4096`.
171171

172+
The `server_name` parameter allows taking the list of identifiers from the
173+
`server_name` directive in the same server block instead of specifying names
174+
explicitly. Not all the values accepted by `server_name` are valid certificate
175+
identifiers: regular expressions and wildcards are not supported.
176+
172177
Since 1.27.2, the `key` parameter supports the additional schemes implemented
173178
in the [`ssl_certificate_key`] directive: `data:`, `engine:` and more recently
174179
`store:`, with a caveat that password-protected keys are not supported.

src/conf.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub struct AcmeServerConfig {
3939
// A single sertificate per server is supported for now.
4040
// With multiple certs we will have to implement certificate selection.
4141
pub order: Option<CertificateOrder<ngx_str_t, Pool>>,
42+
/// Read identifiers set by "server_name" in the server block.
43+
pub server_name: bool,
4244
}
4345

4446
pub static mut NGX_HTTP_ACME_COMMANDS: [ngx_command_t; 4] = [
@@ -277,12 +279,17 @@ extern "C" fn cmd_add_certificate(
277279
continue;
278280
}
279281

282+
if value.as_bytes() == b"server_name" {
283+
ascf.server_name = true;
284+
continue;
285+
}
286+
280287
if let Err(err) = order.try_add_identifier(value) {
281288
return cf.error(&args[0], err);
282289
}
283290
}
284291

285-
if order.identifiers.is_empty() {
292+
if order.identifiers.is_empty() && !ascf.server_name {
286293
return c"no identifiers".as_ptr().cast_mut();
287294
}
288295

@@ -443,6 +450,25 @@ impl AcmeMainConfig {
443450
continue;
444451
};
445452

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

@@ -161,6 +162,34 @@ impl CertificateOrder<ngx_str_t, Pool> {
161162
Ok(())
162163
}
163164

165+
pub fn add_server_names(
166+
&mut self,
167+
cf: &mut ngx_conf_t,
168+
server_names: &[ngx_http_server_name_t],
169+
) -> Result<(), IdentifierError> {
170+
for server_name in server_names {
171+
if !server_name.regex.is_null() {
172+
ngx_log_error!(
173+
nginx_sys::NGX_LOG_WARN,
174+
cf.log,
175+
"\"acme_certificate\": unsupported regular expression in server_name: {}",
176+
server_name.name
177+
);
178+
continue;
179+
}
180+
181+
// A valid server_name entry that we want to ignore.
182+
// We'll fail properly later if that's the only entry.
183+
if server_name.name.is_empty() {
184+
continue;
185+
}
186+
187+
self.try_add_identifier(&server_name.name)?;
188+
}
189+
190+
Ok(())
191+
}
192+
164193
pub fn try_add_identifier(&mut self, value: &ngx_str_t) -> Result<(), IdentifierError> {
165194
if value.is_empty() {
166195
return Err(IdentifierError::Empty);

0 commit comments

Comments
 (0)