diff --git a/acme_common/src/crypto.rs b/acme_common/src/crypto.rs index 55990b5..e4d051a 100644 --- a/acme_common/src/crypto.rs +++ b/acme_common/src/crypto.rs @@ -19,6 +19,12 @@ pub enum BaseHashFunction { Sha512, } +impl BaseHashFunction { + pub fn list_possible_values() -> Vec<&'static str> { + vec!["sha256", "sha384", "sha512"] + } +} + impl FromStr for BaseHashFunction { type Err = Error; diff --git a/acme_common/src/crypto/openssl_certificate.rs b/acme_common/src/crypto/openssl_certificate.rs index 7838431..bfac7cc 100644 --- a/acme_common/src/crypto/openssl_certificate.rs +++ b/acme_common/src/crypto/openssl_certificate.rs @@ -1,5 +1,6 @@ use super::{gen_keypair, KeyPair, KeyType}; use crate::b64_encode; +use crate::crypto::HashFunction; use crate::error::Error; use openssl::asn1::Asn1Time; use openssl::bn::{BigNum, MsbOption}; @@ -70,17 +71,18 @@ impl X509Certificate { domain: &str, acme_ext: &str, key_type: KeyType, + digest: HashFunction, ) -> Result<(KeyPair, Self), Error> { let key_pair = gen_keypair(key_type)?; #[cfg(not(any(ed25519, ed448)))] - let digest = MessageDigest::sha256(); + 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(), - _ => MessageDigest::sha256(), + _ => digest.native_digest(), }; let inner_cert = gen_certificate(domain, &key_pair, &digest, acme_ext)?; let cert = X509Certificate { inner_cert }; diff --git a/acme_common/src/crypto/openssl_hash.rs b/acme_common/src/crypto/openssl_hash.rs index aad8e87..00d1a80 100644 --- a/acme_common/src/crypto/openssl_hash.rs +++ b/acme_common/src/crypto/openssl_hash.rs @@ -1,3 +1,4 @@ +use openssl::hash::MessageDigest; use openssl::sha::{sha256, sha384, sha512}; pub type HashFunction = super::BaseHashFunction; @@ -10,4 +11,12 @@ impl HashFunction { HashFunction::Sha512 => sha512(data).to_vec(), } } + + pub(crate) fn native_digest(&self) -> MessageDigest { + match self { + HashFunction::Sha256 => MessageDigest::sha256(), + HashFunction::Sha384 => MessageDigest::sha384(), + HashFunction::Sha512 => MessageDigest::sha512(), + } + } } diff --git a/man/en/tacd.8 b/man/en/tacd.8 index c8b5a74..9579e5c 100644 --- a/man/en/tacd.8 +++ b/man/en/tacd.8 @@ -14,6 +14,7 @@ .Nm .Op Fl e|--acme-ext Ar STRING .Op Fl -acme-ext-file Ar FILE +.Op Fl -crt-digest Ar STRING .Op Fl -crt-signature-alg Ar STRING .Op Fl d|--domain Ar STRING .Op Fl -domain-file Ar STRING @@ -50,6 +51,16 @@ The options are as follows: The acmeIdentifier extension to set in the self-signed certificate. .It Fl -acme-ext-file Ar FILE File from which is read the acmeIdentifier extension to set in the self-signed certificate. +.It Fl -crt-digest Ar STRING +Set the certificate's digest algorithm. Possible values are: +.Bl -dash -compact +.It +sha256 +.It +sha384 +.It +sha512 +.El .It Fl -crt-signature-alg Ar STRING Set the certificate's signature algorithm. Possible values depends on the cryptographic library support and can be listed using the .Em --help diff --git a/tacd/src/main.rs b/tacd/src/main.rs index 8e680fc..5e3d04b 100644 --- a/tacd/src/main.rs +++ b/tacd/src/main.rs @@ -1,7 +1,7 @@ mod openssl_server; use crate::openssl_server::start as server_start; -use acme_common::crypto::{KeyType, X509Certificate}; +use acme_common::crypto::{HashFunction, KeyType, X509Certificate}; use acme_common::error::Error; use acme_common::logs::{set_log_system, DEFAULT_LOG_LEVEL}; use acme_common::{clean_pid_file, to_idna}; @@ -15,6 +15,7 @@ const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); const DEFAULT_PID_FILE: &str = "/var/run/tacd.pid"; const DEFAULT_LISTEN_ADDR: &str = "127.0.0.1:5001"; const DEFAULT_CRT_KEY_TYPE: KeyType = KeyType::EcdsaP256; +const DEFAULT_CRT_DIGEST: HashFunction = HashFunction::Sha256; const ALPN_ACME_PROTO_NAME: &[u8] = b"\x0aacme-tls/1"; fn read_line(path: Option<&str>) -> Result { @@ -55,7 +56,11 @@ fn init(cnf: &ArgMatches) -> Result<(), Error> { Some(alg) => alg.parse()?, None => DEFAULT_CRT_KEY_TYPE, }; - let (pk, cert) = X509Certificate::from_acme_ext(&domain, &ext, crt_signature_alg)?; + let crt_digest = match cnf.value_of("crt-digest") { + Some(alg) => alg.parse()?, + None => DEFAULT_CRT_DIGEST, + }; + let (pk, cert) = X509Certificate::from_acme_ext(&domain, &ext, crt_signature_alg, crt_digest)?; info!("Starting {} on {} for {}", APP_NAME, listen_addr, domain); server_start(listen_addr, &cert, &pk)?; Ok(()) @@ -63,6 +68,7 @@ fn init(cnf: &ArgMatches) -> Result<(), Error> { fn main() { let default_crt_key_type = DEFAULT_CRT_KEY_TYPE.to_string(); + let default_crt_digest = DEFAULT_CRT_DIGEST.to_string(); let default_log_level = DEFAULT_LOG_LEVEL.to_string().to_lowercase(); let matches = App::new(APP_NAME) .version(APP_VERSION) @@ -118,6 +124,15 @@ fn main() { .possible_values(&KeyType::list_possible_values()) .default_value(&default_crt_key_type) ) + .arg( + Arg::with_name("crt-digest") + .long("crt-digest") + .help("The certificate's digest algorithm") + .takes_value(true) + .value_name("STRING") + .possible_values(&HashFunction::list_possible_values()) + .default_value(&default_crt_digest) + ) .arg( Arg::with_name("log-level") .long("log-level")