use std::path::PathBuf;
use clap::Parser;
use cosmian_kms_client::{
KmsClient,
kmip_2_1::kmip_types::UniqueIdentifier,
read_bytes_from_file,
reexport::cosmian_kms_client_utils::certificate_utils::{Algorithm, build_certify_request},
};
use crate::{
actions::kms::{
console,
labels::{CERTIFICATE_ID, CERTIFICATE_RECERTIFY},
},
error::{KmsCliError, result::KmsCliResult},
};
#[derive(Parser)]
#[clap(verbatim_doc_comment)]
pub struct CertifyAction {
#[clap(long = CERTIFICATE_ID, short = 'c')]
pub(crate) certificate_id: Option<String>,
#[clap(
long = "certificate-signing-request",
short = 'r',
group = "csr_pk",
required = false
)]
pub(crate) certificate_signing_request: Option<PathBuf>,
#[clap(long ="certificate-signing-request-format", short = 'f', default_value="pem", value_parser(["pem", "der"]))]
pub(crate) certificate_signing_request_format: String,
#[clap(
long = "public-key-id-to-certify",
short = 'p',
group = "csr_pk",
requires = "subject_name",
required = false
)]
pub(crate) public_key_id_to_certify: Option<String>,
#[clap(
long = CERTIFICATE_RECERTIFY,
short = 'n',
group = "csr_pk",
required = false
)]
pub(crate) certificate_id_to_re_certify: Option<String>,
#[clap(
long = "generate-key-pair",
short = 'g',
group = "csr_pk",
requires = "subject_name",
requires = "algorithm",
required = false
)]
pub(crate) generate_key_pair: bool,
#[clap(long = "subject-name", short = 's', verbatim_doc_comment)]
pub(crate) subject_name: Option<String>,
#[clap(long = "algorithm", short = 'a', default_value = "rsa4096")]
pub(crate) algorithm: Algorithm,
#[clap(long = "issuer-private-key-id", short = 'k')]
pub(crate) issuer_private_key_id: Option<String>,
#[clap(long = "issuer-certificate-id", short = 'i')]
pub(crate) issuer_certificate_id: Option<String>,
#[clap(long = "days", short = 'd', default_value = "365")]
pub(crate) number_of_days: usize,
#[clap(long = "certificate-extensions", short = 'e', verbatim_doc_comment)]
pub(crate) certificate_extensions: Option<PathBuf>,
#[clap(long = "tag", short = 't', value_name = "TAG")]
pub(crate) tags: Vec<String>,
}
impl Default for CertifyAction {
fn default() -> Self {
Self {
certificate_id: None,
certificate_signing_request: None,
certificate_signing_request_format: "pem".to_owned(),
public_key_id_to_certify: None,
certificate_id_to_re_certify: None,
generate_key_pair: false,
subject_name: None,
algorithm: Algorithm::RSA4096,
issuer_private_key_id: None,
issuer_certificate_id: None,
number_of_days: 365,
certificate_extensions: None,
tags: vec![],
}
}
}
impl CertifyAction {
pub async fn run(&self, kms_rest_client: KmsClient) -> KmsCliResult<UniqueIdentifier> {
let certificate_signing_request_bytes = self
.certificate_signing_request
.as_ref()
.map(read_bytes_from_file)
.transpose()?;
let certificate_extensions_bytes = self
.certificate_extensions
.as_ref()
.map(std::fs::read)
.transpose()?;
let certify_request = build_certify_request(
kms_rest_client.config.vendor_id.as_str(),
&self.certificate_id,
&Some(self.certificate_signing_request_format.clone()),
&certificate_signing_request_bytes,
&self.public_key_id_to_certify,
&self.certificate_id_to_re_certify,
self.generate_key_pair,
&self.subject_name,
self.algorithm,
&self.issuer_private_key_id,
&self.issuer_certificate_id,
self.number_of_days,
&certificate_extensions_bytes,
&self.tags,
)?;
let certificate_unique_identifier = kms_rest_client
.certify(certify_request)
.await
.map_err(|e| KmsCliError::ServerError(format!("failed creating certificate: {e:?}")))?
.unique_identifier;
let mut stdout = console::Stdout::new("The certificate was successfully generated.");
stdout.set_tags(Some(&self.tags));
stdout.set_unique_identifier(&certificate_unique_identifier);
stdout.write()?;
Ok(certificate_unique_identifier)
}
}