1use crate::{
4 binary_format::{self, device::PRD_SCALAR_SIZE},
5 certificate::CertificateChain,
6 crypto::ecc_p256::{FromBytes, Keypair, ToUntaggedBytes, SCALAR_SIZE},
7};
8use binrw::{BinRead, BinWrite};
9use p256::ecdsa::SigningKey;
10use p256::elliptic_curve::PrimeField;
11use rand::{thread_rng, Rng};
12use std::{
13 fs::File,
14 io::{Cursor, Read},
15 path::Path,
16};
17
18#[derive(Debug, Clone)]
20pub struct Device {
21 group_key: Option<SigningKey>,
22 encryption_key: Keypair,
23 signing_key: SigningKey,
24 cert_chain: CertificateChain,
25}
26
27impl Device {
28 pub fn new(
30 group_key: Option<SigningKey>,
31 encryption_key: Keypair,
32 signing_key: SigningKey,
33 cert_chain: CertificateChain,
34 ) -> Self {
35 Self {
36 group_key,
37 encryption_key,
38 signing_key,
39 cert_chain,
40 }
41 }
42
43 pub fn from_slices(
45 group_key: Option<&[u8]>,
46 encryption_key: &[u8],
47 signing_key: &[u8],
48 cert_chain: &[u8],
49 ) -> Result<Self, crate::Error> {
50 let group_key = match group_key {
51 Some(group_key) => Some(SigningKey::from_slice(group_key)?),
52 None => None,
53 };
54
55 let encryption_key = Keypair::from_bytes(encryption_key)?;
56 let signing_key = SigningKey::from_slice(signing_key)?;
57 let cert_chain = CertificateChain::from_bytes(cert_chain)?;
58
59 Ok(Self {
60 group_key,
61 encryption_key,
62 signing_key,
63 cert_chain,
64 })
65 }
66
67 pub fn from_bytes(bytes: &[u8]) -> Result<Self, crate::Error> {
69 let device = binary_format::device::Device::read(&mut Cursor::new(bytes))?;
70
71 let group_key = match &device.inner {
72 binary_format::device::DeviceInner::V2(_) => None,
73 binary_format::device::DeviceInner::V3(v3) => Some(&v3.group_key),
74 };
75
76 let group_key = match group_key {
77 Some(group_key) => Some(SigningKey::from_slice(&group_key[..SCALAR_SIZE])?),
78 None => None,
79 };
80
81 let encryption_key = match &device.inner {
82 binary_format::device::DeviceInner::V2(v2) => &v2.encryption_key,
83 binary_format::device::DeviceInner::V3(v3) => &v3.encryption_key,
84 };
85
86 let signing_key = match &device.inner {
87 binary_format::device::DeviceInner::V2(v2) => &v2.signing_key,
88 binary_format::device::DeviceInner::V3(v3) => &v3.signing_key,
89 };
90
91 let encryption_key = Keypair::from_bytes(&encryption_key[..SCALAR_SIZE])?;
92 let signing_key = SigningKey::from_slice(&signing_key[..SCALAR_SIZE])?;
93
94 let group_certificate = match device.inner {
95 binary_format::device::DeviceInner::V2(v2) => v2.group_certificate,
96 binary_format::device::DeviceInner::V3(v3) => v3.group_certificate,
97 };
98
99 let cert_chain = CertificateChain::from_vec(group_certificate)?;
100
101 Ok(Self {
102 group_key,
103 encryption_key,
104 signing_key,
105 cert_chain,
106 })
107 }
108
109 pub fn from_prd(path: impl AsRef<Path>) -> Result<Self, crate::Error> {
115 let mut file = File::open(path)?;
116 let mut bytes = Vec::<u8>::new();
117 file.read_to_end(&mut bytes)?;
118
119 Self::from_bytes(&bytes)
120 }
121
122 pub fn signing_key(&self) -> &SigningKey {
124 &self.signing_key
125 }
126
127 pub fn encryption_key(&self) -> &Keypair {
129 &self.encryption_key
130 }
131
132 pub fn group_certificate(&self) -> &[u8] {
134 self.cert_chain.raw()
135 }
136
137 pub fn group_key(&self) -> Option<&SigningKey> {
139 self.group_key.as_ref()
140 }
141
142 pub fn name(&self) -> Result<String, crate::Error> {
144 self.cert_chain.name()
145 }
146
147 pub fn security_level(&self) -> Result<u32, crate::Error> {
149 self.cert_chain.security_level()
150 }
151
152 pub fn verify(&self) -> Result<(), crate::Error> {
154 let public_signing_key = self
155 .signing_key
156 .verifying_key()
157 .as_affine()
158 .to_untagged_bytes();
159
160 let public_encryption_key = self
161 .encryption_key
162 .public()
163 .as_element()
164 .to_untagged_bytes();
165
166 if *public_signing_key != *self.cert_chain.public_signing_key()? {
167 return Err(crate::Error::PublicKeyMismatchError("signing key"));
168 }
169
170 if *public_encryption_key != *self.cert_chain.public_encryption_key()? {
171 return Err(crate::Error::PublicKeyMismatchError("encryption key"));
172 }
173
174 if let Some(group_key) = self.group_key() {
175 let group_key = group_key.verifying_key().as_affine().to_untagged_bytes();
176
177 if *group_key != *self.cert_chain.public_group_key()? {
178 return Err(crate::Error::PublicKeyMismatchError("group key"));
179 }
180 }
181
182 self.cert_chain.verify_signatures()
183 }
184
185 pub fn provision(
187 cert_chain: CertificateChain,
188 group_key: SigningKey,
189 ) -> Result<Self, crate::Error> {
190 let mut rng = thread_rng();
191
192 let client_id = rng.gen::<[u8; 16]>();
193 let cert_id = rng.gen::<[u8; 16]>();
194
195 let encryption_key = Keypair::generate(&mut rng);
196 let signing_key = SigningKey::random(&mut rng);
197
198 let public_encryption_key = encryption_key
199 .public()
200 .as_element()
201 .to_untagged_bytes()
202 .to_vec();
203
204 let public_signing_key = signing_key
205 .verifying_key()
206 .as_affine()
207 .to_untagged_bytes()
208 .to_vec();
209
210 let cert_chain = cert_chain.provision(
211 cert_id,
212 client_id,
213 public_signing_key,
214 public_encryption_key,
215 &group_key,
216 )?;
217
218 cert_chain.verify_signatures()?;
219
220 Ok(Self {
221 group_key: Some(group_key),
222 encryption_key,
223 signing_key,
224 cert_chain,
225 })
226 }
227
228 pub fn reprovision(self) -> Result<Self, crate::Error> {
230 let Device {
231 cert_chain,
232 group_key,
233 ..
234 } = self;
235
236 let group_key = group_key.ok_or(crate::Error::GroupKeyMissingError)?;
237
238 Self::provision(cert_chain, group_key)
239 }
240
241 pub fn provision_from_files(
244 group_cert_path: impl AsRef<Path>,
245 group_key_path: impl AsRef<Path>,
246 ) -> Result<Self, crate::Error> {
247 let mut file = File::open(group_cert_path)?;
248 let mut bytes = Vec::<u8>::new();
249 file.read_to_end(&mut bytes)?;
250
251 let cert_chain = CertificateChain::from_bytes(&bytes)?;
252
253 file = File::open(group_key_path)?;
254 bytes.clear();
255 file.read_to_end(&mut bytes)?;
256
257 let group_key = SigningKey::from_slice(bytes.get(..SCALAR_SIZE).ok_or(
258 crate::Error::SliceOutOfBoundsError("group_key", bytes.len()),
259 )?)?;
260
261 Self::provision(cert_chain, group_key)
262 }
263
264 pub fn write_to_file(&self, path: impl AsRef<Path>) -> Result<(), crate::Error> {
266 let mut encryption_key = [0u8; PRD_SCALAR_SIZE];
267 let mut signing_key = [0u8; PRD_SCALAR_SIZE];
268
269 encryption_key[..SCALAR_SIZE]
270 .copy_from_slice(&self.encryption_key.secret().expose_scalar().to_repr());
271 signing_key[..SCALAR_SIZE].copy_from_slice(&self.signing_key.to_bytes());
272
273 let group_certificate = self.group_certificate().to_vec();
274 let group_certificate_length = u32::try_from(group_certificate.len()).unwrap();
275
276 let device = if let Some(ref key) = self.group_key {
277 let mut group_key = [0u8; PRD_SCALAR_SIZE];
278 group_key[..SCALAR_SIZE].copy_from_slice(&key.to_bytes());
279
280 binary_format::device::Device {
281 version: 3,
282 inner: binary_format::device::DeviceInner::V3(binary_format::device::DeviceV3 {
283 group_key,
284 encryption_key,
285 signing_key,
286 group_certificate_length,
287 group_certificate,
288 }),
289 }
290 } else {
291 binary_format::device::Device {
292 version: 2,
293 inner: binary_format::device::DeviceInner::V2(binary_format::device::DeviceV2 {
294 encryption_key,
295 signing_key,
296 group_certificate_length,
297 group_certificate,
298 }),
299 }
300 };
301
302 let mut file = File::create(path)?;
303 device.write(&mut file)?;
304
305 Ok(())
306 }
307}
308
309impl TryFrom<&[u8]> for Device {
310 type Error = crate::Error;
311
312 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
313 Self::from_bytes(value)
314 }
315}