11//! OpenSSH certificate builder.
22
33use 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+ } ;
58use alloc:: { string:: String , vec:: Vec } ;
69
710#[ cfg( feature = "rand_core" ) ]
811use rand_core:: CryptoRngCore ;
912
13+ use core:: future:: Future ;
1014#[ cfg( feature = "std" ) ]
1115use 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