use super::{
CONTENT_READER_DRAIN_ATTESTATION_ID_VERSION, CONTENT_READER_DRAIN_EVIDENCE_DOMAIN,
CONTENT_READER_DRAIN_EVIDENCE_SHA256_TAG, ContentAccessBarrierId, Digest, Error, Result,
Sha256, StorageDomainId, fmt, write_hex,
};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ContentReaderDrainAttestationId([u8; 16]);
impl ContentReaderDrainAttestationId {
pub fn generate() -> Result<Self> {
let mut bytes = [0_u8; 16];
getrandom::fill(&mut bytes).map_err(|error| {
Error::runtime_busy(format!("content reader-drain attestation entropy: {error}"))
})?;
bytes[0] = CONTENT_READER_DRAIN_ATTESTATION_ID_VERSION;
Ok(Self(bytes))
}
pub fn from_bytes(bytes: [u8; 16]) -> Result<Self> {
if bytes[0] != CONTENT_READER_DRAIN_ATTESTATION_ID_VERSION {
return Err(Error::UnsupportedFormat {
message: format!(
"unsupported content reader-drain attestation identity version {}",
bytes[0]
),
});
}
Ok(Self(bytes))
}
#[must_use]
pub const fn to_bytes(self) -> [u8; 16] {
self.0
}
}
impl fmt::Debug for ContentReaderDrainAttestationId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("ContentReaderDrainAttestationId(")?;
write_hex(formatter, &self.0)?;
formatter.write_str(")")
}
}
impl fmt::Display for ContentReaderDrainAttestationId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write_hex(formatter, &self.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ContentReaderDrainCoordinatorId([u8; 16]);
impl ContentReaderDrainCoordinatorId {
#[must_use]
pub const fn from_bytes(bytes: [u8; 16]) -> Self {
Self(bytes)
}
#[must_use]
pub const fn to_bytes(self) -> [u8; 16] {
self.0
}
}
impl fmt::Debug for ContentReaderDrainCoordinatorId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("ContentReaderDrainCoordinatorId(")?;
write_hex(formatter, &self.0)?;
formatter.write_str(")")
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ContentReaderDrainEvidenceDigest([u8; 33]);
impl ContentReaderDrainEvidenceDigest {
#[must_use]
pub fn for_bytes(evidence: &[u8]) -> Self {
let mut hasher = Sha256::new();
hasher.update(CONTENT_READER_DRAIN_EVIDENCE_DOMAIN);
hasher.update(evidence);
let mut bytes = [0_u8; 33];
bytes[0] = CONTENT_READER_DRAIN_EVIDENCE_SHA256_TAG;
bytes[1..].copy_from_slice(&hasher.finalize());
Self(bytes)
}
pub fn from_bytes(bytes: [u8; 33]) -> Result<Self> {
if bytes[0] != CONTENT_READER_DRAIN_EVIDENCE_SHA256_TAG {
return Err(Error::UnsupportedFormat {
message: format!(
"unsupported content reader-drain evidence digest algorithm {}",
bytes[0]
),
});
}
Ok(Self(bytes))
}
#[must_use]
pub const fn to_bytes(self) -> [u8; 33] {
self.0
}
}
impl fmt::Debug for ContentReaderDrainEvidenceDigest {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("ContentReaderDrainEvidenceDigest(")?;
write_hex(formatter, &self.0)?;
formatter.write_str(")")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ContentReaderDrainKind {
DomainBootstrap,
NativeProcessSetRestarted,
RemoteCredentialEpochRetired,
}
impl ContentReaderDrainKind {
pub(in crate::content::reclaim) const fn tag(self) -> u8 {
match self {
Self::DomainBootstrap => 0,
Self::NativeProcessSetRestarted => 1,
Self::RemoteCredentialEpochRetired => 2,
}
}
pub(in crate::content::reclaim) fn from_tag(tag: u8) -> Result<Self> {
match tag {
0 => Ok(Self::DomainBootstrap),
1 => Ok(Self::NativeProcessSetRestarted),
2 => Ok(Self::RemoteCredentialEpochRetired),
_ => Err(Error::UnsupportedFormat {
message: format!("unsupported content reader-drain kind {tag}"),
}),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContentReaderDrainAttestationOptions {
kind: ContentReaderDrainKind,
coordinator_id: ContentReaderDrainCoordinatorId,
evidence_digest: ContentReaderDrainEvidenceDigest,
}
impl ContentReaderDrainAttestationOptions {
#[must_use]
pub const fn new(
kind: ContentReaderDrainKind,
coordinator_id: ContentReaderDrainCoordinatorId,
evidence_digest: ContentReaderDrainEvidenceDigest,
) -> Self {
Self {
kind,
coordinator_id,
evidence_digest,
}
}
#[must_use]
pub const fn kind(self) -> ContentReaderDrainKind {
self.kind
}
#[must_use]
pub const fn coordinator_id(self) -> ContentReaderDrainCoordinatorId {
self.coordinator_id
}
#[must_use]
pub const fn evidence_digest(self) -> ContentReaderDrainEvidenceDigest {
self.evidence_digest
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContentReaderDrainAttestation {
pub(in crate::content::reclaim) storage_domain_id: StorageDomainId,
pub(in crate::content::reclaim) barrier_id: ContentAccessBarrierId,
pub(in crate::content::reclaim) attestation_id: ContentReaderDrainAttestationId,
pub(in crate::content::reclaim) options: ContentReaderDrainAttestationOptions,
pub(in crate::content::reclaim) barrier_enforced_at: crate::ReadVersion,
pub(in crate::content::reclaim) attested_at: crate::ReadVersion,
}
impl ContentReaderDrainAttestation {
#[must_use]
pub const fn storage_domain_id(self) -> StorageDomainId {
self.storage_domain_id
}
#[must_use]
pub const fn barrier_id(self) -> ContentAccessBarrierId {
self.barrier_id
}
#[must_use]
pub const fn attestation_id(self) -> ContentReaderDrainAttestationId {
self.attestation_id
}
#[must_use]
pub const fn options(self) -> ContentReaderDrainAttestationOptions {
self.options
}
#[must_use]
pub const fn barrier_enforced_at(self) -> crate::ReadVersion {
self.barrier_enforced_at
}
#[must_use]
pub const fn attested_at(self) -> crate::ReadVersion {
self.attested_at
}
}