Browse Source

Allow to specify the CSR's digest algorithm

pull/39/head
Rodolphe Breard 4 years ago
parent
commit
bea33179d7
  1. 41
      acme_common/src/crypto/openssl_certificate.rs
  2. 9
      acmed/src/acme_proto.rs
  3. 3
      acmed/src/certificate.rs
  4. 9
      acmed/src/config.rs
  5. 2
      acmed/src/main.rs
  6. 1
      acmed/src/main_event_loop.rs
  7. 11
      man/en/acmed.toml.5

41
acme_common/src/crypto/openssl_certificate.rs

@ -19,12 +19,32 @@ const CRT_SERIAL_NB_BITS: i32 = 32;
const CRT_NB_DAYS_VALIDITY: u32 = 7; const CRT_NB_DAYS_VALIDITY: u32 = 7;
const INVALID_EXT_MSG: &str = "Invalid acmeIdentifier extension."; const INVALID_EXT_MSG: &str = "Invalid acmeIdentifier extension.";
fn get_digest(digest: HashFunction, key_pair: &KeyPair) -> MessageDigest {
#[cfg(not(any(ed25519, ed448)))]
let digest = digest.native_digest();
let _ = key_pair;
#[cfg(any(ed25519, ed448))]
let digest = match key_pair.key_type {
#[cfg(ed25519)]
KeyType::Ed25519 => MessageDigest::null(),
#[cfg(ed448)]
KeyType::Ed448 => MessageDigest::null(),
_ => digest.native_digest(),
};
digest
}
pub struct Csr { pub struct Csr {
inner_csr: X509Req, inner_csr: X509Req,
} }
impl Csr { impl Csr {
pub fn new(key_pair: &KeyPair, domains: &[String], ips: &[String]) -> Result<Self, Error> {
pub fn new(
key_pair: &KeyPair,
digest: HashFunction,
domains: &[String],
ips: &[String],
) -> Result<Self, Error> {
let mut builder = X509ReqBuilder::new()?; let mut builder = X509ReqBuilder::new()?;
builder.set_pubkey(&key_pair.inner_key)?; builder.set_pubkey(&key_pair.inner_key)?;
let ctx = builder.x509v3_context(None); let ctx = builder.x509v3_context(None);
@ -39,7 +59,8 @@ impl Csr {
let mut ext_stack = Stack::new()?; let mut ext_stack = Stack::new()?;
ext_stack.push(san)?; ext_stack.push(san)?;
builder.add_extensions(&ext_stack)?; builder.add_extensions(&ext_stack)?;
builder.sign(&key_pair.inner_key, MessageDigest::sha256())?;
let digest = get_digest(digest, key_pair);
builder.sign(&key_pair.inner_key, digest)?;
Ok(Csr { Ok(Csr {
inner_csr: builder.build(), inner_csr: builder.build(),
}) })
@ -50,6 +71,11 @@ impl Csr {
let csr = b64_encode(&csr); let csr = b64_encode(&csr);
Ok(csr) Ok(csr)
} }
pub fn to_pem(&self) -> Result<String, Error> {
let csr = self.inner_csr.to_pem()?;
Ok(String::from_utf8(csr)?)
}
} }
pub struct X509Certificate { pub struct X509Certificate {
@ -74,16 +100,7 @@ impl X509Certificate {
digest: HashFunction, digest: HashFunction,
) -> Result<(KeyPair, Self), Error> { ) -> Result<(KeyPair, Self), Error> {
let key_pair = gen_keypair(key_type)?; let key_pair = gen_keypair(key_type)?;
#[cfg(not(any(ed25519, ed448)))]
let digest = digest.native_digest();
#[cfg(any(ed25519, ed448))]
let digest = match key_pair.key_type {
#[cfg(ed25519)]
KeyType::Ed25519 => MessageDigest::null(),
#[cfg(ed448)]
KeyType::Ed448 => MessageDigest::null(),
_ => digest.native_digest(),
};
let digest = get_digest(digest, &key_pair);
let inner_cert = gen_certificate(domain, &key_pair, &digest, acme_ext)?; let inner_cert = gen_certificate(domain, &key_pair, &digest, acme_ext)?;
let cert = X509Certificate { inner_cert }; let cert = X509Certificate { inner_cert };
Ok((key_pair, cert)) Ok((key_pair, cert))

9
acmed/src/acme_proto.rs

@ -171,8 +171,15 @@ pub fn request_certificate(
.filter(|e| e.id_type == IdentifierType::Ip) .filter(|e| e.id_type == IdentifierType::Ip)
.map(|e| e.value.to_owned()) .map(|e| e.value.to_owned())
.collect(); .collect();
let csr = Csr::new(
&key_pair,
cert.csr_digest,
domains.as_slice(),
ips.as_slice(),
)?;
cert.trace(&format!("New CSR:\n{}", csr.to_pem()?));
let csr = json!({ let csr = json!({
"csr": Csr::new(&key_pair, domains.as_slice(), ips.as_slice())?.to_der_base64()?,
"csr": csr.to_der_base64()?,
}); });
let csr = csr.to_string(); let csr = csr.to_string();
let data_builder = set_data_builder!(account, csr.as_bytes()); let data_builder = set_data_builder!(account, csr.as_bytes());

3
acmed/src/certificate.rs

@ -3,7 +3,7 @@ use crate::acme_proto::Challenge;
use crate::hooks::{self, ChallengeHookData, Hook, HookEnvData, HookType, PostOperationHookData}; use crate::hooks::{self, ChallengeHookData, Hook, HookEnvData, HookType, PostOperationHookData};
use crate::identifier::{Identifier, IdentifierType}; use crate::identifier::{Identifier, IdentifierType};
use crate::storage::{certificate_files_exists, get_certificate}; use crate::storage::{certificate_files_exists, get_certificate};
use acme_common::crypto::X509Certificate;
use acme_common::crypto::{HashFunction, X509Certificate};
use acme_common::error::Error; use acme_common::error::Error;
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@ -47,6 +47,7 @@ pub struct Certificate {
pub account: Account, pub account: Account,
pub identifiers: Vec<Identifier>, pub identifiers: Vec<Identifier>,
pub algo: Algorithm, pub algo: Algorithm,
pub csr_digest: HashFunction,
pub kp_reuse: bool, pub kp_reuse: bool,
pub endpoint_name: String, pub endpoint_name: String,
pub hooks: Vec<Hook>, pub hooks: Vec<Hook>,

9
acmed/src/config.rs

@ -2,6 +2,7 @@ use crate::certificate::Algorithm;
use crate::duration::parse_duration; use crate::duration::parse_duration;
use crate::hooks; use crate::hooks;
use crate::identifier::IdentifierType; use crate::identifier::IdentifierType;
use acme_common::crypto::HashFunction;
use acme_common::error::Error; use acme_common::error::Error;
use glob::glob; use glob::glob;
use log::info; use log::info;
@ -298,6 +299,7 @@ pub struct Certificate {
pub endpoint: String, pub endpoint: String,
pub identifiers: Vec<Identifier>, pub identifiers: Vec<Identifier>,
pub algorithm: Option<String>, pub algorithm: Option<String>,
pub csr_digest: Option<String>,
pub kp_reuse: Option<bool>, pub kp_reuse: Option<bool>,
pub directory: Option<String>, pub directory: Option<String>,
pub name: Option<String>, pub name: Option<String>,
@ -328,6 +330,13 @@ impl Certificate {
Algorithm::from_str(algo) Algorithm::from_str(algo)
} }
pub fn get_csr_digest(&self) -> Result<HashFunction, Error> {
match &self.csr_digest {
Some(d) => d.parse(),
None => Ok(crate::DEFAULT_CSR_DIGEST),
}
}
pub fn get_identifiers(&self) -> Result<Vec<crate::identifier::Identifier>, Error> { pub fn get_identifiers(&self) -> Result<Vec<crate::identifier::Identifier>, Error> {
let mut ret = vec![]; let mut ret = vec![];
for id in self.identifiers.iter() { for id in self.identifiers.iter() {

2
acmed/src/main.rs

@ -1,4 +1,5 @@
use crate::main_event_loop::MainEventLoop; use crate::main_event_loop::MainEventLoop;
use acme_common::crypto::HashFunction;
use acme_common::logs::{set_log_system, DEFAULT_LOG_LEVEL}; use acme_common::logs::{set_log_system, DEFAULT_LOG_LEVEL};
use acme_common::{clean_pid_file, crypto, init_server}; use acme_common::{clean_pid_file, crypto, init_server};
use clap::{App, Arg}; use clap::{App, Arg};
@ -26,6 +27,7 @@ pub const DEFAULT_CERT_DIR: &str = "/etc/acmed/certs";
pub const DEFAULT_CERT_FORMAT: &str = "{{name}}_{{algo}}.{{file_type}}.{{ext}}"; pub const DEFAULT_CERT_FORMAT: &str = "{{name}}_{{algo}}.{{file_type}}.{{ext}}";
pub const DEFAULT_SLEEP_TIME: u64 = 3600; pub const DEFAULT_SLEEP_TIME: u64 = 3600;
pub const DEFAULT_POOL_TIME: u64 = 5000; pub const DEFAULT_POOL_TIME: u64 = 5000;
pub const DEFAULT_CSR_DIGEST: HashFunction = HashFunction::Sha256;
pub const DEFAULT_CERT_FILE_MODE: u32 = 0o644; pub const DEFAULT_CERT_FILE_MODE: u32 = 0o644;
pub const DEFAULT_CERT_RENEW_DELAY: u64 = 1_814_400; // 1_814_400 is 3 weeks (3 * 7 * 24 * 60 * 60) pub const DEFAULT_CERT_RENEW_DELAY: u64 = 1_814_400; // 1_814_400 is 3 weeks (3 * 7 * 24 * 60 * 60)
pub const DEFAULT_PK_FILE_MODE: u32 = 0o600; pub const DEFAULT_PK_FILE_MODE: u32 = 0o600;

1
acmed/src/main_event_loop.rs

@ -48,6 +48,7 @@ impl MainEventLoop {
account: crt.get_account(&cnf)?, account: crt.get_account(&cnf)?,
identifiers: crt.get_identifiers()?, identifiers: crt.get_identifiers()?,
algo: crt.get_algorithm()?, algo: crt.get_algorithm()?,
csr_digest: crt.get_csr_digest()?,
kp_reuse: crt.get_kp_reuse(), kp_reuse: crt.get_kp_reuse(),
endpoint_name: endpoint_name.clone(), endpoint_name: endpoint_name.clone(),
hooks: crt.get_hooks(&cnf)?, hooks: crt.get_hooks(&cnf)?,

11
man/en/acmed.toml.5

@ -239,6 +239,17 @@ ecdsa_p256
.It .It
ecdsa_p384 ecdsa_p384
.El .El
.It Ic csr_digest Ar string
Name of the certificate's signing request digest algorithm. Possible values are :
.Bl -dash -compact
.It
sha256
.Aq default
.It
sha384
.It
sha512
.El
.It Ic kp_reuse Ar boolean .It Ic kp_reuse Ar boolean
Set whether or not the private key should be reused when renewing the certificate. Default is false. Set whether or not the private key should be reused when renewing the certificate. Default is false.
.It Ic directory Ar string .It Ic directory Ar string

Loading…
Cancel
Save