@@ -12,6 +12,8 @@ use std::sync::atomic::{AtomicU16, Ordering};
1212use std:: time:: Duration ;
1313use std:: { env, fs} ;
1414
15+ use base64:: Engine ;
16+ use base64:: prelude:: BASE64_URL_SAFE_NO_PAD ;
1517use bytes:: { Buf , Bytes } ;
1618use http:: header:: CONTENT_TYPE ;
1719use http:: { Method , Request } ;
@@ -20,8 +22,8 @@ use hyper_util::client::legacy::Client as HyperClient;
2022use hyper_util:: client:: legacy:: connect:: HttpConnector ;
2123use hyper_util:: rt:: TokioExecutor ;
2224use instant_acme:: {
23- Account , AuthorizationStatus , Challenge , ChallengeType , Error , Identifier , KeyAuthorization ,
24- NewAccount , NewOrder , Order , OrderStatus ,
25+ Account , AuthorizationStatus , Challenge , ChallengeType , Error , ExternalAccountKey , Identifier ,
26+ KeyAuthorization , NewAccount , NewOrder , Order , OrderStatus ,
2527} ;
2628use rcgen:: { CertificateParams , DistinguishedName , KeyPair } ;
2729use rustls:: RootCertStore ;
@@ -111,6 +113,40 @@ async fn forbidden_identifier() -> Result<(), Box<dyn StdError>> {
111113 Ok ( ( ) )
112114}
113115
116+ /// Test that account registration works when external account binding is required
117+ #[ tokio:: test]
118+ #[ ignore]
119+ async fn eab_required ( ) -> Result < ( ) , Box < dyn StdError > > {
120+ try_tracing_init ( ) ;
121+
122+ // Creating an environment with external account binding required, but not providing
123+ // an external account key should provoke an error.
124+ let mut config = EnvironmentConfig :: default ( ) ;
125+ config. pebble . external_account_binding_required = true ;
126+ let err = Environment :: new ( config) . await . map ( |_| ( ) ) . unwrap_err ( ) ;
127+ let Error :: Api ( problem) = * err. downcast :: < Error > ( ) ? else {
128+ panic ! ( "unexpected error result" ) ;
129+ } ;
130+ assert_eq ! (
131+ problem. r#type. as_deref( ) ,
132+ Some ( "urn:ietf:params:acme:error:externalAccountRequired" )
133+ ) ;
134+
135+ // Setting a valid external account key should allow account creation to succeed.
136+ let eab_id = "test-account" ;
137+ let eab_hmac_key = "zWNDZM6eQGHWpSRTPal5eIUYFTu7EajVIoguysqZ9wG44nMEtx3MUAsUDkMTQ12W" ;
138+ let raw_eab_hmac_key = BASE64_URL_SAFE_NO_PAD . decode ( eab_hmac_key) . unwrap ( ) ;
139+ let mac_keys = [ ( eab_id, eab_hmac_key) ] . into ( ) ;
140+ let mut config = EnvironmentConfig :: default ( ) ;
141+ config. pebble . external_account_binding_required = true ;
142+ config. pebble . external_account_mac_keys = mac_keys;
143+ config. eab_key = Some ( ExternalAccountKey :: new (
144+ eab_id. to_string ( ) ,
145+ raw_eab_hmac_key. as_ref ( ) ,
146+ ) ) ;
147+ Environment :: new ( config) . await . map ( |_| ( ) )
148+ }
149+
114150fn try_tracing_init ( ) {
115151 let _ = tracing_subscriber:: registry ( )
116152 . with ( fmt:: layer ( ) )
@@ -214,7 +250,7 @@ impl Environment {
214250 only_return_existing : false ,
215251 } ,
216252 & format ! ( "https://{}/dir" , & config. pebble. listen_address) ,
217- None ,
253+ config . eab_key . as_ref ( ) ,
218254 Box :: new ( client. clone ( ) ) ,
219255 )
220256 . await ?;
@@ -517,6 +553,7 @@ struct EnvironmentConfig {
517553 pebble : PebbleConfig ,
518554 dns_port : u16 ,
519555 challtestsrv_port : u16 ,
556+ eab_key : Option < ExternalAccountKey > ,
520557}
521558
522559impl Default for EnvironmentConfig {
@@ -525,6 +562,7 @@ impl Default for EnvironmentConfig {
525562 pebble : PebbleConfig :: default ( ) ,
526563 dns_port : NEXT_PORT . fetch_add ( 1 , Ordering :: SeqCst ) ,
527564 challtestsrv_port : NEXT_PORT . fetch_add ( 1 , Ordering :: SeqCst ) ,
565+ eab_key : None ,
528566 }
529567 }
530568}
0 commit comments