Skip to main content

fxfs_crypt/
lib.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::{Context, Error};
6use fidl_fuchsia_fxfs::{
7    CryptCreateKeyResult, CryptManagementAddWrappingKeyResult,
8    CryptManagementForgetWrappingKeyResult, CryptManagementRequest, CryptManagementRequestStream,
9    CryptManagementSetActiveKeyResult, CryptRequest, CryptRequestStream, KeyPurpose,
10    ObjectType as FxfsFidlObjectType, WrappedKey,
11};
12
13use futures::stream::TryStreamExt;
14
15pub mod log;
16use log::*;
17
18use fxfs_crypt_common::CryptBase;
19use fxfs_crypto::Crypt as _;
20
21pub enum Services {
22    Crypt(CryptRequestStream),
23    CryptManagement(CryptManagementRequestStream),
24}
25
26pub struct CryptService {
27    inner: CryptBase,
28}
29
30impl CryptService {
31    pub fn new() -> Self {
32        Self { inner: CryptBase::new() }
33    }
34
35    async fn create_key(&self, owner: u64, purpose: KeyPurpose) -> CryptCreateKeyResult {
36        let purpose = purpose.try_into().map_err(zx::Status::into_raw)?;
37        let (fxfs_key, unwrapped_key) =
38            self.inner.create_key(owner, purpose).await.map_err(|e| e.into_raw())?;
39        Ok((fxfs_key.wrapping_key_id, (*fxfs_key.key).to_vec(), (*unwrapped_key).to_vec()))
40    }
41
42    async fn create_key_with_id(
43        &self,
44        owner: u64,
45        wrapping_key_id: u128,
46        object_type: FxfsFidlObjectType,
47        _flags: fidl_fuchsia_io::FscryptPolicyFlags,
48    ) -> Result<(WrappedKey, Vec<u8>), i32> {
49        let (encryption_key, unwrapped_key) = self
50            .inner
51            .create_key_with_id(owner, wrapping_key_id.to_le_bytes(), object_type)
52            .await
53            .map_err(|e| e.into_raw())?;
54
55        Ok((WrappedKey::from(encryption_key), (*unwrapped_key).to_vec()))
56    }
57
58    async fn unwrap_key(&self, owner: u64, wrapped_key: WrappedKey) -> Result<Vec<u8>, i32> {
59        let unwrapped_key =
60            self.inner.unwrap_key(&wrapped_key, owner).await.map_err(|e| e.into_raw())?;
61        Ok((*unwrapped_key).to_vec())
62    }
63
64    pub fn add_wrapping_key(
65        &self,
66        wrapping_key_id: u128,
67        key: Vec<u8>,
68    ) -> CryptManagementAddWrappingKeyResult {
69        let key: [u8; 32] = key.try_into().map_err(|_| zx::Status::INVALID_ARGS.into_raw())?;
70        self.inner.add_wrapping_key(wrapping_key_id.to_le_bytes(), key).map_err(|e| e.into_raw())
71    }
72
73    pub fn set_active_key(
74        &self,
75        purpose: KeyPurpose,
76        wrapping_key_id: u128,
77    ) -> CryptManagementSetActiveKeyResult {
78        let purpose = purpose.try_into().map_err(zx::Status::into_raw)?;
79        self.inner.set_active_key(purpose, wrapping_key_id.to_le_bytes()).map_err(|e| e.into_raw())
80    }
81
82    fn forget_wrapping_key(&self, wrapping_key_id: u128) -> CryptManagementForgetWrappingKeyResult {
83        self.inner.forget_wrapping_key(&wrapping_key_id.to_le_bytes()).map_err(|e| e.into_raw())
84    }
85
86    pub async fn handle_request(&self, stream: Services) -> Result<(), Error> {
87        match stream {
88            Services::Crypt(mut stream) => {
89                while let Some(request) = stream.try_next().await.context("Reading request")? {
90                    match request {
91                        CryptRequest::CreateKey { owner, purpose, responder } => {
92                            responder
93                                .send(match &self.create_key(owner, purpose).await {
94                                    Ok((id, wrapped, key)) => Ok((id, wrapped, key)),
95                                    Err(e) => Err(*e),
96                                })
97                                .unwrap_or_else(|e| {
98                                    // TODO(https://fxbug.dev/360919323): we can use `:err` when we
99                                    // enable the log kv_std feature.
100                                    error!(
101                                        error:? = e;
102                                        "Failed to send CreateKey response"
103                                    )
104                                });
105                        }
106                        CryptRequest::CreateKeyWithId {
107                            owner,
108                            wrapping_key_id,
109                            object_type,
110                            flags,
111                            responder,
112                        } => {
113                            responder
114                                .send(
115                                    match self
116                                        .create_key_with_id(
117                                            owner,
118                                            u128::from_le_bytes(wrapping_key_id),
119                                            object_type,
120                                            flags,
121                                        )
122                                        .await
123                                    {
124                                        Ok((ref wrapped, ref key)) => Ok((wrapped, key, None)),
125                                        Err(e) => Err(e),
126                                    },
127                                )
128                                .unwrap_or_else(|e| {
129                                    // TODO(https://fxbug.dev/360919323): we can use `:err` when we
130                                    // enable the log kv_std feature.
131                                    error!(
132                                        error:? = e;
133                                        "Failed to send CreateKeyWithId response"
134                                    )
135                                });
136                        }
137                        CryptRequest::UnwrapKey { owner, wrapped_key, responder } => {
138                            let response;
139                            responder
140                                .send({
141                                    response = self.unwrap_key(owner, wrapped_key).await;
142                                    match &response {
143                                        Ok(v) => Ok((&v[..], None)),
144                                        Err(e) => Err(*e),
145                                    }
146                                })
147                                .unwrap_or_else(|e| {
148                                    // TODO(https://fxbug.dev/360919323): we can use `:err` when we
149                                    // enable the log kv_std feature.
150                                    error!(
151                                        error:? = e;
152                                        "Failed to send UnwrapKey response"
153                                    )
154                                });
155                        }
156                    }
157                }
158            }
159            Services::CryptManagement(mut stream) => {
160                while let Some(request) = stream.try_next().await.context("Reading request")? {
161                    match request {
162                        CryptManagementRequest::AddWrappingKey {
163                            wrapping_key_id,
164                            key,
165                            responder,
166                        } => {
167                            let response =
168                                self.add_wrapping_key(u128::from_le_bytes(wrapping_key_id), key);
169                            responder.send(response).unwrap_or_else(|e| {
170                                // TODO(https://fxbug.dev/360919323): we can use `:err` when we
171                                // enable the log kv_std feature.
172                                error!(
173                                    error:? = e;
174                                    "Failed to send AddWrappingKey response"
175                                )
176                            });
177                        }
178                        CryptManagementRequest::SetActiveKey {
179                            purpose,
180                            wrapping_key_id,
181                            responder,
182                        } => {
183                            let response =
184                                self.set_active_key(purpose, u128::from_le_bytes(wrapping_key_id));
185                            responder.send(response).unwrap_or_else(
186                                // TODO(https://fxbug.dev/360919323): we can use `:err` when we
187                                // enable the log kv_std feature.
188                                |e| error!(error:? = e;"Failed to send SetActiveKey response"),
189                            );
190                        }
191                        CryptManagementRequest::ForgetWrappingKey {
192                            wrapping_key_id,
193                            responder,
194                        } => {
195                            let response =
196                                self.forget_wrapping_key(u128::from_le_bytes(wrapping_key_id));
197                            responder.send(response).unwrap_or_else(|e| {
198                                // TODO(https://fxbug.dev/360919323): we can use `:err` when we
199                                // enable the log kv_std feature.
200                                error!(
201                                    error:? = e;
202                                    "Failed to send ForgetWrappingKey response"
203                                )
204                            });
205                        }
206                    }
207                }
208            }
209        }
210        Ok(())
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::CryptService;
217    use fidl_fuchsia_fxfs::{FxfsKey, KeyPurpose, ObjectType, WrappedKey};
218
219    #[fuchsia::test]
220    async fn wrap_unwrap_key() {
221        let service = CryptService::new();
222        let key = vec![0xABu8; 32];
223        service.add_wrapping_key(1, key.clone()).expect("add_key failed");
224        service.set_active_key(KeyPurpose::Data, 1).expect("set_active_key failed");
225
226        let (wrapping_key_id, wrapped_key, unwrapped_key) =
227            service.create_key(0, KeyPurpose::Data).await.expect("create_key failed");
228        let wrapping_key_id_int = u128::from_le_bytes(wrapping_key_id);
229        assert_eq!(wrapping_key_id_int, 1);
230        let unwrap_result = service
231            .unwrap_key(
232                0,
233                WrappedKey::Fxfs(FxfsKey {
234                    wrapping_key_id,
235                    wrapped_key: wrapped_key.try_into().unwrap(),
236                }),
237            )
238            .await
239            .expect("unwrap_key failed");
240        assert_eq!(unwrap_result, unwrapped_key);
241
242        // Do it twice to make sure the service can use the same key repeatedly.
243        let (wrapping_key_id, wrapped_key, unwrapped_key) =
244            service.create_key(1, KeyPurpose::Data).await.expect("create_key failed");
245        let wrapping_key_id_int = u128::from_le_bytes(wrapping_key_id);
246        assert_eq!(wrapping_key_id_int, 1);
247        let unwrap_result = service
248            .unwrap_key(
249                1,
250                WrappedKey::Fxfs(FxfsKey {
251                    wrapping_key_id,
252                    wrapped_key: wrapped_key.try_into().unwrap(),
253                }),
254            )
255            .await
256            .expect("unwrap_key failed");
257        assert_eq!(unwrap_result, unwrapped_key);
258    }
259
260    #[fuchsia::test]
261    async fn wrap_unwrap_key_with_arbitrary_wrapping_key() {
262        let service = CryptService::new();
263        let key = vec![0xABu8; 32];
264        service.add_wrapping_key(2, key.clone()).expect("add_key failed");
265
266        let (wrapped_key, unwrapped_key) = service
267            .create_key_with_id(
268                0,
269                2,
270                ObjectType::File,
271                fidl_fuchsia_io::FscryptPolicyFlags::empty(),
272            )
273            .await
274            .expect("create_key_with_id failed");
275        let unwrap_result = service.unwrap_key(0, wrapped_key).await.expect("unwrap_key failed");
276        assert_eq!(unwrap_result, unwrapped_key);
277
278        // Do it twice to make sure the service can use the same key repeatedly.
279        let (wrapped_key, unwrapped_key) = service
280            .create_key_with_id(
281                1,
282                2,
283                ObjectType::File,
284                fidl_fuchsia_io::FscryptPolicyFlags::empty(),
285            )
286            .await
287            .expect("create_key_with_id failed");
288        let unwrap_result = service.unwrap_key(1, wrapped_key).await.expect("unwrap_key failed");
289        assert_eq!(unwrap_result, unwrapped_key);
290    }
291
292    #[fuchsia::test]
293    async fn create_key_with_wrapping_key_that_does_not_exist() {
294        let service = CryptService::new();
295        service
296            .create_key_with_id(
297                0,
298                2,
299                ObjectType::File,
300                fidl_fuchsia_io::FscryptPolicyFlags::empty(),
301            )
302            .await
303            .expect_err("create_key_with_id should fail if the wrapping key does not exist");
304
305        let wrapping_key = vec![0xABu8; 32];
306        service.add_wrapping_key(2, wrapping_key.clone()).expect("add_key failed");
307
308        let (wrapped_key, unwrapped_key) = service
309            .create_key_with_id(
310                0,
311                2,
312                ObjectType::File,
313                fidl_fuchsia_io::FscryptPolicyFlags::empty(),
314            )
315            .await
316            .expect("create_key_with_id failed");
317        let unwrap_result = service.unwrap_key(0, wrapped_key).await.expect("unwrap_key failed");
318        assert_eq!(unwrap_result, unwrapped_key);
319    }
320
321    #[fuchsia::test]
322    async fn unwrap_key_wrong_key() {
323        let service = CryptService::new();
324        let key = vec![0xABu8; 32];
325        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
326        service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
327
328        let (wrapping_key_id, mut wrapped_key, _) =
329            service.create_key(0, KeyPurpose::Data).await.expect("create_key failed");
330        for byte in &mut wrapped_key {
331            *byte ^= 0xff;
332        }
333        service
334            .unwrap_key(
335                0,
336                WrappedKey::Fxfs(FxfsKey {
337                    wrapping_key_id,
338                    wrapped_key: wrapped_key.try_into().unwrap(),
339                }),
340            )
341            .await
342            .expect_err("unwrap_key should fail");
343    }
344
345    #[fuchsia::test]
346    async fn unwrap_key_wrong_owner() {
347        let service = CryptService::new();
348        let key = vec![0xABu8; 32];
349        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
350        service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
351
352        let (wrapping_key_id, wrapped_key, _) =
353            service.create_key(0, KeyPurpose::Data).await.expect("create_key failed");
354        service
355            .unwrap_key(
356                1,
357                WrappedKey::Fxfs(FxfsKey {
358                    wrapping_key_id,
359                    wrapped_key: wrapped_key.try_into().unwrap(),
360                }),
361            )
362            .await
363            .expect_err("unwrap_key should fail");
364    }
365
366    #[test]
367    fn add_forget_key() {
368        let service = CryptService::new();
369        let key = vec![0xABu8; 32];
370        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
371        service.add_wrapping_key(0, key.clone()).expect_err("add_key should fail on a used slot");
372        service.add_wrapping_key(1, key.clone()).expect("add_key failed");
373
374        service.forget_wrapping_key(0).expect("forget_key failed");
375
376        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
377    }
378
379    #[test]
380    fn set_active_key() {
381        let service = CryptService::new();
382        let key = vec![0xABu8; 32];
383
384        service
385            .set_active_key(KeyPurpose::Data, 0)
386            .expect_err("set_active_key should fail when targeting nonexistent keys");
387
388        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
389        service.add_wrapping_key(1, key.clone()).expect("add_key failed");
390
391        service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
392        service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
393
394        service.forget_wrapping_key(0).expect_err("forget_key should fail on an active key");
395        service.forget_wrapping_key(1).expect_err("forget_key should fail on an active key");
396    }
397}