• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! # Interface library for communicating with the hwkey service.
18 
19 #![no_std]
20 #![feature(allocator_api)]
21 
22 #[allow(non_upper_case_globals)]
23 #[allow(non_camel_case_types)]
24 #[allow(unused)]
25 #[allow(deref_nullptr)] // https://github.com/rust-lang/rust-bindgen/issues/1651
26 mod sys {
27     include!(env!("BINDGEN_INC_FILE"));
28 }
29 
30 mod err;
31 #[cfg(test)]
32 mod test;
33 
34 use core::ffi::CStr;
35 use core::mem;
36 pub use err::HwkeyError;
37 use sys::*;
38 use tipc::{Deserialize, Handle, Serialize, Serializer, TipcError};
39 use trusty_std::alloc::{TryAllocFrom, Vec};
40 
41 /// A HwkeySession is a Handle.
42 type HwkeySession = Handle;
43 
44 /// Connection to the hwkey service.
45 #[derive(Debug, Eq, PartialEq)]
46 pub struct Hwkey(HwkeySession);
47 
48 impl Hwkey {
49     /// Attempt to open a hwkey session.
50     ///
51     /// # Examples
52     ///
53     /// ```
54     /// let hwkey_session = Hwkey::open().expect("could not open hwkey session");
55     /// ```
56     ///
open() -> Result<Self, TipcError>57     pub fn open() -> Result<Self, TipcError> {
58         let port =
59             CStr::from_bytes_with_nul(HWKEY_PORT).expect("HWKEY_PORT was not null terminated");
60         HwkeySession::connect(port).map(Self)
61     }
62 
validate_cmd(sent_cmd: &u32, recvd_cmd: &u32) -> bool63     fn validate_cmd(sent_cmd: &u32, recvd_cmd: &u32) -> bool {
64         *recvd_cmd == (sent_cmd | hwkey_cmd_HWKEY_RESP_BIT as u32)
65     }
66 
67     /// Starts a request to derive a key from a context.
68     ///
69     /// # Returns
70     ///
71     /// A [`DerivedKeyRequest`] request builder
72     /// functionality.
73     ///
74     /// # Examples
75     ///
76     /// ```
77     /// let hwkey_session = Hwkey::open().expect("could not open hwkey session");
78     /// let request_builder = hwkey_session.derive_key_req();
79     /// ```
80     ///
derive_key_req(&self) -> DerivedKeyRequest81     pub fn derive_key_req(&self) -> DerivedKeyRequest {
82         DerivedKeyRequest::new(&self)
83     }
84 
85     /// Gets the keyslot data referenced by slot_id.
86     ///
87     /// # Arguments
88     ///
89     /// * `slot_id` - The name of the keyslot, must be null-terminated.
90     /// * `keyslot_data` - The buffer into which the keyslot data will be populated.
91     ///
92     /// # Returns
93     ///
94     /// A truncated prefix of the input keyslot_data buffer that contains
95     /// the key bytes.
96     ///
97     /// # Examples
98     ///
99     /// ```
100     /// let hwkey_session = Hwkey::open().expect("could not open hwkey session");
101     /// let buf = &mut [0u8; 2048 as usize];
102     /// let keyslot = CStr::from_bytes_with_nul(b"keyslot_name\0").unwrap();
103     /// let keyslot_data =
104     ///     hwkey_session.get_keyslot_data(keyslot, buf).expect("could not retrieve keyslot data");
105     /// ```
106     ///
get_keyslot_data<'a>( &self, slot_id: &CStr, keyslot_data: &'a mut [u8], ) -> Result<&'a [u8], HwkeyError>107     pub fn get_keyslot_data<'a>(
108         &self,
109         slot_id: &CStr,
110         keyslot_data: &'a mut [u8],
111     ) -> Result<&'a [u8], HwkeyError> {
112         let slot_id = slot_id.to_bytes();
113 
114         // slot_id is at least one byte because of null byte;
115         // check for empty slot_id string or empty keyslot_data
116         if slot_id.len() <= 0 {
117             log::error!("slot_id cannot be an empty string");
118             return Err(HwkeyError::NotValid);
119         }
120 
121         if keyslot_data.is_empty() {
122             log::error!("keyslot_data cannot be empty");
123             return Err(HwkeyError::NotValid);
124         }
125 
126         let cmd = hwkey_cmd_HWKEY_GET_KEYSLOT as u32;
127 
128         let req_msg = hwkey_msg {
129             header: hwkey_msg_header { cmd, op_id: 0u32, status: 0 },
130             arg1: 0u32,
131             arg2: 0u32,
132             payload: __IncompleteArrayField::new(),
133         };
134 
135         self.0.send(&HwkeyMsg { msg: req_msg, request: slot_id })?;
136         let buf = &mut [0; HWKEY_MAX_MSG_SIZE as usize];
137         let response: HwkeyResponse = self.0.recv(buf)?;
138 
139         if !Self::validate_cmd(&cmd, &response.cmd) {
140             log::error!("unknown response cmd: {:?}", response.cmd);
141             return Err(HwkeyError::InvalidCmdResponse);
142         }
143 
144         HwkeyError::from_hwkey_rc(response.status)?;
145 
146         if keyslot_data.len() < response.payload.len() {
147             log::error!(
148                 "keyslot data len ({:?}) < response payload len ({:?})",
149                 keyslot_data.len(),
150                 response.payload.len()
151             );
152             return Err(HwkeyError::BadLen);
153         }
154 
155         keyslot_data[..response.payload.len()].copy_from_slice(&response.payload[..]);
156         Ok(&keyslot_data[..response.payload.len()])
157     }
158 
159     /// Derive a versioned, device-specific key from provided context.
160     ///
161     /// # Arguments
162     ///
163     /// * `src` - The context from which the key will be derived. If
164     /// empty, `key_buf` must be empty as well.
165     /// * `key_buf` - The buffer into which the key will be written. If
166     /// empty, no key will be generated and only the current versions
167     /// may be queried.
168     /// * `args` - Key derivation options.
169     ///
170     /// # Returns
171     ///
172     /// The DeriveResult containing information used in derivation.
173     ///
derive( &self, src: &[u8], key_buf: &mut [u8], args: DerivedKeyRequest, ) -> Result<DeriveResult, HwkeyError>174     fn derive(
175         &self,
176         src: &[u8],
177         key_buf: &mut [u8],
178         args: DerivedKeyRequest,
179     ) -> Result<DeriveResult, HwkeyError> {
180         if src.len() == 0 && key_buf.len() != 0 {
181             log::error!("if key context is empty, key buffer must also be empty");
182             return Err(HwkeyError::NotValid);
183         }
184 
185         const HEADER_SIZE: usize = mem::size_of::<hwkey_derive_versioned_msg>();
186         const MAX_PAYLOAD_LEN: usize = HWKEY_MAX_MSG_SIZE as usize - HEADER_SIZE;
187 
188         if src.len() > MAX_PAYLOAD_LEN {
189             log::error!("src context length ({:?}) > ({:?})", src.len(), MAX_PAYLOAD_LEN);
190             return Err(HwkeyError::BadLen);
191         }
192 
193         if key_buf.len() > MAX_PAYLOAD_LEN {
194             log::error!("key buffer length ({:?}) > ({:?})", key_buf.len(), MAX_PAYLOAD_LEN);
195             return Err(HwkeyError::BadLen);
196         }
197 
198         let key_options = if args.shared_key {
199             hwkey_derived_key_options_HWKEY_SHARED_KEY_TYPE
200         } else {
201             hwkey_derived_key_options_HWKEY_DEVICE_UNIQUE_KEY_TYPE
202         };
203 
204         let os_rollback_version: i32 = args.os_rollback_version.try_into()?;
205         let mut rollback_versions =
206             [0; hwkey_rollback_version_indices_HWKEY_ROLLBACK_VERSION_INDEX_COUNT as usize];
207         rollback_versions
208             [hwkey_rollback_version_indices_HWKEY_ROLLBACK_VERSION_OS_INDEX as usize] =
209             os_rollback_version;
210 
211         let cmd = hwkey_cmd_HWKEY_DERIVE_VERSIONED as u32;
212 
213         let req_msg = hwkey_derive_versioned_msg {
214             header: hwkey_msg_header { cmd, op_id: 0u32, status: 0u32 },
215             kdf_version: args.kdf_version.into(),
216             rollback_version_source: args.rollback_version_source.into(),
217             rollback_versions,
218             key_options: key_options as u32,
219             key_len: key_buf.len() as u32,
220         };
221 
222         let msg = HwkeyDeriveVersionedMsg { msg: req_msg, context: src };
223 
224         self.0.send(&msg)?;
225 
226         let buf = &mut [0; HWKEY_MAX_MSG_SIZE as usize];
227         let response: HwkeyDeriveVersionedResponse = self.0.recv(buf)?;
228 
229         if !Hwkey::validate_cmd(&cmd, &response.cmd) {
230             log::error!("unknown response cmd: {:?}", response.cmd);
231             return Err(HwkeyError::InvalidCmdResponse);
232         }
233 
234         HwkeyError::from_hwkey_rc(response.status)?;
235 
236         if key_buf.len() != response.payload.len() {
237             log::error!(
238                 "key buffer size ({:?}) != payload size ({:?})",
239                 key_buf.len(),
240                 response.payload.len()
241             );
242             return Err(HwkeyError::BadLen);
243         }
244 
245         key_buf.copy_from_slice(&response.payload[..]);
246 
247         Ok(DeriveResult {
248             kdf_version: KdfVersion::from(response.kdf_version),
249             os_rollback_version: OsRollbackVersion::try_from(response.os_rollback_version)?,
250         })
251     }
252 
253     /// Queries the current OS version.
254     ///
255     /// # Returns
256     ///
257     /// The current [`OsRollbackVersion`] to be incorporated
258     /// into key derivation.
259     ///
260     /// # Examples
261     ///
262     /// ```
263     /// let hwkey_session = Hwkey::open().expect("could not open hwkey session");
264     /// let os_rollback_version = hwkey_session
265     ///     .query_current_os_version(RollbackVersionSource::RunningVersion)
266     ///     .expect("could not query version");
267     /// ```
query_current_os_version( &self, rollback_source: RollbackVersionSource, ) -> Result<OsRollbackVersion, HwkeyError>268     pub fn query_current_os_version(
269         &self,
270         rollback_source: RollbackVersionSource,
271     ) -> Result<OsRollbackVersion, HwkeyError> {
272         let derive_request = self
273             .derive_key_req()
274             .rollback_version_source(rollback_source)
275             .os_rollback_version(OsRollbackVersion::Current);
276         self.derive(&[], &mut [], derive_request).map(|res| res.os_rollback_version)
277     }
278 }
279 
280 /// The KDF algorithm version the hwkey service will use.
281 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
282 pub enum KdfVersion {
283     /// Tell the hwkey service to choose the best KDF algorithm version.
284     Best,
285     /// Specify KDF version hwkey service should use.
286     Version(u32),
287 }
288 
289 impl Into<u32> for KdfVersion {
290     /// Converts a [`KdfVersion`] into an [`i32`].
into(self) -> u32291     fn into(self) -> u32 {
292         match self {
293             Self::Best => 0,
294             Self::Version(v) => v,
295         }
296     }
297 }
298 
299 impl From<u32> for KdfVersion {
300     /// Converts an [`i32`] into a [`KdfVersion`].
from(v: u32) -> KdfVersion301     fn from(v: u32) -> KdfVersion {
302         if v == 0 {
303             KdfVersion::Best
304         } else {
305             KdfVersion::Version(v)
306         }
307     }
308 }
309 
310 /// the OS rollback version to be incorporated
311 /// into the key derivation.
312 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
313 pub enum OsRollbackVersion {
314     /// The latest available version will be used.
315     Current,
316     /// A specific version will be used.
317     Version(u32),
318 }
319 
320 impl TryInto<i32> for OsRollbackVersion {
321     type Error = HwkeyError;
322     /// Tries to convert a [`OsRollbackVersion`] into an [`i32`].
try_into(self) -> Result<i32, HwkeyError>323     fn try_into(self) -> Result<i32, HwkeyError> {
324         match self {
325             OsRollbackVersion::Current => Ok(HWKEY_ROLLBACK_VERSION_CURRENT),
326             OsRollbackVersion::Version(version) => Ok(version.try_into()?),
327         }
328     }
329 }
330 
331 impl TryFrom<i32> for OsRollbackVersion {
332     type Error = HwkeyError;
333     /// Tries to convert an [`i32`] into an [`OsRollbackVersion`].
try_from(v: i32) -> Result<OsRollbackVersion, HwkeyError>334     fn try_from(v: i32) -> Result<OsRollbackVersion, HwkeyError> {
335         match v {
336             HWKEY_ROLLBACK_VERSION_CURRENT => Ok(OsRollbackVersion::Current),
337             n => Ok(OsRollbackVersion::Version(n.try_into()?)),
338         }
339     }
340 }
341 
342 /// Specifies whether the rollback version must
343 /// have been committed. If
344 /// [`RollbackVersionSource::CommittedVersion`]
345 /// is specified, the system must guarantee that software
346 /// with a lower rollback version cannot ever run on a future
347 /// boot.
348 #[derive(Copy, Clone, Debug)]
349 pub enum RollbackVersionSource {
350     /// Gate the derived key based on the anti-rollback counter that has been
351     /// committed to fuses or stored. A version of Trusty with a version smaller
352     /// than this value should never run on the device again. The latest key may
353     /// not be available the first few times a new version of Trusty runs on the
354     /// device, because the counter may not be committed immediately. This
355     /// version source may not allow versions > 0 on some devices (i.e. rollback
356     /// versions cannot be committed).
357     CommittedVersion,
358     /// Gate the derived key based on the anti-rollback version in the signed
359     /// image of Trusty that is currently running. The latest key should be
360     /// available immediately, but the Trusty image may be rolled back on a
361     /// future boot. Care should be taken that Trusty still works if the image is
362     /// rolled back and access to this key is lost. Care should also be taken
363     /// that Trusty cannot infer this key if it rolls back to a previous version.
364     /// For example, storing the latest version of this key in Trusty’s storage
365     /// would allow it to be retrieved after rollback.
366     RunningVersion,
367 }
368 
369 impl Into<u32> for RollbackVersionSource {
370     /// Converts a [`RollbackVersionSource`] into a [`u32`].
into(self) -> u32371     fn into(self) -> u32 {
372         match self {
373             Self::CommittedVersion => {
374                 hwkey_rollback_version_source_HWKEY_ROLLBACK_COMMITTED_VERSION as u32
375             }
376             Self::RunningVersion => {
377                 hwkey_rollback_version_source_HWKEY_ROLLBACK_RUNNING_VERSION as u32
378             }
379         }
380     }
381 }
382 
383 /// The result of deriving a key.
384 #[derive(Debug, Eq, PartialEq)]
385 pub struct DeriveResult {
386     /// The KDF algorithm version used in key derivation.
387     pub kdf_version: KdfVersion,
388     /// The OS rollback version used in key derivation.
389     pub os_rollback_version: OsRollbackVersion,
390 }
391 
392 /// A builder for a derived key request. May
393 /// only be created via Hwkey::derive_key_req,
394 /// which will default to values backwards-compatible
395 /// with the unversioned key derivation functionality
396 /// provided by the hwkey service.
397 pub struct DerivedKeyRequest<'a> {
398     /// The version of the KDF to use.
399     /// [`KdfVersion::Best`] will be assumed, and
400     /// the latest version will be used.
401     kdf_version: KdfVersion,
402     /// If true, the derived key will be consistent and shared across the entire
403     /// family of devices, given the same input. If false, the derived key will
404     /// be unique to the particular device it was derived on.
405     shared_key: bool,
406     /// Specifies whether the @rollback_version must have been committed. If
407     /// [`RollbackVersionSource::CommittedVersion`] is specified, the system
408     /// must guarantee that software with a lower rollback version cannot
409     /// ever run on a future boot.
410     rollback_version_source: RollbackVersionSource,
411     /// The OS rollback version to be incorporated into the key
412     /// derivation. Must be less than or equal to the current Trusty OS rollback
413     /// version from [`RollbackVersionSource`]. If set to
414     /// [`OsRollbackVersion::Current`] the latest available version will be used
415     /// and will be written back to the struct.
416     os_rollback_version: OsRollbackVersion,
417     /// Hwkey session
418     session: &'a Hwkey,
419 }
420 
421 impl<'a> DerivedKeyRequest<'a> {
422     /// Returns default options; backwards-compatible,
423     /// with unversioned derived key service.
new(hwkey_sess: &'a Hwkey) -> Self424     fn new(hwkey_sess: &'a Hwkey) -> Self {
425         Self {
426             kdf_version: KdfVersion::Best,
427             shared_key: false,
428             rollback_version_source: RollbackVersionSource::CommittedVersion,
429             os_rollback_version: OsRollbackVersion::Version(0),
430             session: hwkey_sess,
431         }
432     }
433 
434     /// Sets the KDF algorithm version used in key derivation.
kdf(mut self, kdf_version: KdfVersion) -> Self435     pub fn kdf(mut self, kdf_version: KdfVersion) -> Self {
436         self.kdf_version = kdf_version;
437         self
438     }
439 
440     /// Tells derivation service to generate a shared key,
441     /// which will be consistent and shared across the entire
442     /// family of devices, given the same input.
shared_key(mut self) -> Self443     pub fn shared_key(mut self) -> Self {
444         self.shared_key = true;
445         self
446     }
447 
448     /// Tells derivation service to generate a key which will
449     /// be unique to the particular device it was derived on.
450     /// This key should never be available outside of
451     /// this device.
unique_key(mut self) -> Self452     pub fn unique_key(mut self) -> Self {
453         self.shared_key = false;
454         self
455     }
456 
457     /// Sets the rollback version source used in key derivation.
rollback_version_source(mut self, src: RollbackVersionSource) -> Self458     pub fn rollback_version_source(mut self, src: RollbackVersionSource) -> Self {
459         self.rollback_version_source = src;
460         self
461     }
462 
463     /// Sets the OS rollback version used in key derivation.
464     /// Must be less than or equal to the current Trusty rollback version
465     /// from [`RollbackVersionSource`].
os_rollback_version(mut self, v: OsRollbackVersion) -> Self466     pub fn os_rollback_version(mut self, v: OsRollbackVersion) -> Self {
467         self.os_rollback_version = v;
468         self
469     }
470 
471     /// Derive a versioned, device-specific key from the provided context.
472     ///
473     /// # Arguments
474     ///
475     /// * `src` - The context from which the key will be derived. If
476     /// empty, `key_buf` must be empty as well.
477     /// * `key_buf` - The buffer into which the key will be written. If
478     /// empty, no key will be generated and only the current versions
479     /// may be queried.
480     ///
481     /// # Returns
482     ///
483     /// The DeriveResult containing information used in derivation.
484     ///
485     /// # Examples
486     ///
487     /// ```
488     /// let hwkey_session = Hwkey::open().expect("could not open hwkey session");
489     /// let buf = &mut [0u8; 32 as usize];
490     /// let DeriveResult { kdf_version, os_rollback_version } = hwkey_session
491     ///     .derive_key_req()
492     ///     .derive(b"thirtytwo-bytes-of-nonsense-data", buf)
493     ///     .expect("could not derive key");
494     /// ```
495     ///
496     /// ```
497     /// let hwkey_session = Hwkey::open().expect("could not open hwkey session");
498     /// let buf = &mut [0u8; 128 as usize];
499     /// let DeriveResult { kdf_version, os_rollback_version } = hwkey_session
500     ///     .derive_key_req()
501     ///     .unique_key()
502     ///     .kdf(KdfVersion::Best)
503     ///     .os_rollback_version(OsRollbackVersion::Current)
504     ///     .rollback_version_source(RollbackVersionSource::RunningVersion)
505     ///     .derive(b"thirtytwo-bytes-of-nonsense-data", buf)
506     ///     .expect("could not derive key");
507     /// ```
508     ///
derive(self, src: &[u8], key_buf: &mut [u8]) -> Result<DeriveResult, HwkeyError>509     pub fn derive(self, src: &[u8], key_buf: &mut [u8]) -> Result<DeriveResult, HwkeyError> {
510         self.session.derive(src, key_buf, self)
511     }
512 }
513 
514 struct HwkeyMsg<'a> {
515     msg: hwkey_msg,
516     request: &'a [u8],
517 }
518 
519 impl<'s> Serialize<'s> for HwkeyMsg<'s> {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>520     fn serialize<'a: 's, S: Serializer<'s>>(
521         &'a self,
522         serializer: &mut S,
523     ) -> Result<S::Ok, S::Error> {
524         // SAFETY:
525         //  hwkey_msg.header is a fully-initialized, repr(C)
526         //  struct that outlives the Serializer lifetime.
527         //  arg1 and arg2 each a u32
528         unsafe {
529             serializer.serialize_as_bytes(&self.msg.header)?;
530             serializer.serialize_as_bytes(&self.msg.arg1)?;
531             serializer.serialize_as_bytes(&self.msg.arg2)?;
532         }
533         serializer.serialize_bytes(self.request)
534     }
535 }
536 
537 struct HwkeyDeriveVersionedMsg<'a> {
538     msg: hwkey_derive_versioned_msg,
539     context: &'a [u8],
540 }
541 
542 impl<'s> Serialize<'s> for HwkeyDeriveVersionedMsg<'s> {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>543     fn serialize<'a: 's, S: Serializer<'s>>(
544         &'a self,
545         serializer: &mut S,
546     ) -> Result<S::Ok, S::Error> {
547         // SAFETY:
548         //  hwkey_derive_versioned_msg.header is a fully-initialized,
549         //  repr(C) struct that outlives the Serializer lifetime.
550         //  All other serialized attributes are trivial types with
551         //  a corresponding C repr.
552         unsafe {
553             serializer.serialize_as_bytes(&self.msg.header)?;
554             serializer.serialize_as_bytes(&self.msg.kdf_version)?;
555             serializer.serialize_as_bytes(&self.msg.rollback_version_source)?;
556         }
557 
558         for rv in &self.msg.rollback_versions {
559             unsafe {
560                 serializer.serialize_as_bytes(rv)?;
561             }
562         }
563 
564         unsafe {
565             serializer.serialize_as_bytes(&self.msg.key_options)?;
566             serializer.serialize_as_bytes(&self.msg.key_len)?;
567         }
568 
569         serializer.serialize_bytes(self.context)
570     }
571 }
572 
573 // TODO: replace owned payload with references when
574 // GATs are available for use in Deserialize trait
575 #[derive(Eq, PartialEq, Debug)]
576 struct HwkeyResponse {
577     kdf_version: u32,
578     status: u32,
579     cmd: u32,
580     payload: Vec<u8>,
581 }
582 
583 impl Deserialize for HwkeyResponse {
584     type Error = HwkeyError;
585     const MAX_SERIALIZED_SIZE: usize = HWKEY_MAX_MSG_SIZE as usize;
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>586     fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
587         let header_size = mem::size_of::<hwkey_msg>();
588         if bytes.len() < header_size {
589             log::error!("response too small to be valid");
590             return Err(HwkeyError::BadLen);
591         }
592         // SAFETY: We have validated that the buffer contains enough data to
593         // represent a hwkey_msg. The constructed lifetime here does not
594         // outlive the function and thus cannot outlive the lifetime of the
595         // buffer.
596         let msg = unsafe { &*(bytes.as_ptr() as *const hwkey_msg) };
597 
598         let response_payload = Vec::try_alloc_from(&bytes[header_size..])?;
599         Ok(Self {
600             status: msg.header.status,
601             cmd: msg.header.cmd,
602             kdf_version: msg.arg1,
603             payload: response_payload,
604         })
605     }
606 }
607 
608 // TODO: replace owned payload with references when
609 // GATs are available for use in Deserialize trait
610 struct HwkeyDeriveVersionedResponse {
611     cmd: u32,
612     status: u32,
613     os_rollback_version: i32,
614     kdf_version: u32,
615     payload: Vec<u8>,
616 }
617 
618 impl Deserialize for HwkeyDeriveVersionedResponse {
619     type Error = HwkeyError;
620 
621     const MAX_SERIALIZED_SIZE: usize = HWKEY_MAX_MSG_SIZE as usize;
622 
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>623     fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
624         let header_size = mem::size_of::<hwkey_derive_versioned_msg>();
625         if bytes.len() < header_size {
626             log::error!("response too small to be valid");
627             return Err(HwkeyError::BadLen);
628         }
629 
630         // SAFETY: We have validated that the buffer contains enough data to
631         // represent a hwkey_derive_versioned_msg.
632         let msg = unsafe { &*(bytes.as_ptr() as *const hwkey_derive_versioned_msg) };
633 
634         // the rest of the buffer should be the key data
635         if bytes.len() - header_size != msg.key_len as usize {
636             log::error!(
637                 "response payload size ({:?}) != key length ({:?})",
638                 bytes.len() - header_size,
639                 msg.key_len
640             );
641             return Err(HwkeyError::BadLen);
642         }
643 
644         let response_payload = Vec::try_alloc_from(&bytes[header_size..])?;
645         Ok(Self {
646             cmd: msg.header.cmd,
647             status: msg.header.status,
648             os_rollback_version: msg.rollback_versions
649                 [hwkey_rollback_version_indices_HWKEY_ROLLBACK_VERSION_OS_INDEX as usize],
650             kdf_version: msg.kdf_version,
651             payload: response_payload,
652         })
653     }
654 }
655