1+ use std:: borrow:: Cow ;
12use std:: ops:: { ControlFlow , Deref } ;
23use std:: sync:: Arc ;
34use std:: time:: { Duration , Instant , SystemTime } ;
@@ -12,7 +13,7 @@ use tokio::time::sleep;
1213use crate :: account:: AccountInner ;
1314use crate :: types:: {
1415 Authorization , AuthorizationState , AuthorizationStatus , AuthorizedIdentifier , Challenge ,
15- ChallengeType , Empty , FinalizeRequest , OrderState , OrderStatus , Problem ,
16+ ChallengeType , DeviceAttestation , Empty , FinalizeRequest , OrderState , OrderStatus , Problem ,
1617} ;
1718use crate :: { Error , Key , crypto, nonce_from_response, retry_after} ;
1819
@@ -453,6 +454,42 @@ impl ChallengeHandle<'_> {
453454 }
454455 }
455456
457+ /// Notify the server that the challenge is ready and send device attestation
458+ ///
459+ /// This function is for the ACME challenge device-attest-01.
460+ /// See <https://datatracker.ietf.org/doc/draft-acme-device-attest/> for details.
461+ ///
462+ /// Note: Do not use this function for http-01, tls-alpn-01 or dns-01 challenges.
463+ ///
464+ /// `payload` is the device attestation object as defined in link. Provide the attestation
465+ /// object as a raw blob. Base64 encoding of the attestation object `payload.att_obj`
466+ /// is done by this function.
467+ pub async fn send_device_attestation (
468+ & mut self ,
469+ payload : & DeviceAttestation < ' _ > ,
470+ ) -> Result < ( ) , Error > {
471+ if self . challenge . r#type != ChallengeType :: DeviceAttest01 {
472+ return Err ( Error :: Str ( "challenge type should be device-attest-01" ) ) ;
473+ }
474+
475+ // The DeviceAttestation struct can be used for base64 encoding.
476+ let payload = DeviceAttestation {
477+ att_obj : Cow :: Owned ( BASE64_URL_SAFE_NO_PAD . encode ( & payload. att_obj ) . into ( ) ) ,
478+ } ;
479+
480+ let rsp = self
481+ . account
482+ . post ( Some ( & payload) , self . nonce . take ( ) , & self . challenge . url )
483+ . await ?;
484+
485+ * self . nonce = nonce_from_response ( & rsp) ;
486+ let response = Problem :: check :: < Challenge > ( rsp) . await ?;
487+ match response. error {
488+ Some ( details) => Err ( Error :: Api ( details) ) ,
489+ None => Ok ( ( ) ) ,
490+ }
491+ }
492+
456493 /// Create a [`KeyAuthorization`] for this challenge
457494 ///
458495 /// Combines a challenge's token with the thumbprint of the account's public key to compute
0 commit comments