Skip to content

Commit 34f6364

Browse files
committed
async sign
1 parent 3d8f0c9 commit 34f6364

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

ssh-key/src/certificate/builder.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
//! OpenSSH certificate builder.
22
33
use super::{unix_time::UnixTime, CertType, Certificate, Field, OptionsMap};
4-
use crate::{public, Result, Signature, SigningKey};
4+
use crate::{
5+
public::{self, KeyData},
6+
PublicKey, Result, Signature, SigningKey,
7+
};
58
use alloc::{string::String, vec::Vec};
69

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

13+
use core::future::Future;
1014
#[cfg(feature = "std")]
1115
use std::time::SystemTime;
1216

@@ -270,10 +274,7 @@ impl Builder {
270274
Ok(self)
271275
}
272276

273-
/// Sign the certificate using the provided signer type.
274-
///
275-
/// The [`PrivateKey`] type can be used as a signer.
276-
pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
277+
fn placeholder_certificate(self, public_key: KeyData) -> Result<Certificate> {
277278
// Empty valid principals result in a "golden ticket", so this check
278279
// ensures that was explicitly configured via `all_principals_valid`.
279280
let valid_principals = match self.valid_principals {
@@ -294,9 +295,17 @@ impl Builder {
294295
extensions: self.extensions,
295296
reserved: Vec::new(),
296297
comment: self.comment.unwrap_or_default(),
297-
signature_key: signing_key.public_key(),
298+
signature_key: public_key,
298299
signature: Signature::placeholder(),
299300
};
301+
Ok(cert)
302+
}
303+
304+
/// Sign the certificate using the provided signer type.
305+
///
306+
/// The [`PrivateKey`] type can be used as a signer.
307+
pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
308+
let mut cert = self.placeholder_certificate(signing_key.public_key())?;
300309

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

311320
Ok(cert)
312321
}
322+
323+
/// Sign the certicate using the `signer` (async) closure
324+
///
325+
/// `signing_public_key`: public key to verify the signature generated by `signer`
326+
/// `signer`: closure which generates an signature over the certificate data
327+
/// `check_signature`: wheather to check if the generated signature corresponds to the
328+
/// specified `signing_public_key`
329+
pub async fn with_signer<S, F>(
330+
self,
331+
signing_public_key: KeyData,
332+
signer: S,
333+
check_signature: bool,
334+
) -> Result<Certificate>
335+
where
336+
S: Fn(&[u8]) -> F,
337+
F: Future<Output = Result<Signature>>,
338+
{
339+
let mut cert = self.placeholder_certificate(signing_public_key)?;
340+
341+
let mut tbs_cert = Vec::new();
342+
cert.encode_tbs(&mut tbs_cert)?;
343+
cert.signature = signer(&tbs_cert).await?;
344+
345+
if check_signature {
346+
cert.validate_at(
347+
cert.valid_after.into(),
348+
&[cert.signature_key.fingerprint(Default::default())],
349+
)?;
350+
}
351+
352+
Ok(cert)
353+
}
313354
}

0 commit comments

Comments
 (0)