Skip to content

Commit c116425

Browse files
christianhoelzldjc
authored andcommitted
introduce send_device_attestation() for device-attest-01
1 parent 6c6de6b commit c116425

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

src/order.rs

Lines changed: 36 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,40 @@ impl ChallengeHandle<'_> {
453454
}
454455
}
455456

457+
/// Notify the server that the challenge is ready by sending a device attestation
458+
///
459+
/// This function is for the ACME challenge device-attest-01. It should not be used
460+
/// with other challenge types.
461+
/// See <https://datatracker.ietf.org/doc/draft-acme-device-attest/> for details.
462+
///
463+
/// `payload` is the device attestation object as defined in link. Provide the attestation
464+
/// object as a raw blob. Base64 encoding of the attestation object `payload.att_obj`
465+
/// is done by this function.
466+
pub async fn send_device_attestation(
467+
&mut self,
468+
payload: &DeviceAttestation<'_>,
469+
) -> Result<(), Error> {
470+
if self.challenge.r#type != ChallengeType::DeviceAttest01 {
471+
return Err(Error::Str("challenge type should be device-attest-01"));
472+
}
473+
474+
let payload = DeviceAttestation {
475+
att_obj: Cow::Owned(BASE64_URL_SAFE_NO_PAD.encode(&payload.att_obj).into()),
476+
};
477+
478+
let rsp = self
479+
.account
480+
.post(Some(&payload), self.nonce.take(), &self.challenge.url)
481+
.await?;
482+
483+
*self.nonce = nonce_from_response(&rsp);
484+
let response = Problem::check::<Challenge>(rsp).await?;
485+
match response.error {
486+
Some(details) => Err(Error::Api(details)),
487+
None => Ok(()),
488+
}
489+
}
490+
456491
/// Create a [`KeyAuthorization`] for this challenge
457492
///
458493
/// Combines a challenge's token with the thumbprint of the account's public key to compute

src/types.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,14 +648,24 @@ pub enum AuthorizationStatus {
648648
#[allow(missing_docs)]
649649
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
650650
#[non_exhaustive]
651-
#[serde(tag = "type", content = "value", rename_all = "camelCase")]
651+
#[serde(tag = "type", content = "value", rename_all = "kebab-case")]
652652
pub enum Identifier {
653653
Dns(String),
654654

655655
/// An IP address (IPv4 or IPv6) identifier
656656
///
657657
/// Note that not all ACME servers will accept an order with an IP address identifier.
658658
Ip(IpAddr),
659+
660+
/// Permanent Identifier
661+
///
662+
/// Note that this identifier is only used for attestation.
663+
PermanentIdentifier(String),
664+
665+
/// Hardware Module identifier
666+
///
667+
/// Note that this identifier is only used for attestation.
668+
HardwareModule(String),
659669
}
660670

661671
impl Identifier {
@@ -690,6 +700,10 @@ impl fmt::Display for AuthorizedIdentifier<'_> {
690700
(true, Identifier::Dns(dns)) => f.write_fmt(format_args!("*.{dns}")),
691701
(false, Identifier::Dns(dns)) => f.write_str(dns),
692702
(_, Identifier::Ip(addr)) => write!(f, "{addr}"),
703+
(_, Identifier::PermanentIdentifier(permanent_identifier)) => {
704+
f.write_str(permanent_identifier)
705+
}
706+
(_, Identifier::HardwareModule(hardware_module)) => f.write_str(hardware_module),
693707
}
694708
}
695709
}
@@ -704,6 +718,8 @@ pub enum ChallengeType {
704718
Dns01,
705719
#[serde(rename = "tls-alpn-01")]
706720
TlsAlpn01,
721+
#[serde(rename = "device-attest-01")]
722+
DeviceAttest01,
707723
#[serde(untagged)]
708724
Unknown(String),
709725
}
@@ -930,6 +946,16 @@ pub(crate) enum SigningAlgorithm {
930946
Hs256,
931947
}
932948

949+
/// Attestation payload used for device-attest-01
950+
///
951+
/// See <https://datatracker.ietf.org/doc/draft-acme-device-attest/> for details.
952+
#[derive(Serialize)]
953+
#[serde(rename_all = "camelCase")]
954+
pub struct DeviceAttestation<'a> {
955+
/// attestation payload
956+
pub att_obj: Cow<'a, [u8]>,
957+
}
958+
933959
#[derive(Debug, Serialize)]
934960
pub(crate) struct Empty {}
935961

0 commit comments

Comments
 (0)