1
1
//! OpenSSH certificate builder.
2
2
3
3
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
+ } ;
5
8
use alloc:: { string:: String , vec:: Vec } ;
6
9
7
10
#[ cfg( feature = "rand_core" ) ]
8
11
use rand_core:: CryptoRngCore ;
9
12
13
+ use core:: future:: Future ;
10
14
#[ cfg( feature = "std" ) ]
11
15
use std:: time:: SystemTime ;
12
16
@@ -270,10 +274,7 @@ impl Builder {
270
274
Ok ( self )
271
275
}
272
276
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 > {
277
278
// Empty valid principals result in a "golden ticket", so this check
278
279
// ensures that was explicitly configured via `all_principals_valid`.
279
280
let valid_principals = match self . valid_principals {
@@ -294,9 +295,17 @@ impl Builder {
294
295
extensions : self . extensions ,
295
296
reserved : Vec :: new ( ) ,
296
297
comment : self . comment . unwrap_or_default ( ) ,
297
- signature_key : signing_key . public_key ( ) ,
298
+ signature_key : public_key,
298
299
signature : Signature :: placeholder ( ) ,
299
300
} ;
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 ( ) ) ?;
300
309
301
310
let mut tbs_cert = Vec :: new ( ) ;
302
311
cert. encode_tbs ( & mut tbs_cert) ?;
@@ -310,4 +319,36 @@ impl Builder {
310
319
311
320
Ok ( cert)
312
321
}
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
+ }
313
354
}
0 commit comments