@@ -4,7 +4,6 @@ use std::sync::Arc;
44#[ cfg( feature = "time" ) ]
55use std:: time:: { Duration , SystemTime } ;
66
7- use base64:: prelude:: { BASE64_URL_SAFE_NO_PAD , Engine } ;
87use http:: header:: LOCATION ;
98#[ cfg( feature = "time" ) ]
109use http:: header:: USER_AGENT ;
@@ -22,17 +21,17 @@ use serde::{Deserialize, Serialize};
2221
2322#[ cfg( feature = "hyper-rustls" ) ]
2423use crate :: DefaultClient ;
24+ use crate :: crypto:: { CryptoProvider , key_thumbprint} ;
2525use crate :: order:: Order ;
2626use crate :: types:: {
27- AccountCredentials , AuthorizationStatus , Empty , Header , JoseJson , Jwk , KeyOrKeyId , NewAccount ,
27+ AccountCredentials , AuthorizationStatus , Empty , Header , JoseJson , KeyOrKeyId , NewAccount ,
2828 NewAccountPayload , NewOrder , OrderState , Problem , ProfileMeta , RevocationRequest , Signer ,
29- SigningAlgorithm ,
3029} ;
3130#[ cfg( feature = "time" ) ]
3231use crate :: types:: { CertificateIdentifier , RenewalInfo } ;
3332#[ cfg( feature = "time" ) ]
3433use crate :: { BodyWrapper , CRATE_USER_AGENT , retry_after} ;
35- use crate :: { BytesResponse , Client , Error , HttpClient , crypto , nonce_from_response} ;
34+ use crate :: { BytesResponse , Client , Error , HttpClient , nonce_from_response} ;
3635
3736/// An ACME account as described in RFC 8555 (section 7.1.2)
3837///
@@ -55,6 +54,7 @@ impl Account {
5554 pub fn builder ( ) -> Result < AccountBuilder , Error > {
5655 Ok ( AccountBuilder {
5756 http : Box :: new ( DefaultClient :: try_new ( ) ?) ,
57+ crypto : CryptoProvider :: builtin ( ) ,
5858 } )
5959 }
6060
@@ -73,14 +73,43 @@ impl Account {
7373 match roots. add ( root_der) {
7474 Ok ( ( ) ) => Ok ( AccountBuilder {
7575 http : Box :: new ( DefaultClient :: with_roots ( roots) ?) ,
76+ crypto : CryptoProvider :: builtin ( ) ,
7677 } ) ,
7778 Err ( err) => Err ( Error :: Other ( err. into ( ) ) ) ,
7879 }
7980 }
8081
8182 /// Create an account builder with the given HTTP client
83+ #[ cfg( any( feature = "ring" , feature = "aws-lc-rs" ) ) ]
8284 pub fn builder_with_http ( http : Box < dyn HttpClient > ) -> AccountBuilder {
83- AccountBuilder { http }
85+ AccountBuilder {
86+ http,
87+ crypto : CryptoProvider :: builtin ( ) ,
88+ }
89+ }
90+
91+ /// Create an account builder with the given [`CryptoProvider`] and default HTTP client
92+ ///
93+ /// Use this when you need a custom crypto backend but are fine with the default
94+ /// HTTP client. For a custom HTTP client too, use
95+ /// [`Account::builder_with_crypto_and_http()`] instead.
96+ #[ cfg( feature = "hyper-rustls" ) ]
97+ pub fn builder_with_crypto ( crypto : & ' static CryptoProvider ) -> Result < AccountBuilder , Error > {
98+ Ok ( AccountBuilder {
99+ http : Box :: new ( DefaultClient :: try_new ( ) ?) ,
100+ crypto,
101+ } )
102+ }
103+
104+ /// Create an account builder with the given [`CryptoProvider`] and HTTP client
105+ ///
106+ /// Use this when you need both a custom crypto backend and a custom HTTP client.
107+ /// For the default HTTP client, use [`Account::builder_with_crypto()`] instead.
108+ pub fn builder_with_crypto_and_http (
109+ crypto : & ' static CryptoProvider ,
110+ http : Box < dyn HttpClient > ,
111+ ) -> AccountBuilder {
112+ AccountBuilder { http, crypto }
84113 }
85114
86115 /// Create a new order based on the given [`NewOrder`]
@@ -227,15 +256,15 @@ impl Account {
227256 struct NewKey < ' a > {
228257 account : & ' a str ,
229258 #[ serde( rename = "oldKey" ) ]
230- old_key : Jwk ,
259+ old_key : & ' a serde_json :: Value ,
231260 }
232261
233- let ( new_key, new_key_pkcs8) = Key :: generate_pkcs8 ( ) ?;
262+ let ( new_key, new_key_pkcs8) = Key :: generate_pkcs8_with ( self . inner . key . provider ) ?;
234263 let mut header = new_key. header ( Some ( "nonce" ) , new_key_url) ;
235264 header. nonce = None ;
236265 let payload = NewKey {
237266 account : & self . inner . id ,
238- old_key : Jwk :: new ( & self . inner . key . inner ) ,
267+ old_key : & self . inner . key . jwk ,
239268 } ;
240269
241270 let body = JoseJson :: new ( Some ( & payload) , header, & new_key) ?;
@@ -353,10 +382,11 @@ impl AccountInner {
353382 async fn from_credentials (
354383 credentials : AccountCredentials ,
355384 http : Box < dyn HttpClient > ,
385+ crypto : & ' static CryptoProvider ,
356386 ) -> Result < Self , Error > {
357387 Ok ( Self {
358388 id : credentials. id ,
359- key : Key :: from_pkcs8_der ( credentials. key_pkcs8 ) ?,
389+ key : Key :: from_pkcs8_der_with ( credentials. key_pkcs8 , crypto ) ?,
360390 client : Arc :: new ( match ( credentials. directory , credentials. urls ) {
361391 ( Some ( directory_url) , _) => Client :: new ( directory_url, http) . await ?,
362392 ( None , Some ( directory) ) => Client {
@@ -390,20 +420,20 @@ impl AccountInner {
390420}
391421
392422impl Signer for AccountInner {
393- type Signature = < Key as Signer > :: Signature ;
423+ type Signature = Vec < u8 > ;
394424
395425 fn header < ' n , ' u : ' n , ' s : ' u > ( & ' s self , nonce : Option < & ' n str > , url : & ' u str ) -> Header < ' n > {
396426 debug_assert ! ( nonce. is_some( ) ) ;
397427 Header {
398- alg : self . key . signing_algorithm ,
428+ alg : & self . key . alg ,
399429 key : KeyOrKeyId :: KeyId ( & self . id ) ,
400430 nonce,
401431 url,
402432 }
403433 }
404434
405- fn sign ( & self , payload : & [ u8 ] ) -> Result < Self :: Signature , Error > {
406- self . key . sign ( payload)
435+ fn sign ( & self , payload : & [ u8 ] ) -> Result < Vec < u8 > , Error > {
436+ self . key . inner . sign ( payload)
407437 }
408438}
409439
@@ -412,16 +442,27 @@ impl Signer for AccountInner {
412442/// Create one via [`Account::builder()`] or [`Account::builder_with_http()`].
413443pub struct AccountBuilder {
414444 http : Box < dyn HttpClient > ,
445+ crypto : & ' static CryptoProvider ,
415446}
416447
417448impl AccountBuilder {
449+ /// Override the [`CryptoProvider`] for this builder
450+ ///
451+ /// By default, the builder uses [`CryptoProvider::builtin()`].
452+ pub fn crypto_provider ( mut self , provider : & ' static CryptoProvider ) -> Self {
453+ self . crypto = provider;
454+ self
455+ }
456+
418457 /// Restore an existing account from the given credentials
419458 ///
420459 /// The [`AccountCredentials`] type is opaque, but supports deserialization.
421460 #[ allow( clippy:: wrong_self_convention) ]
422461 pub async fn from_credentials ( self , credentials : AccountCredentials ) -> Result < Account , Error > {
423462 Ok ( Account {
424- inner : Arc :: new ( AccountInner :: from_credentials ( credentials, self . http ) . await ?) ,
463+ inner : Arc :: new (
464+ AccountInner :: from_credentials ( credentials, self . http , self . crypto ) . await ?,
465+ ) ,
425466 } )
426467 }
427468
@@ -435,7 +476,7 @@ impl AccountBuilder {
435476 directory_url : String ,
436477 external_account : Option < & ExternalAccountKey > ,
437478 ) -> Result < ( Account , AccountCredentials ) , Error > {
438- let ( key, key_pkcs8) = Key :: generate_pkcs8 ( ) ?;
479+ let ( key, key_pkcs8) = Key :: generate_pkcs8_with ( self . crypto ) ?;
439480 Self :: create_inner (
440481 account,
441482 ( key, key_pkcs8) ,
@@ -512,7 +553,7 @@ impl AccountBuilder {
512553 Ok ( Account {
513554 inner : Arc :: new ( AccountInner {
514555 id,
515- key : Key :: from_pkcs8_der ( key_pkcs8_der) ?,
556+ key : Key :: from_pkcs8_der_with ( key_pkcs8_der, self . crypto ) ?,
516557 client : Arc :: new ( Client :: new ( directory_url, self . http ) . await ?) ,
517558 } ) ,
518559 } )
@@ -529,7 +570,7 @@ impl AccountBuilder {
529570 external_account_binding : external_account
530571 . map ( |eak| {
531572 JoseJson :: new (
532- Some ( & Jwk :: new ( & key. inner ) ) ,
573+ Some ( & key. jwk ) ,
533574 eak. header ( None , & client. directory . new_account ) ,
534575 eak,
535576 )
@@ -577,68 +618,93 @@ impl AccountBuilder {
577618
578619/// Private account key used to sign requests
579620pub struct Key {
580- rng : crypto:: SystemRandom ,
581- signing_algorithm : SigningAlgorithm ,
582- inner : crypto:: EcdsaKeyPair ,
621+ inner : Arc < dyn crate :: crypto:: AccountKey > ,
622+ pub ( crate ) provider : & ' static CryptoProvider ,
623+ jwk : serde_json:: Value ,
624+ alg : String ,
583625 pub ( crate ) thumb : String ,
584626}
585627
586628impl Key {
587- /// Generate a new ECDSA P-256 key pair
629+ /// Generate a new key pair using the built-in [`CryptoProvider`]
630+ #[ cfg( any( feature = "ring" , feature = "aws-lc-rs" ) ) ]
588631 #[ deprecated( since = "0.8.3" , note = "use `generate_pkcs8()` instead" ) ]
589632 pub fn generate ( ) -> Result < ( Self , PrivateKeyDer < ' static > ) , Error > {
590633 let ( key, pkcs8) = Self :: generate_pkcs8 ( ) ?;
591634 Ok ( ( key, PrivateKeyDer :: Pkcs8 ( pkcs8) ) )
592635 }
593636
594- /// Generate a new ECDSA P-256 key pair
637+ /// Generate a new key pair using the built-in [`CryptoProvider`]
638+ #[ cfg( any( feature = "ring" , feature = "aws-lc-rs" ) ) ]
595639 pub fn generate_pkcs8 ( ) -> Result < ( Self , PrivatePkcs8KeyDer < ' static > ) , Error > {
596- let rng = crypto:: SystemRandom :: new ( ) ;
597- let pkcs8 =
598- crypto:: EcdsaKeyPair :: generate_pkcs8 ( & crypto:: ECDSA_P256_SHA256_FIXED_SIGNING , & rng)
599- . map_err ( |_| Error :: Crypto ) ?;
640+ Self :: generate_pkcs8_with ( CryptoProvider :: builtin ( ) )
641+ }
642+
643+ /// Generate a new key pair using the given [`CryptoProvider`]
644+ ///
645+ /// The key type depends on the provider. The built-in providers use ECDSA P-256.
646+ pub fn generate_pkcs8_with (
647+ provider : & ' static CryptoProvider ,
648+ ) -> Result < ( Self , PrivatePkcs8KeyDer < ' static > ) , Error > {
649+ let ( key, pkcs8) = provider. account_key . generate_key ( ) ?;
650+ let thumb = key_thumbprint ( key. as_ref ( ) , provider. sha256 ) ?;
651+ let jwk = key. to_jwk ( ) ?;
652+ let alg = key. jws_algorithm ( ) . to_owned ( ) ;
600653 Ok ( (
601- Self :: new ( pkcs8. as_ref ( ) , rng) ?,
602- PrivatePkcs8KeyDer :: from ( pkcs8. as_ref ( ) . to_vec ( ) ) ,
654+ Self {
655+ inner : key,
656+ provider,
657+ jwk,
658+ alg,
659+ thumb,
660+ } ,
661+ pkcs8,
603662 ) )
604663 }
605664
606- /// Create a new key from the given PKCS#8 DER-encoded private key
607- ///
608- /// Currently, only ECDSA P-256 keys are supported.
665+ /// Create a key from the given PKCS#8 DER-encoded private key using the built-in
666+ /// [`CryptoProvider`]
667+ # [ cfg ( any ( feature = "ring" , feature = "aws-lc-rs" ) ) ]
609668 pub fn from_pkcs8_der ( pkcs8_der : PrivatePkcs8KeyDer < ' _ > ) -> Result < Self , Error > {
610- Self :: new ( pkcs8_der. secret_pkcs8_der ( ) , crypto :: SystemRandom :: new ( ) )
669+ Self :: from_pkcs8_der_with ( pkcs8_der, CryptoProvider :: builtin ( ) )
611670 }
612671
613- fn new ( pkcs8_der : & [ u8 ] , rng : crypto:: SystemRandom ) -> Result < Self , Error > {
614- let inner = crypto:: p256_key_pair_from_pkcs8 ( pkcs8_der, & rng) ?;
615- let thumb = BASE64_URL_SAFE_NO_PAD . encode ( Jwk :: thumb_sha256 ( & inner) ?) ;
672+ /// Create a key from the given PKCS#8 DER-encoded private key using the given
673+ /// [`CryptoProvider`]
674+ pub fn from_pkcs8_der_with (
675+ pkcs8_der : PrivatePkcs8KeyDer < ' _ > ,
676+ provider : & ' static CryptoProvider ,
677+ ) -> Result < Self , Error > {
678+ let owned = PrivatePkcs8KeyDer :: from ( pkcs8_der. secret_pkcs8_der ( ) . to_vec ( ) ) ;
679+ let key = provider. account_key . load_key ( owned) ?;
680+ let thumb = key_thumbprint ( key. as_ref ( ) , provider. sha256 ) ?;
681+ let jwk = key. to_jwk ( ) ?;
682+ let alg = key. jws_algorithm ( ) . to_owned ( ) ;
616683 Ok ( Self {
617- rng,
618- signing_algorithm : SigningAlgorithm :: Es256 ,
619- inner,
684+ inner : key,
685+ provider,
686+ jwk,
687+ alg,
620688 thumb,
621689 } )
622690 }
623691}
624692
625693impl Signer for Key {
626- type Signature = crypto :: Signature ;
694+ type Signature = Vec < u8 > ;
627695
628696 fn header < ' n , ' u : ' n , ' s : ' u > ( & ' s self , nonce : Option < & ' n str > , url : & ' u str ) -> Header < ' n > {
629697 debug_assert ! ( nonce. is_some( ) ) ;
630698 Header {
631- alg : self . signing_algorithm ,
632- key : KeyOrKeyId :: from_key ( & self . inner ) ,
699+ alg : & self . alg ,
700+ key : KeyOrKeyId :: Key ( & self . jwk ) ,
633701 nonce,
634702 url,
635703 }
636704 }
637705
638- fn sign ( & self , payload : & [ u8 ] ) -> Result < Self :: Signature , Error > {
639- self . inner
640- . sign ( & self . rng , payload)
641- . map_err ( |_| Error :: Crypto )
706+ fn sign ( & self , payload : & [ u8 ] ) -> Result < Vec < u8 > , Error > {
707+ self . inner . sign ( payload)
642708 }
643709}
644710
@@ -647,36 +713,48 @@ impl Signer for Key {
647713/// See RFC 8555 section 7.3.4 for more information.
648714pub struct ExternalAccountKey {
649715 id : String ,
650- key : crypto:: hmac:: Key ,
716+ key_value : Vec < u8 > ,
717+ provider : & ' static CryptoProvider ,
651718}
652719
653720impl ExternalAccountKey {
654- /// Create a new external account key
721+ /// Create a new external account key using the built-in [`CryptoProvider`]
655722 ///
656723 /// Note that the `key_value` argument represents the raw key value, so if the caller holds
657724 /// an encoded key value (for example, using base64), decode it before passing it in.
725+ #[ cfg( any( feature = "ring" , feature = "aws-lc-rs" ) ) ]
658726 pub fn new ( id : String , key_value : & [ u8 ] ) -> Self {
727+ Self :: new_with ( id, key_value, CryptoProvider :: builtin ( ) )
728+ }
729+
730+ /// Create a new external account key using the given [`CryptoProvider`]
731+ ///
732+ /// Note that the `key_value` argument represents the raw key value, so if the caller holds
733+ /// an encoded key value (for example, using base64), decode it before passing it in.
734+ pub fn new_with ( id : String , key_value : & [ u8 ] , provider : & ' static CryptoProvider ) -> Self {
659735 Self {
660736 id,
661- key : crypto:: hmac:: Key :: new ( crypto:: hmac:: HMAC_SHA256 , key_value) ,
737+ key_value : key_value. to_vec ( ) ,
738+ provider,
662739 }
663740 }
664741}
665742
666743impl Signer for ExternalAccountKey {
667- type Signature = crypto :: hmac :: Tag ;
744+ type Signature = Vec < u8 > ;
668745
669746 fn header < ' n , ' u : ' n , ' s : ' u > ( & ' s self , nonce : Option < & ' n str > , url : & ' u str ) -> Header < ' n > {
670747 debug_assert_eq ! ( nonce, None ) ;
671748 Header {
672- alg : SigningAlgorithm :: Hs256 ,
749+ alg : "HS256" ,
673750 key : KeyOrKeyId :: KeyId ( & self . id ) ,
674751 nonce,
675752 url,
676753 }
677754 }
678755
679- fn sign ( & self , payload : & [ u8 ] ) -> Result < Self :: Signature , Error > {
680- Ok ( crypto:: hmac:: sign ( & self . key , payload) )
756+ fn sign ( & self , payload : & [ u8 ] ) -> Result < Vec < u8 > , Error > {
757+ let tag = self . provider . hmac_sha256 . sign ( & self . key_value , payload) ;
758+ Ok ( ( * tag) . as_ref ( ) . to_vec ( ) )
681759 }
682760}
0 commit comments