1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use core::fmt::Debug;

use alloc::{string::String, vec::Vec};
use ciborium::Value;
use tinyvec::ArrayVec;

use crate::measurement::{Measurement, MEASUREMENTS_SLOT_NR, MEASUREMENTS_SLOT_RIM};

pub const CHALLENGE_LABEL: u64 = 10;
pub const PERSONALIZATION_VALUE_LABEL: u64 = 44235;
pub const INITIAL_MEASUREMENT_LABEL: u64 = 44238;
pub const EXTENSIBLE_MEASUREMENTS_LABEL: u64 = 44239;
pub const HASH_ALGO_ID_LABEL: u64 = 44236;
pub const PUBLIC_KEY_LABEL: u64 = 44237;
pub const PUBLIC_KEY_HASH_ALOG_ID_LABEL: u64 = 44240;

#[derive(Clone, Copy, Debug, Default)]
pub struct MeasurementEntry(Measurement, usize);

#[derive(Clone, Debug)]
pub struct Data<T: Default, const N: usize>(ArrayVec<[T; N]>);

impl<T: Copy + Default, const N: usize> Data<T, N> {
    pub fn from_slice(slice: &[T]) -> Self {
        Data(slice.iter().cloned().collect())
    }
}

pub const REM_SLOT_NR: usize = MEASUREMENTS_SLOT_NR - 1;

pub type Challenge = Data<u8, 64>;
pub type PersonalizationValue = Data<u8, 64>;
pub type REMs = Data<MeasurementEntry, REM_SLOT_NR>;
pub type RIM = MeasurementEntry;
pub type HashAlgo = String;
pub type RAKPubKey = Data<u8, 97>;

#[derive(Clone, Debug)]
pub struct Claim<T> {
    value: T,
    label: u64,
}

impl<T: Into<Value>> From<Claim<T>> for (Value, Value) {
    fn from(value: Claim<T>) -> Self {
        (Value::Integer(value.label.into()), value.value.into())
    }
}

impl From<MeasurementEntry> for Value {
    fn from(value: MeasurementEntry) -> Self {
        Value::Bytes(value.0.as_ref()[..value.1].to_vec())
    }
}

impl<const N: usize> From<Data<u8, N>> for Value {
    fn from(value: Data<u8, N>) -> Self {
        Value::Bytes(value.0.to_vec())
    }
}

impl<T: Into<Value>, const N: usize> From<Data<T, N>> for Value
where
    T: Default,
{
    default fn from(value: Data<T, N>) -> Self {
        let mut array = Vec::new();
        for el in value.0.into_iter() {
            array.push(el.into());
        }
        array.into()
    }
}

#[derive(Clone, Debug)]
pub struct RealmClaims {
    pub challenge: Claim<Challenge>,
    pub personalization_value: Claim<PersonalizationValue>,
    pub rim: Claim<RIM>,
    pub rems: Claim<REMs>,
    pub measurement_hash_algo: Claim<HashAlgo>,
    pub rak_pub: Claim<RAKPubKey>,
    pub rak_pub_hash_algo: Claim<HashAlgo>,
}

impl RealmClaims {
    pub fn init(
        challenge: &[u8],
        personalization_val: &[u8],
        measurements: &[Measurement],
        measurement_hash_algo: String,
        key_pub: &[u8],
        key_pub_hash_algo: String,
    ) -> RealmClaims {
        let challenge_claim: Claim<Challenge> = Claim {
            label: CHALLENGE_LABEL,
            value: Data::from_slice(challenge),
        };

        let personalization_value: Claim<PersonalizationValue> = Claim {
            label: PERSONALIZATION_VALUE_LABEL,
            value: Data::from_slice(personalization_val),
        };

        let measurement_size = match measurement_hash_algo.as_str() {
            "sha-256" => 32,
            "sha-512" => 64,
            _ => panic!("Unexpected hash algo id {}", measurement_hash_algo),
        };

        let rim: Claim<RIM> = Claim {
            label: INITIAL_MEASUREMENT_LABEL,
            value: MeasurementEntry(measurements[MEASUREMENTS_SLOT_RIM], measurement_size),
        };

        let mut rems_data = [MeasurementEntry::default(); REM_SLOT_NR];
        for i in 0..REM_SLOT_NR {
            rems_data[i] = MeasurementEntry(measurements[i + 1], measurement_size);
        }

        let rems: Claim<REMs> = Claim {
            label: EXTENSIBLE_MEASUREMENTS_LABEL,
            value: Data::from_slice(&rems_data),
        };

        let hash_algo_id: Claim<HashAlgo> = Claim {
            label: HASH_ALGO_ID_LABEL,
            value: measurement_hash_algo,
        };

        let rak_pub: Claim<RAKPubKey> = Claim {
            label: PUBLIC_KEY_LABEL,
            value: Data::from_slice(key_pub),
        };

        let rak_pub_hash_algo: Claim<HashAlgo> = Claim {
            label: PUBLIC_KEY_HASH_ALOG_ID_LABEL,
            value: key_pub_hash_algo,
        };

        Self {
            challenge: challenge_claim,
            personalization_value,
            rim,
            rems,
            measurement_hash_algo: hash_algo_id,
            rak_pub,
            rak_pub_hash_algo,
        }
    }
}