Skip to main content

islet_rmm/rsi/attestation/
claims.rs

1use core::fmt::Debug;
2
3use alloc::{
4    string::{String, ToString},
5    vec::Vec,
6};
7use ciborium::Value;
8use tinyvec::ArrayVec;
9
10use crate::cose;
11use crate::measurement::{Measurement, MEASUREMENTS_SLOT_NR, MEASUREMENTS_SLOT_RIM};
12
13pub const CHALLENGE_LABEL: u64 = 10;
14pub const PROFILE_LABEL: u64 = 265;
15pub const PERSONALIZATION_VALUE_LABEL: u64 = 44235;
16pub const INITIAL_MEASUREMENT_LABEL: u64 = 44238;
17pub const EXTENSIBLE_MEASUREMENTS_LABEL: u64 = 44239;
18pub const HASH_ALGO_ID_LABEL: u64 = 44236;
19pub const PUBLIC_KEY_LABEL: u64 = 44237;
20pub const PUBLIC_KEY_HASH_ALOG_ID_LABEL: u64 = 44240;
21
22pub const REALM_PROFILE: &str = "tag:arm.com,2023:realm#1.0.0";
23
24#[derive(Clone, Copy, Debug, Default)]
25pub struct MeasurementEntry(Measurement, usize);
26
27#[derive(Clone, Debug)]
28pub struct Data<T: Default, const N: usize>(ArrayVec<[T; N]>);
29
30impl<T: Copy + Default, const N: usize> Data<T, N> {
31    pub fn from_slice(slice: &[T]) -> Self {
32        Data(slice.iter().cloned().collect())
33    }
34}
35
36pub const REM_SLOT_NR: usize = MEASUREMENTS_SLOT_NR - 1;
37
38pub type Challenge = Data<u8, 64>;
39pub type Profile = String;
40pub type PersonalizationValue = Data<u8, 64>;
41pub type REMs = Data<MeasurementEntry, REM_SLOT_NR>;
42pub type RIM = MeasurementEntry;
43pub type HashAlgo = String;
44pub type RAKPubKey = Vec<u8>;
45
46#[derive(Clone, Debug)]
47pub struct Claim<T> {
48    value: T,
49    label: u64,
50}
51
52impl<T: Into<Value>> From<Claim<T>> for (Value, Value) {
53    fn from(value: Claim<T>) -> Self {
54        (Value::Integer(value.label.into()), value.value.into())
55    }
56}
57
58impl From<MeasurementEntry> for Value {
59    fn from(value: MeasurementEntry) -> Self {
60        Value::Bytes(value.0.as_ref()[..value.1].to_vec())
61    }
62}
63
64impl<const N: usize> From<Data<u8, N>> for Value {
65    fn from(value: Data<u8, N>) -> Self {
66        Value::Bytes(value.0.to_vec())
67    }
68}
69
70impl<T: Into<Value>, const N: usize> From<Data<T, N>> for Value
71where
72    T: Default,
73{
74    default fn from(value: Data<T, N>) -> Self {
75        let mut array = Vec::new();
76        for el in value.0.into_iter() {
77            array.push(el.into());
78        }
79        array.into()
80    }
81}
82
83#[derive(Clone, Debug)]
84pub struct RealmClaims {
85    pub challenge: Claim<Challenge>,
86    pub profile: Claim<Profile>,
87    pub personalization_value: Claim<PersonalizationValue>,
88    pub rim: Claim<RIM>,
89    pub rems: Claim<REMs>,
90    pub measurement_hash_algo: Claim<HashAlgo>,
91    pub rak_pub: Claim<RAKPubKey>,
92    pub rak_pub_hash_algo: Claim<HashAlgo>,
93}
94
95impl RealmClaims {
96    pub fn init(
97        challenge: &[u8],
98        personalization_val: &[u8],
99        measurements: &[Measurement],
100        measurement_hash_algo: String,
101        key_pub: &[u8],
102        key_pub_hash_algo: String,
103    ) -> RealmClaims {
104        let challenge_claim: Claim<Challenge> = Claim {
105            label: CHALLENGE_LABEL,
106            value: Data::from_slice(challenge),
107        };
108
109        let profile: Claim<Profile> = Claim {
110            label: PROFILE_LABEL,
111            value: REALM_PROFILE.to_string(),
112        };
113
114        let personalization_value: Claim<PersonalizationValue> = Claim {
115            label: PERSONALIZATION_VALUE_LABEL,
116            value: Data::from_slice(personalization_val),
117        };
118
119        let measurement_size = match measurement_hash_algo.as_str() {
120            "sha-256" => 32,
121            "sha-512" => 64,
122            _ => panic!("Unexpected hash algo id {}", measurement_hash_algo),
123        };
124
125        let rim: Claim<RIM> = Claim {
126            label: INITIAL_MEASUREMENT_LABEL,
127            value: MeasurementEntry(measurements[MEASUREMENTS_SLOT_RIM], measurement_size),
128        };
129
130        let mut rems_data = [MeasurementEntry::default(); REM_SLOT_NR];
131        for i in 0..REM_SLOT_NR {
132            rems_data[i] = MeasurementEntry(measurements[i + 1], measurement_size);
133        }
134
135        let rems: Claim<REMs> = Claim {
136            label: EXTENSIBLE_MEASUREMENTS_LABEL,
137            value: Data::from_slice(&rems_data),
138        };
139
140        let hash_algo_id: Claim<HashAlgo> = Claim {
141            label: HASH_ALGO_ID_LABEL,
142            value: measurement_hash_algo,
143        };
144
145        let key_pub_cose = cose::ec_public_key_sec1_to_cose(key_pub);
146
147        let rak_pub: Claim<RAKPubKey> = Claim {
148            label: PUBLIC_KEY_LABEL,
149            value: key_pub_cose,
150        };
151
152        let rak_pub_hash_algo: Claim<HashAlgo> = Claim {
153            label: PUBLIC_KEY_HASH_ALOG_ID_LABEL,
154            value: key_pub_hash_algo,
155        };
156
157        Self {
158            challenge: challenge_claim,
159            profile,
160            personalization_value,
161            rim,
162            rems,
163            measurement_hash_algo: hash_algo_id,
164            rak_pub,
165            rak_pub_hash_algo,
166        }
167    }
168}