Skip to content

Commit

Permalink
Merge pull request #3268 from didier-wenzek/refactor/simplify_csr_cre…
Browse files Browse the repository at this point in the history
…ation

refactor: Untangle certificate request, creation and renewal
  • Loading branch information
didier-wenzek authored Nov 28, 2024
2 parents 974562d + 88bcaad commit 649e4ed
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 215 deletions.
61 changes: 23 additions & 38 deletions crates/common/certificate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::Path;
use std::path::PathBuf;
use time::Duration;
use time::OffsetDateTime;
use zeroize::Zeroizing;
pub use zeroize::Zeroizing;
#[cfg(feature = "reqwest")]
mod cloud_root_certificate;
#[cfg(feature = "reqwest")]
Expand Down Expand Up @@ -124,6 +124,20 @@ impl KeyCertPair {
let not_before = today - Duration::days(1); // Ensure the certificate is valid today
let params =
Self::create_selfsigned_certificate_parameters(config, id, key_kind, not_before)?;

Ok(KeyCertPair {
certificate: Zeroizing::new(Certificate::from_params(params)?),
})
}

pub fn new_certificate_sign_request(
config: &NewCertificateConfig,
id: &str,
key_kind: &KeyKind,
) -> Result<KeyCertPair, CertificateError> {
// Create Certificate without `not_before` and `not_after` fields
// as rcgen library will not parse it for certificate signing request
let params = Self::create_csr_parameters(config, id, key_kind)?;
Ok(KeyCertPair {
certificate: Zeroizing::new(Certificate::from_params(params)?),
})
Expand All @@ -135,48 +149,19 @@ impl KeyCertPair {
key_kind: &KeyKind,
not_before: OffsetDateTime,
) -> Result<CertificateParams, CertificateError> {
KeyCertPair::check_identifier(id, config.max_cn_size)?;
let mut distinguished_name = rcgen::DistinguishedName::new();
distinguished_name.push(rcgen::DnType::CommonName, id);
distinguished_name.push(rcgen::DnType::OrganizationName, &config.organization_name);
distinguished_name.push(
rcgen::DnType::OrganizationalUnitName,
&config.organizational_unit_name,
);

let mut params = CertificateParams::default();

params.distinguished_name = distinguished_name;
let mut params = Self::create_csr_parameters(config, id, key_kind)?;

let not_after = not_before + Duration::days(config.validity_period_days.into());
params.not_before = not_before;
params.not_after = not_after;

params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); // IsCa::SelfSignedOnly is rejected by C8Y

params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; // ECDSA signing using the P-256 curves and SHA-256 hashing as per RFC 5758

if let KeyKind::Reuse { keypair_pem } = key_kind {
params.key_pair = Some(KeyPair::from_pem(keypair_pem)?);
}
// IsCa::SelfSignedOnly is rejected by C8Y with "422 Unprocessable Entity"
params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);

Ok(params)
}

// Create Certificate without `not_before` and `not_after` fields
// as rcgen library will not parse it for certificate signing request
pub fn new_certificate_sign_request(
config: &NewCertificateConfig,
id: &str,
key_kind: &KeyKind,
) -> Result<KeyCertPair, CertificateError> {
let params = Self::create_certificate_sign_request_parameters(config, id, key_kind)?;
Ok(KeyCertPair {
certificate: Zeroizing::new(Certificate::from_params(params)?),
})
}

fn create_certificate_sign_request_parameters(
fn create_csr_parameters(
config: &NewCertificateConfig,
id: &str,
key_kind: &KeyKind,
Expand All @@ -193,7 +178,8 @@ impl KeyCertPair {
let mut params = CertificateParams::default();
params.distinguished_name = distinguished_name;

params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; // ECDSA signing using the P-256 curves and SHA-256 hashing as per RFC 5758
// ECDSA signing using the P-256 curves and SHA-256 hashing as per RFC 5758
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;

if let KeyKind::Reuse { keypair_pem } = key_kind {
params.key_pair = Some(KeyPair::from_pem(keypair_pem)?);
Expand Down Expand Up @@ -464,9 +450,8 @@ mod tests {
let config = NewCertificateConfig::default();
let id = "some-id";

let params =
KeyCertPair::create_certificate_sign_request_parameters(&config, id, &KeyKind::New)
.expect("Fail to get a certificate parameters");
let params = KeyCertPair::create_csr_parameters(&config, id, &KeyKind::New)
.expect("Fail to get a certificate parameters");

let keypair = KeyCertPair {
certificate: Zeroizing::new(
Expand Down
21 changes: 12 additions & 9 deletions crates/core/tedge/src/cli/certificate/cli.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::bridge::BridgeLocation;
use camino::Utf8PathBuf;
use tedge_config::OptionalConfigError;
use tedge_config::ProfileName;
Expand Down Expand Up @@ -52,10 +51,10 @@ pub enum TEdgeCertCli {
impl BuildCommand for TEdgeCertCli {
fn build_command(self, context: BuildContext) -> Result<Box<dyn Command>, ConfigError> {
let config = context.load_config()?;
let bridge_location = if config.mqtt.bridge.built_in {
BridgeLocation::BuiltIn
let (user, group) = if config.mqtt.bridge.built_in {
("tedge", "tedge")
} else {
BridgeLocation::Mosquitto
(crate::BROKER_USER, crate::BROKER_USER)
};

let cmd = match self {
Expand All @@ -64,20 +63,25 @@ impl BuildCommand for TEdgeCertCli {
id,
cert_path: config.device.cert_path.clone(),
key_path: config.device.key_path.clone(),
csr_path: None,
bridge_location,
user: user.to_owned(),
group: group.to_owned(),
};
cmd.into_boxed()
}

TEdgeCertCli::CreateCsr { id, output_path } => {
// Use the current device id if no id is provided
let id = match id {
Some(id) => id,
None => config.device.id.try_read(&config)?.clone(),
};
let cmd = CreateCsrCmd {
id,
cert_path: config.device.cert_path.clone(),
key_path: config.device.key_path.clone(),
// Use output file instead of csr_path from tedge config if provided
csr_path: output_path.unwrap_or_else(|| config.device.csr_path.clone()),
bridge_location,
user: user.to_owned(),
group: group.to_owned(),
};
cmd.into_boxed()
}
Expand Down Expand Up @@ -123,7 +127,6 @@ impl BuildCommand for TEdgeCertCli {
let cmd = RenewCertCmd {
cert_path: config.device.cert_path.clone(),
key_path: config.device.key_path.clone(),
bridge_location,
};
cmd.into_boxed()
}
Expand Down
Loading

0 comments on commit 649e4ed

Please sign in to comment.