• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 //! Implementation of the `KeyValueStore` trait using Trusty secure storage.
18 //!
19 //! Store each secret in a file of its own (mapping the secret ID to the filename) as there are not
20 //! expected to be many extant secrets.  However, use a prefix for the filename to allow easier
21 //! migration to a different scheme in future if this assumption changes.
22 
23 use alloc::string::String;
24 use secretkeeper_comm::data_types::error::Error;
25 use secretkeeper_core::store::KeyValueStore;
26 use storage::{OpenMode, Port, Session};
27 
28 /// Store each secret in a file named "v1_<hex>", using the hex representation of the key/secret ID.
29 /// Note that IDs are not confidential, so can appear in logs.
30 const PREFIX_V1: &str = "v1_";
31 
32 /// Generate the filename corresponding to a key.
filename(key: &[u8]) -> String33 fn filename(key: &[u8]) -> String {
34     let mut result = String::with_capacity(PREFIX_V1.len() + 2 * key.len());
35     result += PREFIX_V1;
36     for byte in key {
37         result += &format!("{:02x}", byte);
38     }
39     result
40 }
41 
42 /// Helper macro for emitting an error.
43 macro_rules! ss_err {
44     {  $e:expr, $($arg:tt)+ } => {
45         {
46             log::error!("{}: {:?}", format_args!($($arg)+), $e);
47             Error::UnexpectedError
48         }
49     };
50 }
51 
52 /// Create a storage session.
create_session() -> Result<Session, Error>53 fn create_session() -> Result<Session, Error> {
54     // Use TD storage, which means that:
55     // - storage is only available after Android has booted
56     // - storage is wiped on factory reset
57     // - size of stored data isn't problematic
58     Session::new(Port::TamperDetect, /* wait_for_port= */ true)
59         .map_err(|e| ss_err!(e, "Couldn't create storage session"))
60 }
61 
62 /// An implementation of `KeyValueStore` backed by secure storage.
63 #[derive(Default)]
64 pub struct SecureStore;
65 
66 impl KeyValueStore for SecureStore {
store(&mut self, key: &[u8], val: &[u8]) -> Result<(), Error>67     fn store(&mut self, key: &[u8], val: &[u8]) -> Result<(), Error> {
68         let filename = filename(key);
69         let mut session = create_session()?;
70 
71         // This will overwrite the value if key is already present.
72         let mut file = session
73             .open_file(&filename, OpenMode::Create)
74             .map_err(|e| ss_err!(e, "Couldn't create file '{filename}'"))?;
75         session.write_all(&mut file, val).map_err(|e| ss_err!(e, "Failed to write data"))?;
76         Ok(())
77     }
78 
get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error>79     fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
80         let filename = filename(key);
81         let mut session = create_session()?;
82         let file = match session.open_file(&filename, OpenMode::Open) {
83             Ok(f) => f,
84             Err(storage::Error::Code(trusty_sys::Error::NotFound)) => return Ok(None),
85             Err(e) => return Err(ss_err!(e, "Failed to open file '{filename}'")),
86         };
87         let size = session
88             .get_size(&file)
89             .map_err(|e| ss_err!(e, "Failed to get size for '{filename}'"))?;
90         let mut buffer = vec![0; size];
91         let content = session
92             .read_all(&file, buffer.as_mut_slice())
93             .map_err(|e| ss_err!(e, "Failed to read '{filename}'"))?;
94         let total_size = content.len();
95         buffer.resize(total_size, 0);
96         Ok(Some(buffer))
97     }
98 
delete(&mut self, key: &[u8]) -> Result<(), Error>99     fn delete(&mut self, key: &[u8]) -> Result<(), Error> {
100         let filename = filename(key);
101         let mut session = create_session()?;
102         match session.remove(&filename) {
103             Ok(_) => Ok(()),
104             Err(storage::Error::Code(trusty_sys::Error::NotFound)) => Ok(()),
105             Err(e) => Err(ss_err!(e, "Failed to delete file '{filename}'")),
106         }
107     }
108 
delete_all(&mut self) -> Result<(), Error>109     fn delete_all(&mut self) -> Result<(), Error> {
110         let mut failed = false;
111         let mut session = create_session()?;
112         for entry in session.list_files().map_err(|e| ss_err!(e, "Failed to list files"))? {
113             match entry {
114                 Ok((filename, _state)) if filename.starts_with(PREFIX_V1) => {
115                     let result = session
116                         .remove(&filename)
117                         .map_err(|e| ss_err!(e, "Failed to delete '{filename}'"));
118                     if result.is_err() {
119                         failed = true;
120                     }
121                 }
122                 Ok((filename, _state)) => log::info!("Skipping unrelated file {filename}"),
123                 Err(e) => log::error!("Failed to delete an entry: {e:?}"),
124             };
125         }
126         if failed {
127             Err(Error::UnexpectedError)
128         } else {
129             Ok(())
130         }
131     }
132 }
133 
134 #[cfg(test)]
135 mod tests {
136     use super::*;
137     use test::expect_eq;
138 
139     const KEY1: &[u8] = b"bogus key 1";
140     const KEY2: &[u8] = b"bogus key 2";
141     const SECRET1: &[u8] = b"bogus secret 1";
142     const SECRET2: &[u8] = b"bogus secret 2";
143 
144     #[test]
test_secretkeeper_store()145     fn test_secretkeeper_store() {
146         let mut store = SecureStore::default();
147 
148         // Ensure consistent state before.
149         store.delete(KEY1).unwrap();
150         store.delete(KEY2).unwrap();
151 
152         store.store(KEY1, SECRET1).unwrap();
153         expect_eq!(store.get(KEY1), Ok(Some(SECRET1.to_vec())));
154         expect_eq!(store.get(KEY2), Ok(None));
155         store.store(KEY1, SECRET2).unwrap();
156         expect_eq!(store.get(KEY1), Ok(Some(SECRET2.to_vec())));
157         expect_eq!(store.get(KEY2), Ok(None));
158         store.store(KEY1, SECRET1).unwrap();
159         expect_eq!(store.get(KEY1), Ok(Some(SECRET1.to_vec())));
160         expect_eq!(store.get(KEY2), Ok(None));
161         store.store(KEY2, SECRET1).unwrap();
162         expect_eq!(store.get(KEY1), Ok(Some(SECRET1.to_vec())));
163         expect_eq!(store.get(KEY2), Ok(Some(SECRET1.to_vec())));
164         store.delete(KEY1).unwrap();
165         expect_eq!(store.get(KEY1), Ok(None));
166         expect_eq!(store.get(KEY2), Ok(Some(SECRET1.to_vec())));
167         store.delete(KEY2).unwrap();
168         expect_eq!(store.get(KEY1), Ok(None));
169         expect_eq!(store.get(KEY2), Ok(None));
170 
171         // Ensure consistent state after.
172         store.delete(KEY1).unwrap();
173         store.delete(KEY2).unwrap();
174     }
175 }
176