islet_rmm/rsi/attestation/
mod.rs1pub mod claims;
2
3use alloc::{boxed::Box, string::String, vec, vec::Vec};
4use ciborium::{ser, Value};
5use coset::{CoseSign1Builder, HeaderBuilder, TaggedCborSerializable};
6use ecdsa::signature::Signer;
7use tinyvec::ArrayVec;
8
9use crate::{
10 measurement::Measurement,
11 rmi::{HASH_ALGO_SHA256, HASH_ALGO_SHA512},
12};
13
14use self::claims::RealmClaims;
15use crate::rmm_el3::{plat_token, realm_attest_key};
16
17pub const MAX_CCA_TOKEN_SIZE: usize = 4096;
19pub const MAX_PLATFORM_TOKEN_SIZE: usize = 2048;
23pub const MAX_CHALLENGE_SIZE: usize = 64;
24
25const CCA_TOKEN_COLLECTION: u64 = 399;
26const CCA_PLATFORM_TOKEN: u64 = 44234;
27const CCA_REALM_DELEGATED_TOKEN: u64 = 44241;
28
29#[cfg(fuzzing)]
31const RAK_PRIV_KEY: [u8; 48] = [
32 60, 140, 180, 183, 23, 21, 46, 76, 243, 33, 155, 38, 242, 82, 86, 0, 57, 97, 140, 67, 71, 234,
33 13, 22, 87, 140, 136, 172, 120, 226, 162, 115, 202, 242, 116, 10, 141, 245, 16, 119, 255, 31,
34 1, 3, 10, 113, 218, 134,
35];
36
37type PlatformToken = ArrayVec<[u8; MAX_PLATFORM_TOKEN_SIZE]>;
38type RAKPriv = ArrayVec<[u8; 48]>;
40
41#[derive(Debug, Default)]
42pub struct Attestation {
43 platform_token: PlatformToken,
44 rak_priv: RAKPriv,
45}
46
47impl Attestation {
49 pub fn new(platform_token: &[u8], rak_priv: &[u8]) -> Self {
50 let mut at = Self::default();
51 at.set_platform_token(platform_token);
52 at.set_rak_priv(rak_priv);
53 at
54 }
55
56 fn set_platform_token(&mut self, token: &[u8]) {
57 self.platform_token = token.iter().cloned().collect();
58 }
59
60 fn set_rak_priv(&mut self, key_priv: &[u8]) {
61 self.rak_priv = key_priv.iter().cloned().collect();
62 }
63
64 pub fn create_attestation_token(
68 &self,
69 challenge: &[u8],
70 measurements: &[Measurement],
71 personalization_value: &[u8],
72 hash_algo: u8,
73 ) -> Vec<u8> {
74 let mut cca_token = Vec::new();
75
76 let realm_token =
77 self.create_realm_token(challenge, measurements, personalization_value, hash_algo);
78
79 let realm_token_entry = (
80 Value::Integer(CCA_REALM_DELEGATED_TOKEN.into()),
81 Value::Bytes(realm_token),
82 );
83
84 let platform_token_entry = (
85 Value::Integer(CCA_PLATFORM_TOKEN.into()),
86 Value::Bytes(self.platform_token.to_vec()),
87 );
88
89 let token_map: Vec<(Value, Value)> = vec![platform_token_entry, realm_token_entry];
90
91 ser::into_writer(
92 &Value::Tag(CCA_TOKEN_COLLECTION, Box::new(Value::Map(token_map))),
93 &mut cca_token,
94 )
95 .expect("Failed to serialize CCA token");
96
97 cca_token
98 }
99
100 fn create_realm_token(
101 &self,
102 challenge: &[u8],
103 measurements: &[Measurement],
104 personalization_value: &[u8],
105 hash_algo: u8,
106 ) -> Vec<u8> {
107 let hash_algo_id = match hash_algo {
108 HASH_ALGO_SHA256 => String::from("sha-256"),
109 HASH_ALGO_SHA512 => String::from("sha-512"),
110 _ => panic!("Unrecognized hash algorithm {}", hash_algo),
111 };
112
113 let secret_key =
114 p384::SecretKey::from_slice(&self.rak_priv).expect("Failed to import private RAK.");
115
116 let public_key = secret_key.public_key().to_sec1_bytes().to_vec();
117
118 let claims = RealmClaims::init(
119 challenge,
120 personalization_value,
121 measurements,
122 hash_algo_id,
123 &public_key,
124 String::from("sha-256"),
126 );
127
128 let claims_map: Vec<(Value, Value)> = vec![
129 claims.challenge.into(),
130 claims.profile.into(),
131 claims.personalization_value.into(),
132 claims.rim.into(),
133 claims.rems.into(),
134 claims.measurement_hash_algo.into(),
135 claims.rak_pub.into(),
136 claims.rak_pub_hash_algo.into(),
137 ];
138
139 let mut realm_token = Vec::new();
140 ser::into_writer(&Value::Map(claims_map), &mut realm_token)
141 .expect("Failed to serialize realm token");
142
143 let protected = HeaderBuilder::new()
144 .algorithm(coset::iana::Algorithm::ES384)
145 .build();
146
147 let sign1 = CoseSign1Builder::new()
148 .protected(protected)
149 .payload(realm_token)
150 .create_signature(b"", |payload| Self::sign(secret_key, payload))
151 .build();
152
153 sign1
154 .to_tagged_vec()
155 .expect("Failed to create tagged signed token")
156 }
157
158 fn sign(secret_key: p384::SecretKey, data: &[u8]) -> Vec<u8> {
159 let signing_key = p384::ecdsa::SigningKey::from_bytes(&secret_key.to_bytes())
160 .expect("Failed to generate signing key");
161
162 let signature: p384::ecdsa::Signature = signing_key
163 .try_sign(data)
164 .expect("Failed to create P384 signature");
165 signature.to_vec()
166 }
167}
168
169pub fn get_token(
170 challenge: &[u8],
171 measurements: &[Measurement],
172 personalization_value: &[u8],
173 hash_algo: u8,
174) -> Vec<u8> {
175 #[cfg(fuzzing)]
178 let realm_attest_key = &RAK_PRIV_KEY;
179 #[cfg(not(fuzzing))]
180 let realm_attest_key = &realm_attest_key();
181
182 Attestation::new(&plat_token(), realm_attest_key).create_attestation_token(
183 challenge,
184 measurements,
185 personalization_value,
186 hash_algo,
187 )
188}