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