Skip to content

Commit 0acd83f

Browse files
introduce send_device_attestation() for device-attest-01
1 parent aee2e80 commit 0acd83f

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

src/order.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::borrow::Cow;
12
use std::ops::{ControlFlow, Deref};
23
use std::sync::Arc;
34
use std::time::{Duration, Instant, SystemTime};
@@ -12,7 +13,7 @@ use tokio::time::sleep;
1213
use crate::account::AccountInner;
1314
use crate::types::{
1415
Authorization, AuthorizationState, AuthorizationStatus, AuthorizedIdentifier, Challenge,
15-
ChallengeType, Empty, FinalizeRequest, OrderState, OrderStatus, Problem,
16+
ChallengeType, DeviceAttestation, Empty, FinalizeRequest, OrderState, OrderStatus, Problem,
1617
};
1718
use 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

src/types.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ pub enum ChallengeType {
704704
Dns01,
705705
#[serde(rename = "tls-alpn-01")]
706706
TlsAlpn01,
707+
#[serde(rename = "device-attest-01")]
708+
DeviceAttest01,
707709
#[serde(untagged)]
708710
Unknown(String),
709711
}
@@ -930,6 +932,14 @@ pub(crate) enum SigningAlgorithm {
930932
Hs256,
931933
}
932934

935+
/// Attestation payload used for device-attest-01
936+
#[derive(Serialize)]
937+
#[serde(rename_all = "camelCase")]
938+
pub struct DeviceAttestation<'a> {
939+
/// attestation payload
940+
pub att_obj: Cow<'a, [u8]>,
941+
}
942+
933943
#[derive(Debug, Serialize)]
934944
pub(crate) struct Empty {}
935945

0 commit comments

Comments
 (0)