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