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 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 {
inner_csr: X509Req,
}
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()?;
builder.set_pubkey(&key_pair.inner_key)?;
let ctx = builder.x509v3_context(None);
@ -39,7 +59,8 @@ impl Csr {
let mut ext_stack = Stack::new()?;
ext_stack.push(san)?;
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 {
inner_csr: builder.build(),
})
@ -50,6 +71,11 @@ impl Csr {
let csr = b64_encode(&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 {
@ -74,16 +100,7 @@ impl X509Certificate {
digest: HashFunction,
) -> Result<(KeyPair, Self), Error> {
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 cert = X509Certificate { inner_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)
.map(|e| e.value.to_owned())
.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!({
"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 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::identifier::{Identifier, IdentifierType};
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 log::{debug, info, trace, warn};
use std::collections::{HashMap, HashSet};
@ -47,6 +47,7 @@ pub struct Certificate {
pub account: Account,
pub identifiers: Vec<Identifier>,
pub algo: Algorithm,
pub csr_digest: HashFunction,
pub kp_reuse: bool,
pub endpoint_name: String,
pub hooks: Vec<Hook>,

9
acmed/src/config.rs

@ -2,6 +2,7 @@ use crate::certificate::Algorithm;
use crate::duration::parse_duration;
use crate::hooks;
use crate::identifier::IdentifierType;
use acme_common::crypto::HashFunction;
use acme_common::error::Error;
use glob::glob;
use log::info;
@ -298,6 +299,7 @@ pub struct Certificate {
pub endpoint: String,
pub identifiers: Vec<Identifier>,
pub algorithm: Option<String>,
pub csr_digest: Option<String>,
pub kp_reuse: Option<bool>,
pub directory: Option<String>,
pub name: Option<String>,
@ -328,6 +330,13 @@ impl Certificate {
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> {
let mut ret = vec![];
for id in self.identifiers.iter() {

2
acmed/src/main.rs

@ -1,4 +1,5 @@
use crate::main_event_loop::MainEventLoop;
use acme_common::crypto::HashFunction;
use acme_common::logs::{set_log_system, DEFAULT_LOG_LEVEL};
use acme_common::{clean_pid_file, crypto, init_server};
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_SLEEP_TIME: u64 = 3600;
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_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;

1
acmed/src/main_event_loop.rs

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

11
man/en/acmed.toml.5

@ -239,6 +239,17 @@ ecdsa_p256
.It
ecdsa_p384
.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
Set whether or not the private key should be reused when renewing the certificate. Default is false.
.It Ic directory Ar string

Loading…
Cancel
Save