mirror of https://github.com/breard-r/acmed.git
Rodolphe Breard
4 years ago
19 changed files with 449 additions and 139 deletions
-
7CHANGELOG.md
-
2README.md
-
29acme_common/src/crypto/openssl_certificate.rs
-
6acme_common/src/error.rs
-
1acme_common/src/tests.rs
-
84acme_common/src/tests/certificate.rs
-
26acmed/config/default_hooks.toml
-
36acmed/src/acme_proto.rs
-
2acmed/src/acme_proto/structs.rs
-
2acmed/src/acme_proto/structs/authorization.rs
-
29acmed/src/acme_proto/structs/order.rs
-
64acmed/src/certificate.rs
-
52acmed/src/config.rs
-
5acmed/src/hooks.rs
-
149acmed/src/identifier.rs
-
1acmed/src/main.rs
-
2acmed/src/main_event_loop.rs
-
8man/en/acmed.8
-
79man/en/acmed.toml.5
@ -1,2 +1,3 @@ |
|||||
|
mod certificate;
|
||||
mod crypto_keys;
|
mod crypto_keys;
|
||||
mod idna;
|
mod idna;
|
@ -0,0 +1,84 @@ |
|||||
|
use crate::crypto::X509Certificate;
|
||||
|
use std::collections::HashSet;
|
||||
|
use std::iter::FromIterator;
|
||||
|
|
||||
|
const CERTIFICATE_P256_DOMAINS_PEM: &str = r#"-----BEGIN CERTIFICATE-----
|
||||
|
MIICtDCCAZygAwIBAgIIf5BEPlNrrYkwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
|
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAyZDE2ODgwHhcNMjAwODI1MTMwMzE3
|
||||
|
WhcNMjUwODI1MTMwMzE3WjAYMRYwFAYDVQQDEw1sb2NhbC53aGF0LnRmMFkwEwYH
|
||||
|
KoZIzj0CAQYIKoZIzj0DAQcDQgAE0c/unUqpoOMxxc8e1pkpPQTSsh2irQruOJgd
|
||||
|
ITN9WLC4mzFSJ/ad64TFi4HsCFNd7mv/QRH6rW1s3LbocEvBuqOBvDCBuTAOBgNV
|
||||
|
HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
|
||||
|
EwEB/wQCMAAwHQYDVR0OBBYEFGjf1TWIZyE+QP9SGkBN6dfviIsaMB8GA1UdIwQY
|
||||
|
MBaAFLgD5DMU2ijpIxlxaAv82sQvb5ofMDoGA1UdEQQzMDGCDWxvY2FsLndoYXQu
|
||||
|
dGaCDzEubG9jYWwud2hhdC50ZoIPMi5sb2NhbC53aGF0LnRmMA0GCSqGSIb3DQEB
|
||||
|
CwUAA4IBAQDREOAU2JwHfSPGt4SYlQ3OmFl4HHI2f+XyNE/09uZVteM0aChkntgX
|
||||
|
rAZltuAAX+coSlgv3a04hJBqioDG1R9MFtf4LZBhfkgZwbzucMt8Ga3QL3XFXOkn
|
||||
|
FlOwb/ZEIjFsBFQWt1ZSA85WxIVkGsgMfQeGpu/p8gEmJAE5l0qHEVFP9cYNsIqg
|
||||
|
wsUGwZzPZFLsBXurM2cEA7cTt2HryVXlQWl8QI5YFpIpa43itYaerfMldfIfNdJ9
|
||||
|
8GLZPEfJb6t/UYYexXEkpQY9wGZkaTWvYeItuC0YlPY9RUCAl48Q85Yjf37Wbm5z
|
||||
|
f810HGl+/c6ttyoHKmLfY/GcX07AUcLc
|
||||
|
-----END CERTIFICATE-----"#;
|
||||
|
const CERTIFICATE_P256_IP_PEM: &str = r#"-----BEGIN CERTIFICATE-----
|
||||
|
MIICkTCCAXmgAwIBAgIIMW1X7DjQOFgwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
|
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxYWM3MzcwHhcNMjAwODI1MTQzMjQw
|
||||
|
WhcNMjUwODI1MTQzMjQwWjAOMQwwCgYDVQQDEwM6OjEwWTATBgcqhkjOPQIBBggq
|
||||
|
hkjOPQMBBwNCAASF+MvxX7GBAVe3McuAc+0emdFpBfAQG4mt9j8417qT76qHHyJ6
|
||||
|
oIHRNXAUxh4J78ihrvyph8TvqND73Nxk8Jj9o4GjMIGgMA4GA1UdDwEB/wQEAwIF
|
||||
|
oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd
|
||||
|
BgNVHQ4EFgQU5R7EGzjpZqrs2o/ZwuBqNHlMB2AwHwYDVR0jBBgwFoAUhEUnWREW
|
||||
|
GoAScr1wv/aXHTGOVoswIQYDVR0RBBowGIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAA
|
||||
|
ATANBgkqhkiG9w0BAQsFAAOCAQEAS8oRpjGakUU+KRtXCGoVlXgKYFe3u/G2aFMF
|
||||
|
soApjvwd3L1W9b3bsT4FquF7F5qB6TGBwiXoNBoDAeVhRcUsHbmN8GZRUaq2TEsm
|
||||
|
MwpPr8L4rqeRIuxY85AqmbGfMuFUie6r4FbwelnBniO0eMQkTW/XY41rbhGZ+lmj
|
||||
|
DTQy08oj0892py2U/YbkL3JnCBwBba//f/Ji7nnSKdJl4Yd1iguA0nbdElcWaKk3
|
||||
|
ij3t17FSNeI5uMOI3TRBr4k4bu3ZMnuN2DYFPnL6GiSEhyNrxaiac8xKuOXBICmJ
|
||||
|
oyO7pZVvc5cDcP/USPcWJYcnR9gvuL8snQdFpWND8H19eZ+i0g==
|
||||
|
-----END CERTIFICATE-----"#;
|
||||
|
const CERTIFICATE_P256_DOMAINS_IP_PEM: &str = r#"-----BEGIN CERTIFICATE-----
|
||||
|
MIICzDCCAbSgAwIBAgIIff0SyxJBhtMwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
|
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxYWM3MzcwHhcNMjAwODI1MTQzNjE1
|
||||
|
WhcNMjUwODI1MTQzNjE1WjAYMRYwFAYDVQQDEw1sb2NhbC53aGF0LnRmMFkwEwYH
|
||||
|
KoZIzj0CAQYIKoZIzj0DAQcDQgAE7Jp4AmF0TTcYfUy4TtZhN4bXn4DXWnqF0I6i
|
||||
|
Yvz4kc0r2L01nrUrICg2bmCFM7BU9pr9fcCDodH3ZuhlRqBAf6OB1DCB0TAOBgNV
|
||||
|
HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
|
||||
|
EwEB/wQCMAAwHQYDVR0OBBYEFHV0lnh55aQGfljcsjNkzZa4lTG6MB8GA1UdIwQY
|
||||
|
MBaAFIRFJ1kRFhqAEnK9cL/2lx0xjlaLMFIGA1UdEQRLMEmCDWxvY2FsLndoYXQu
|
||||
|
dGaCDzEubG9jYWwud2hhdC50ZoIPMi5sb2NhbC53aGF0LnRmhwR/AAABhxAAAAAA
|
||||
|
AAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQC3VmoTlrrTCWCd4eUB4RSB
|
||||
|
+080uco6Jl7VMqcY5F+eG1S7p4Kqz6kc1wiiKB8ILA94hdP1qTbfphdGllYiEvbs
|
||||
|
urj0x62cm5URahEDx4xn+dQkmh4XiiZgZVw2ccphjqJqJa28GsuR2zAxSkKMDnB7
|
||||
|
eX1G4/Av0XE7RqJ3Frq8qa5EjjLJTw0iEaWS5NGtZxMqWEIetCgb0IDZNxNvbeAv
|
||||
|
mmH6qnF3xQPx5FkwP/Yw4d9T4KhSHNf2/tImIlbuk3SEsOglGbKNY1juor8uw+J2
|
||||
|
5XsUZxD5QiDbCFd3dGmH58XmkiQHXs8hhIbhu9ZLgp+fNv0enVMHTTI1gGpZ5MPm
|
||||
|
-----END CERTIFICATE-----"#;
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_san_domains() {
|
||||
|
let san = vec!["local.what.tf", "1.local.what.tf", "2.local.what.tf"];
|
||||
|
let san = HashSet::from_iter(san.iter().map(|v| v.to_string()));
|
||||
|
let crt = X509Certificate::from_pem(CERTIFICATE_P256_DOMAINS_PEM.as_bytes()).unwrap();
|
||||
|
assert_eq!(crt.subject_alt_names(), san);
|
||||
|
}
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_san_ip() {
|
||||
|
let san = vec!["127.0.0.1", "::1"];
|
||||
|
let san = HashSet::from_iter(san.iter().map(|v| v.to_string()));
|
||||
|
let crt = X509Certificate::from_pem(CERTIFICATE_P256_IP_PEM.as_bytes()).unwrap();
|
||||
|
assert_eq!(crt.subject_alt_names(), san);
|
||||
|
}
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_san_domains_and_ip() {
|
||||
|
let san = vec![
|
||||
|
"127.0.0.1",
|
||||
|
"::1",
|
||||
|
"local.what.tf",
|
||||
|
"1.local.what.tf",
|
||||
|
"2.local.what.tf",
|
||||
|
];
|
||||
|
let san = HashSet::from_iter(san.iter().map(|v| v.to_string()));
|
||||
|
let crt = X509Certificate::from_pem(CERTIFICATE_P256_DOMAINS_IP_PEM.as_bytes()).unwrap();
|
||||
|
assert_eq!(crt.subject_alt_names(), san);
|
||||
|
}
|
@ -0,0 +1,149 @@ |
|||||
|
use crate::acme_proto::Challenge;
|
||||
|
use acme_common::error::Error;
|
||||
|
use acme_common::to_idna;
|
||||
|
use serde::{Deserialize, Serialize};
|
||||
|
use std::collections::HashMap;
|
||||
|
use std::fmt;
|
||||
|
use std::net::IpAddr;
|
||||
|
use std::str::FromStr;
|
||||
|
|
||||
|
// RFC 3596, section 2.5
|
||||
|
fn u8_to_nibbles_string(value: &u8) -> String {
|
||||
|
let bytes = value.to_ne_bytes();
|
||||
|
let first = bytes[0] & 0x0f;
|
||||
|
let second = (bytes[0] >> 4) & 0x0f;
|
||||
|
format!("{:x}.{:x}", first, second)
|
||||
|
}
|
||||
|
|
||||
|
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
|
||||
|
pub enum IdentifierType {
|
||||
|
#[serde(rename = "dns")]
|
||||
|
Dns,
|
||||
|
#[serde(rename = "ip")]
|
||||
|
Ip,
|
||||
|
}
|
||||
|
|
||||
|
impl IdentifierType {
|
||||
|
pub fn supported_challenges(&self) -> Vec<Challenge> {
|
||||
|
match self {
|
||||
|
IdentifierType::Dns => vec![Challenge::Http01, Challenge::Dns01, Challenge::TlsAlpn01],
|
||||
|
IdentifierType::Ip => vec![Challenge::Http01, Challenge::TlsAlpn01],
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
impl fmt::Display for IdentifierType {
|
||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
let name = match self {
|
||||
|
IdentifierType::Dns => "dns",
|
||||
|
IdentifierType::Ip => "ip",
|
||||
|
};
|
||||
|
write!(f, "{}", name)
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
#[derive(Clone, Debug)]
|
||||
|
pub struct Identifier {
|
||||
|
pub id_type: IdentifierType,
|
||||
|
pub value: String,
|
||||
|
pub challenge: Challenge,
|
||||
|
pub env: HashMap<String, String>,
|
||||
|
}
|
||||
|
|
||||
|
impl Identifier {
|
||||
|
pub fn new(
|
||||
|
id_type: IdentifierType,
|
||||
|
value: &str,
|
||||
|
challenge: &str,
|
||||
|
env: &HashMap<String, String>,
|
||||
|
) -> Result<Self, Error> {
|
||||
|
let value = match id_type {
|
||||
|
IdentifierType::Dns => to_idna(value)?,
|
||||
|
IdentifierType::Ip => IpAddr::from_str(value)?.to_string(),
|
||||
|
};
|
||||
|
let challenge = Challenge::from_str(challenge)?;
|
||||
|
if !id_type.supported_challenges().contains(&challenge) {
|
||||
|
let msg = format!(
|
||||
|
"Challenge {} cannot be used with identifier of type {}",
|
||||
|
challenge, id_type
|
||||
|
);
|
||||
|
return Err(msg.into());
|
||||
|
}
|
||||
|
Ok(Identifier {
|
||||
|
id_type,
|
||||
|
value,
|
||||
|
challenge,
|
||||
|
env: env.clone(),
|
||||
|
})
|
||||
|
}
|
||||
|
|
||||
|
pub fn get_tls_alpn_name(&self) -> Result<String, Error> {
|
||||
|
match &self.id_type {
|
||||
|
IdentifierType::Dns => Ok(self.value.to_owned()),
|
||||
|
IdentifierType::Ip => match IpAddr::from_str(&self.value)? {
|
||||
|
IpAddr::V4(ip) => {
|
||||
|
let dn = ip
|
||||
|
.octets()
|
||||
|
.iter()
|
||||
|
.rev()
|
||||
|
.map(|v| v.to_string())
|
||||
|
.collect::<Vec<String>>()
|
||||
|
.join(".");
|
||||
|
let dn = format!("{}.in-addr.arpa", dn);
|
||||
|
Ok(dn)
|
||||
|
}
|
||||
|
IpAddr::V6(ip) => {
|
||||
|
let dn = ip
|
||||
|
.octets()
|
||||
|
.iter()
|
||||
|
.rev()
|
||||
|
.map(u8_to_nibbles_string)
|
||||
|
.collect::<Vec<String>>()
|
||||
|
.join(".");
|
||||
|
let dn = format!("{}.ip6.arpa", dn);
|
||||
|
Ok(dn)
|
||||
|
}
|
||||
|
},
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
impl fmt::Display for Identifier {
|
||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
write!(f, "{}: {} ({})", self.id_type, self.value, self.challenge)
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
#[cfg(test)]
|
||||
|
mod tests {
|
||||
|
use super::*;
|
||||
|
use std::collections::HashMap;
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_ipv4_tls_alpn_name() {
|
||||
|
let env = HashMap::new();
|
||||
|
let id = Identifier::new(IdentifierType::Ip, "203.0.113.1", "http-01", &env).unwrap();
|
||||
|
assert_eq!(&id.get_tls_alpn_name().unwrap(), "1.113.0.203.in-addr.arpa");
|
||||
|
}
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_ipv6_tls_alpn_name() {
|
||||
|
let env = HashMap::new();
|
||||
|
let id = Identifier::new(IdentifierType::Ip, "2001:db8::1", "http-01", &env).unwrap();
|
||||
|
assert_eq!(
|
||||
|
&id.get_tls_alpn_name().unwrap(),
|
||||
|
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"
|
||||
|
);
|
||||
|
let id = Identifier::new(
|
||||
|
IdentifierType::Ip,
|
||||
|
"4321:0:1:2:3:4:567:89ab",
|
||||
|
"http-01",
|
||||
|
&env,
|
||||
|
)
|
||||
|
.unwrap();
|
||||
|
assert_eq!(
|
||||
|
&id.get_tls_alpn_name().unwrap(),
|
||||
|
"b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.ip6.arpa"
|
||||
|
);
|
||||
|
}
|
||||
|
}
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue