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 #![no_std]
18 #![feature(allocator_api)]
19
20 mod err;
21
22 #[cfg(test)]
23 mod test;
24
25 #[allow(non_upper_case_globals)]
26 #[allow(non_camel_case_types)]
27 #[allow(unused)]
28 #[allow(deref_nullptr)] // https://github.com/rust-lang/rust-bindgen/issues/1651
29 mod sys {
30 include!(env!("BINDGEN_INC_FILE"));
31 }
32
33 pub use err::HwWskError;
34 pub use sys::HWWSK_MAX_MSG_SIZE;
35
36 use core::mem;
37 use sys::*;
38 use tipc::{Deserialize, Handle, Serialize, Serializer};
39 use trusty_std::alloc::{TryAllocFrom, Vec};
40
41 /// The command sent to the hwwsk service.
42 pub enum HwWskCmd {
43 /// Generate (or import) a persistent storage key.
44 ///
45 /// Result is wrapped using a device-unique key.
46 Generate(GenerateKeyReq),
47 /// Re-wrap a non-ephemeral wrapped key with ephemeral storage key.
48 ///
49 /// Result is a key that is only good for the current session.
50 Export(ExportKeyReq),
51 }
52
53 /// A request to the hwwsk service.
54 pub struct HwWskReq {
55 hdr: hwwsk_req_hdr,
56 /// The command that is requested.
57 pub req: HwWskCmd,
58 }
59
60 impl HwWskReq {
response_from(&self, status: u32, payload: Vec<u8>) -> HwWskResponse61 pub fn response_from(&self, status: u32, payload: Vec<u8>) -> HwWskResponse {
62 HwWskResponse { status, cmd: self.hdr.cmd | hwwsk_cmd_HWWSK_CMD_RESP as u32, payload }
63 }
64 }
65
66 impl<'s> Serialize<'s> for HwWskReq {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>67 fn serialize<'a: 's, S: Serializer<'s>>(
68 &'a self,
69 serializer: &mut S,
70 ) -> Result<S::Ok, S::Error> {
71 self.hdr.cmd.serialize(serializer)?;
72 self.hdr.flags.serialize(serializer)?;
73
74 match &self.req {
75 HwWskCmd::Generate(g) => g.serialize(serializer),
76 HwWskCmd::Export(e) => e.serialize(serializer),
77 }
78 }
79 }
80
81 impl Deserialize for HwWskReq {
82 type Error = HwWskError;
83 const MAX_SERIALIZED_SIZE: usize = HWWSK_MAX_MSG_SIZE as usize;
84
deserialize(bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>85 fn deserialize(bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
86 let header_size = mem::size_of::<hwwsk_req_hdr>();
87 if bytes.len() < header_size {
88 log::error!("response too small");
89 return Err(HwWskError::BadLen);
90 }
91 // SAFETY: We have validated that the buffer contains enough data to
92 // represent a hwwsk_req_hdr. The constructed lifetime here does not
93 // outlive the function and thus cannot outlive the lifetime of the
94 // buffer.
95 let hdr = unsafe { &*(bytes.as_ptr() as *const hwwsk_req_hdr) };
96
97 let req = {
98 #[allow(non_upper_case_globals)]
99 match hdr.cmd as hwwsk_cmd {
100 hwwsk_cmd_HWWSK_CMD_GENERATE_KEY => Ok(HwWskCmd::Generate(
101 GenerateKeyReq::deserialize(&bytes[header_size..], handles)?,
102 )),
103 hwwsk_cmd_HWWSK_CMD_EXPORT_KEY => {
104 Ok(HwWskCmd::Export(ExportKeyReq::deserialize(&bytes[header_size..], handles)?))
105 }
106 cmd => {
107 log::error!("unrecognized command request: {:?}", cmd);
108 Err(HwWskError::NotValid)
109 }
110 }
111 }?;
112 Ok(Self { hdr: hwwsk_req_hdr { cmd: hdr.cmd, flags: hdr.flags }, req })
113 }
114 }
115
116 /// Request to generate a persistent storage key. If the supplied key is empty,
117 /// a new key will be generated. Otherwise, the provided data will be
118 /// imported as a raw key.
119 pub struct GenerateKeyReq {
120 req: hwwsk_generate_key_req,
121 raw_key: Vec<u8>,
122 }
123
124 impl<'s> Serialize<'s> for GenerateKeyReq {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>125 fn serialize<'a: 's, S: Serializer<'s>>(
126 &'a self,
127 serializer: &mut S,
128 ) -> Result<S::Ok, S::Error> {
129 // SAFETY:
130 // All serialized attributes are trivial types with
131 // corresponding C representations
132 unsafe {
133 serializer.serialize_as_bytes(&self.req.key_size)?;
134 serializer.serialize_as_bytes(&self.req.key_flags)?;
135 }
136
137 serializer.serialize_bytes(&self.raw_key)
138 }
139 }
140
141 impl Deserialize for GenerateKeyReq {
142 type Error = HwWskError;
143 const MAX_SERIALIZED_SIZE: usize = HWWSK_MAX_MSG_SIZE as usize;
144
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>145 fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
146 let header_size = mem::size_of::<hwwsk_generate_key_req>();
147 if bytes.len() < header_size {
148 log::error!("response too small");
149 return Err(HwWskError::BadLen);
150 }
151 // SAFETY: We have validated that the buffer contains enough data to
152 // represent a hwwsk_generate_key_req. The constructed lifetime here does not
153 // outlive the function and thus cannot outlive the lifetime of the
154 // buffer.
155 let hwwsk_generate_key_req { key_size, key_flags } =
156 unsafe { &*(bytes.as_ptr() as *const hwwsk_generate_key_req) };
157
158 Ok(Self {
159 req: hwwsk_generate_key_req { key_size: *key_size, key_flags: *key_flags },
160 raw_key: Vec::try_alloc_from(&bytes[header_size..])?,
161 })
162 }
163 }
164
165 /// A request to re-wrap a non-ephemeral key using an ephemeral storage key.
166 /// The resulting key is only good for the current session.
167 pub struct ExportKeyReq {
168 key_blob: Vec<u8>,
169 }
170
171 impl<'s> Serialize<'s> for ExportKeyReq {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>172 fn serialize<'a: 's, S: Serializer<'s>>(
173 &'a self,
174 serializer: &mut S,
175 ) -> Result<S::Ok, S::Error> {
176 serializer.serialize_bytes(&self.key_blob)
177 }
178 }
179
180 impl Deserialize for ExportKeyReq {
181 type Error = HwWskError;
182 const MAX_SERIALIZED_SIZE: usize = HWWSK_MAX_MSG_SIZE as usize;
183
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>184 fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
185 Ok(Self { key_blob: Vec::try_alloc_from(bytes)? })
186 }
187 }
188
189 /// Response from hwwsk service.
190 pub struct HwWskResponse {
191 /// Sent command, acknowledged by service if successful.
192 cmd: u32,
193 /// Status of command result.
194 status: u32,
195 /// Response data.
196 payload: Vec<u8>,
197 }
198
199 impl<'s> Serialize<'s> for HwWskResponse {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>200 fn serialize<'a: 's, S: Serializer<'s>>(
201 &'a self,
202 serializer: &mut S,
203 ) -> Result<S::Ok, S::Error> {
204 // SAFETY:
205 // All serialized attributes are trivial types with
206 // corresponding C representations
207 unsafe {
208 serializer.serialize_as_bytes(&self.cmd)?;
209 serializer.serialize_as_bytes(&self.status)?;
210 }
211
212 serializer.serialize_bytes(&self.payload)
213 }
214 }
215
216 impl Deserialize for HwWskResponse {
217 type Error = HwWskError;
218 const MAX_SERIALIZED_SIZE: usize = HWWSK_MAX_MSG_SIZE as usize;
219
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error>220 fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> {
221 // response must at least contain cmd and status
222 let header_size = mem::size_of::<u32>() * 2;
223 if bytes.len() < header_size {
224 log::error!("response too small");
225 return Err(HwWskError::BadLen);
226 }
227 let (cmd_bytes, rest) = bytes.split_at(mem::size_of::<u32>());
228 let (status_bytes, payload_bytes) = rest.split_at(mem::size_of::<u32>());
229
230 let status = u32::from_ne_bytes(status_bytes.try_into()?);
231 let cmd = u32::from_ne_bytes(cmd_bytes.try_into()?);
232
233 let response_payload = Vec::try_alloc_from(payload_bytes)?;
234 Ok(Self { status, cmd, payload: response_payload })
235 }
236 }
237
238 // TODO: consider trusty util for this across client implementations
validate_cmd(sent_cmd: &u32, recvd_cmd: &u32) -> Result<(), HwWskError>239 fn validate_cmd(sent_cmd: &u32, recvd_cmd: &u32) -> Result<(), HwWskError> {
240 let validated = *recvd_cmd == (sent_cmd | hwwsk_cmd_HWWSK_CMD_RESP as u32);
241 if !validated {
242 log::error!(
243 "unknown response cmd: {:?}/{:?}",
244 recvd_cmd,
245 (sent_cmd | hwwsk_cmd_HWWSK_CMD_RESP as u32)
246 );
247 return Err(HwWskError::InvalidCmdResponse);
248 }
249
250 Ok(())
251 }
252
253 /// A combination of flags can be passed to [`generate_key`].
254 pub struct KeyFlags {
255 flags: u32,
256 }
257
258 impl KeyFlags {
new() -> Self259 pub fn new() -> Self {
260 Self { flags: 0 }
261 }
262
263 /// Indicates that the resulting key must be rollback resistant.
rollback_resistance(mut self) -> Self264 pub fn rollback_resistance(mut self) -> Self {
265 self.flags |= hwwsk_key_flags_HWWSK_FLAGS_ROLLBACK_RESISTANCE as u32;
266 self
267 }
268 }
269
270 /// Creates a new persistent key from provided raw key material.
271 ///
272 /// This routine creates a new hardware wrapped storage key by
273 /// either importing raw key material that's specified by the caller.
274 /// The resulting key is persistent and reusable across device reset.
275 ///
276 /// # Arguments
277 ///
278 /// * `session` - IPC channel to HWWSK service
279 /// * `buf` - buffer to store resulting key blob
280 /// * `key_size` - key size in bits
281 /// * `key_flags` - a combination of [`KeyFlags`] to specify any additional
282 /// properties of the generated key
283 /// * `raw_key` - the buffer containing raw key data for import operation
284 ///
285 /// # Returns
286 ///
287 /// A truncated view into `buf` where the wrapped key data was populated.
288 ///
import_key<'a>( session: &Handle, buf: &'a mut [u8], key_size: usize, key_flags: KeyFlags, raw_key: &[u8], ) -> Result<&'a [u8], HwWskError>289 pub fn import_key<'a>(
290 session: &Handle,
291 buf: &'a mut [u8],
292 key_size: usize,
293 key_flags: KeyFlags,
294 raw_key: &[u8],
295 ) -> Result<&'a [u8], HwWskError> {
296 if raw_key.is_empty() {
297 return Err(HwWskError::BadLen);
298 }
299 create_key(session, buf, key_size, key_flags, raw_key)
300 }
301
302 /// Creates a new persistent key.
303 ///
304 /// This routine creates a new hardware wrapped storage key by
305 /// generating a new random key The resulting key is persistent and
306 /// reusable across device reset.
307 ///
308 /// # Arguments
309 ///
310 /// * `session` - IPC channel to HWWSK service
311 /// * `buf` - buffer to store resulting key blob
312 /// * `key_size` - key size in bits
313 /// * `key_flags` - a combination of [`KeyFlags`] to specify any additional
314 /// properties of the generated key
315 ///
316 /// # Returns
317 ///
318 /// A truncated view into `buf` where the wrapped key data was populated.
319 ///
generate_key<'a>( session: &Handle, buf: &'a mut [u8], key_size: usize, key_flags: KeyFlags, ) -> Result<&'a [u8], HwWskError>320 pub fn generate_key<'a>(
321 session: &Handle,
322 buf: &'a mut [u8],
323 key_size: usize,
324 key_flags: KeyFlags,
325 ) -> Result<&'a [u8], HwWskError> {
326 create_key(session, buf, key_size, key_flags, &[])
327 }
328
create_key<'a>( session: &Handle, buf: &'a mut [u8], key_size: usize, key_flags: KeyFlags, raw_key: &[u8], ) -> Result<&'a [u8], HwWskError>329 fn create_key<'a>(
330 session: &Handle,
331 buf: &'a mut [u8],
332 key_size: usize,
333 key_flags: KeyFlags,
334 raw_key: &[u8],
335 ) -> Result<&'a [u8], HwWskError> {
336 let cmd = hwwsk_cmd_HWWSK_CMD_GENERATE_KEY as u32;
337 let req = HwWskReq {
338 hdr: hwwsk_req_hdr { cmd, flags: 0 },
339 req: HwWskCmd::Generate(GenerateKeyReq {
340 req: hwwsk_generate_key_req { key_size: key_size as u32, key_flags: key_flags.flags },
341 raw_key: Vec::try_alloc_from(raw_key)?,
342 }),
343 };
344
345 session.send(&req)?;
346
347 let resp_buf = &mut [0; HWWSK_MAX_MSG_SIZE as usize];
348 let response: HwWskResponse = session.recv(resp_buf)?;
349
350 validate_cmd(&cmd, &response.cmd)?;
351 HwWskError::from_status(response.status)?;
352
353 if buf.len() < response.payload.len() {
354 log::error!("response payload is too large to fit into the buffer");
355 return Err(HwWskError::BadLen);
356 }
357
358 let res_buffer = &mut buf[..response.payload.len()];
359 res_buffer.copy_from_slice(&response.payload);
360
361 Ok(res_buffer)
362 }
363
364 /// Rewrap specified SK key with ESK.
365 ///
366 /// This routine rewraps a specified persistent SK key with an ephemeral
367 /// storage key (ESK). The resulting key is only good for the current
368 /// session.
369 ///
370 /// # Arguments
371 ///
372 /// * `session` - IPC channel to HWWSK service
373 /// * `buf` - buffer to store the resulting key blob
374 /// * `key_blob` - the key blob to unwrap
375 ///
376 /// # Returns
377 ///
378 /// A truncated view into `buf` where the rewrrapped key data was populated.
379 ///
export_key<'a>( session: &Handle, buf: &'a mut [u8], key_blob: &[u8], ) -> Result<&'a [u8], HwWskError>380 pub fn export_key<'a>(
381 session: &Handle,
382 buf: &'a mut [u8],
383 key_blob: &[u8],
384 ) -> Result<&'a [u8], HwWskError> {
385 let cmd = hwwsk_cmd_HWWSK_CMD_EXPORT_KEY as u32;
386 let req = HwWskReq {
387 hdr: hwwsk_req_hdr { cmd, flags: 0 },
388 req: HwWskCmd::Export(ExportKeyReq { key_blob: Vec::try_alloc_from(key_blob)? }),
389 };
390
391 session.send(&req)?;
392
393 let resp_buf = &mut [0; HWWSK_MAX_MSG_SIZE as usize];
394 let response: HwWskResponse = session.recv(resp_buf)?;
395
396 validate_cmd(&cmd, &response.cmd)?;
397 HwWskError::from_status(response.status)?;
398
399 if buf.len() < response.payload.len() {
400 log::error!("response payload is too large to fit into the buffer");
401 return Err(HwWskError::BadLen);
402 }
403
404 let res_buffer = &mut buf[..response.payload.len()];
405 res_buffer.copy_from_slice(&response.payload);
406
407 Ok(res_buffer)
408 }
409