Skip to content

Commit

Permalink
async sign
Browse files Browse the repository at this point in the history
  • Loading branch information
shimunn committed Feb 8, 2025
1 parent 3d8f0c9 commit 34f6364
Showing 1 changed file with 47 additions and 6 deletions.
53 changes: 47 additions & 6 deletions ssh-key/src/certificate/builder.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
//! OpenSSH certificate builder.
use super::{unix_time::UnixTime, CertType, Certificate, Field, OptionsMap};
use crate::{public, Result, Signature, SigningKey};
use crate::{
public::{self, KeyData},
PublicKey, Result, Signature, SigningKey,
};
use alloc::{string::String, vec::Vec};

#[cfg(feature = "rand_core")]
use rand_core::CryptoRngCore;

use core::future::Future;
#[cfg(feature = "std")]
use std::time::SystemTime;

Expand Down Expand Up @@ -270,10 +274,7 @@ impl Builder {
Ok(self)
}

/// Sign the certificate using the provided signer type.
///
/// The [`PrivateKey`] type can be used as a signer.
pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
fn placeholder_certificate(self, public_key: KeyData) -> Result<Certificate> {
// Empty valid principals result in a "golden ticket", so this check
// ensures that was explicitly configured via `all_principals_valid`.
let valid_principals = match self.valid_principals {
Expand All @@ -294,9 +295,17 @@ impl Builder {
extensions: self.extensions,
reserved: Vec::new(),
comment: self.comment.unwrap_or_default(),
signature_key: signing_key.public_key(),
signature_key: public_key,
signature: Signature::placeholder(),
};
Ok(cert)
}

/// Sign the certificate using the provided signer type.
///
/// The [`PrivateKey`] type can be used as a signer.
pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
let mut cert = self.placeholder_certificate(signing_key.public_key())?;

let mut tbs_cert = Vec::new();
cert.encode_tbs(&mut tbs_cert)?;
Expand All @@ -310,4 +319,36 @@ impl Builder {

Ok(cert)
}

/// Sign the certicate using the `signer` (async) closure
///
/// `signing_public_key`: public key to verify the signature generated by `signer`
/// `signer`: closure which generates an signature over the certificate data
/// `check_signature`: wheather to check if the generated signature corresponds to the
/// specified `signing_public_key`
pub async fn with_signer<S, F>(
self,
signing_public_key: KeyData,
signer: S,
check_signature: bool,
) -> Result<Certificate>
where
S: Fn(&[u8]) -> F,
F: Future<Output = Result<Signature>>,
{
let mut cert = self.placeholder_certificate(signing_public_key)?;

let mut tbs_cert = Vec::new();
cert.encode_tbs(&mut tbs_cert)?;
cert.signature = signer(&tbs_cert).await?;

if check_signature {
cert.validate_at(
cert.valid_after.into(),
&[cert.signature_key.fingerprint(Default::default())],
)?;
}

Ok(cert)
}
}

0 comments on commit 34f6364

Please sign in to comment.