1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //! Core NP Rust FFI structures and methods for advertisement deserialization.
15 
16 use crate::common::*;
17 use crate::credentials::CredentialBook;
18 use crate::deserialize::v0::*;
19 use crate::deserialize::v1::*;
20 use crate::utils::FfiEnum;
21 use crypto_provider_default::CryptoProviderImpl;
22 use handle_map::{declare_handle_map, HandleLike, HandleMapFullError, HandleNotPresentError};
23 use np_adv::deserialization_arena;
24 
25 pub mod v0;
26 pub mod v1;
27 
28 /// Discriminant for `DeserializeAdvertisementResult`.
29 #[repr(u8)]
30 pub enum DeserializeAdvertisementResultKind {
31     /// Deserializing the advertisement failed, for some reason or another.
32     Error = 0,
33     /// The advertisement was correctly deserialized, and it's a V0 advertisement.
34     /// `DeserializeAdvertisementResult#into_v0()` is the corresponding cast
35     /// to the associated enum variant.
36     V0 = 1,
37     /// The advertisement was correctly deserialized, and it's a V1 advertisement.
38     /// `DeserializeAdvertisementResult#into_v1()` is the corresponding cast
39     /// to the associated enum variant.
40     V1 = 2,
41 }
42 
43 /// The result of calling `np_ffi_deserialize_advertisement`.
44 /// Must be explicitly deallocated after use with
45 /// a corresponding `np_ffi_deallocate_deserialize_advertisement_result`
46 #[repr(u8)]
47 pub enum DeserializeAdvertisementResult {
48     /// Deserializing the advertisement failed, for some reason or another.
49     /// `DeserializeAdvertisementResultKind::Error` is the associated enum tag.
50     Error,
51     /// The advertisement was correctly deserialized, and it's a V0 advertisement.
52     /// `DeserializeAdvertisementResultKind::V0` is the associated enum tag.
53     V0(DeserializedV0Advertisement),
54     /// The advertisement was correctly deserialized, and it's a V1 advertisement.
55     /// `DeserializeAdvertisementResultKind::V1` is the associated enum tag.
56     V1(DeserializedV1Advertisement),
57 }
58 
59 impl FfiEnum for DeserializeAdvertisementResult {
60     type Kind = DeserializeAdvertisementResultKind;
kind(&self) -> Self::Kind61     fn kind(&self) -> Self::Kind {
62         match self {
63             DeserializeAdvertisementResult::Error => DeserializeAdvertisementResultKind::Error,
64             DeserializeAdvertisementResult::V0(_) => DeserializeAdvertisementResultKind::V0,
65             DeserializeAdvertisementResult::V1(_) => DeserializeAdvertisementResultKind::V1,
66         }
67     }
68 }
69 
70 impl DeserializeAdvertisementResult {
71     declare_enum_cast! {into_v0, V0, DeserializedV0Advertisement}
72     declare_enum_cast! {into_v1, V1, DeserializedV1Advertisement}
73 
74     /// Deallocates any internal data referenced by a `DeserializeAdvertisementResult`. This takes
75     /// ownership of any internal handles.
deallocate(self) -> DeallocateResult76     pub fn deallocate(self) -> DeallocateResult {
77         match self {
78             DeserializeAdvertisementResult::Error => DeallocateResult::Success,
79             DeserializeAdvertisementResult::V0(adv) => adv.deallocate(),
80             DeserializeAdvertisementResult::V1(adv) => adv.deallocate(),
81         }
82     }
83 }
84 
85 //TODO: Once the `FromResidual` trait is stabilized, we won't need to do this
86 enum DeserializeAdvertisementSuccess {
87     V0(DeserializedV0Advertisement),
88     V1(DeserializedV1Advertisement),
89 }
90 
91 pub(crate) struct DeserializeAdvertisementError;
92 
93 impl From<HandleMapFullError> for DeserializeAdvertisementError {
from(_: HandleMapFullError) -> Self94     fn from(_: HandleMapFullError) -> Self {
95         DeserializeAdvertisementError
96     }
97 }
98 
99 impl From<HandleNotPresentError> for DeserializeAdvertisementError {
from(_: HandleNotPresentError) -> Self100     fn from(_: HandleNotPresentError) -> Self {
101         DeserializeAdvertisementError
102     }
103 }
104 
105 impl From<np_adv::AdvDeserializationError> for DeserializeAdvertisementError {
from(_: np_adv::AdvDeserializationError) -> Self106     fn from(_: np_adv::AdvDeserializationError) -> Self {
107         DeserializeAdvertisementError
108     }
109 }
110 
deserialize_advertisement_from_slice_internal( adv_payload: &[u8], credential_book: CredentialBook, ) -> Result<DeserializeAdvertisementSuccess, DeserializeAdvertisementError>111 fn deserialize_advertisement_from_slice_internal(
112     adv_payload: &[u8],
113     credential_book: CredentialBook,
114 ) -> Result<DeserializeAdvertisementSuccess, DeserializeAdvertisementError> {
115     // Deadlock Safety: Credential-book locks always live longer than deserialized advs.
116     let credential_book_read_guard = credential_book.get()?;
117 
118     let cred_book = &credential_book_read_guard.book;
119 
120     let arena = deserialization_arena!();
121     let deserialized_advertisement =
122         np_adv::deserialize_advertisement::<_, CryptoProviderImpl>(arena, adv_payload, cred_book)?;
123     match deserialized_advertisement {
124         np_adv::DeserializedAdvertisement::V0(adv_contents) => {
125             let adv_handle = DeserializedV0Advertisement::allocate_with_contents(adv_contents)?;
126             Ok(DeserializeAdvertisementSuccess::V0(adv_handle))
127         }
128         np_adv::DeserializedAdvertisement::V1(adv_contents) => {
129             let adv_handle = DeserializedV1Advertisement::allocate_with_contents(adv_contents)?;
130             Ok(DeserializeAdvertisementSuccess::V1(adv_handle))
131         }
132     }
133 }
134 
135 /// Attempts to deserialize an advertisement with the given payload. Suitable for langs which have
136 /// a suitably expressive slice-type. This uses the given `credential_book` handle but does not
137 /// take ownership of it. The caller is given ownership of any handles in the returned structure.
deserialize_advertisement_from_slice( adv_payload: &[u8], credential_book: CredentialBook, ) -> DeserializeAdvertisementResult138 pub fn deserialize_advertisement_from_slice(
139     adv_payload: &[u8],
140     credential_book: CredentialBook,
141 ) -> DeserializeAdvertisementResult {
142     let result = deserialize_advertisement_from_slice_internal(adv_payload, credential_book);
143     match result {
144         Ok(DeserializeAdvertisementSuccess::V0(x)) => DeserializeAdvertisementResult::V0(x),
145         Ok(DeserializeAdvertisementSuccess::V1(x)) => DeserializeAdvertisementResult::V1(x),
146         Err(_) => DeserializeAdvertisementResult::Error,
147     }
148 }
149 
150 /// Attempts to deserialize an advertisement with the given payload.  Suitable for langs which
151 /// don't have an expressive-enough slice type. This uses the given `credential_book` handle but
152 /// does not take ownership of it. The caller is given ownership of any handles in the returned
153 /// structure.
deserialize_advertisement( adv_payload: &RawAdvertisementPayload, credential_book: CredentialBook, ) -> DeserializeAdvertisementResult154 pub fn deserialize_advertisement(
155     adv_payload: &RawAdvertisementPayload,
156     credential_book: CredentialBook,
157 ) -> DeserializeAdvertisementResult {
158     deserialize_advertisement_from_slice(adv_payload.as_slice(), credential_book)
159 }
160 
161 /// Errors returned from attempting to decrypt metadata
162 pub(crate) enum DecryptMetadataError {
163     /// The advertisement payload handle was either deallocated
164     /// or corresponds to a public advertisement, and so we
165     /// don't have any metadata to decrypt.
166     EncryptedMetadataNotAvailable,
167     /// Decryption of the raw metadata bytes failed.
168     DecryptionFailed,
169 }
170 
171 /// The result of decrypting metadata from either a V0Payload or DeserializedV1Section
172 #[repr(C)]
173 #[allow(missing_docs)]
174 pub enum DecryptMetadataResult {
175     Success(DecryptedMetadata),
176     Error,
177 }
178 
179 /// Discriminant for `DecryptMetadataResult`.
180 #[repr(u8)]
181 pub enum DecryptMetadataResultKind {
182     /// The attempt to decrypt the metadata of the associated credential succeeded
183     /// The associated payload may be obtained via
184     /// `DecryptMetadataResult#into_success`.
185     Success,
186     /// The attempt to decrypt the metadata failed, either the payload had no matching identity
187     /// ie it was a public advertisement OR the decrypt attempt itself was unsuccessful
188     Error,
189 }
190 
191 impl FfiEnum for DecryptMetadataResult {
192     type Kind = DecryptMetadataResultKind;
193 
kind(&self) -> Self::Kind194     fn kind(&self) -> Self::Kind {
195         match self {
196             DecryptMetadataResult::Success(_) => DecryptMetadataResultKind::Success,
197             DecryptMetadataResult::Error => DecryptMetadataResultKind::Error,
198         }
199     }
200 }
201 
202 impl DecryptMetadataResult {
203     declare_enum_cast! {into_success, Success, DecryptedMetadata}
204 }
205 
206 /// Internals of decrypted metadata
207 pub struct DecryptedMetadataInternals {
208     decrypted_bytes: Box<[u8]>,
209 }
210 
211 /// A `#[repr(C)]` handle to a value of type `DecryptedMetadataInternals`
212 #[repr(C)]
213 #[derive(Clone, Copy, PartialEq, Eq)]
214 pub struct DecryptedMetadata {
215     handle_id: u64,
216 }
217 
218 declare_handle_map!(
219     decrypted_metadata,
220     crate::common::default_handle_map_dimensions(),
221     super::DecryptedMetadata,
222     super::DecryptedMetadataInternals
223 );
224 
225 /// The pointer and length of the decrypted metadata byte buffer
226 #[repr(C)]
227 pub struct MetadataBufferParts {
228     ptr: *const u8,
229     len: usize,
230 }
231 
232 #[repr(C)]
233 #[allow(missing_docs)]
234 pub enum GetMetadataBufferPartsResult {
235     Success(MetadataBufferParts),
236     Error,
237 }
238 
239 impl GetMetadataBufferPartsResult {
240     declare_enum_cast! {into_success, Success, MetadataBufferParts}
241 }
242 
243 #[repr(u8)]
244 #[allow(missing_docs)]
245 pub enum GetMetadataBufferPartsResultKind {
246     Success = 0,
247     Error = 1,
248 }
249 
250 impl FfiEnum for GetMetadataBufferPartsResult {
251     type Kind = GetMetadataBufferPartsResultKind;
252 
kind(&self) -> Self::Kind253     fn kind(&self) -> Self::Kind {
254         match self {
255             GetMetadataBufferPartsResult::Success(_) => GetMetadataBufferPartsResultKind::Success,
256             GetMetadataBufferPartsResult::Error => GetMetadataBufferPartsResultKind::Error,
257         }
258     }
259 }
260 
allocate_decrypted_metadata_handle(metadata: Vec<u8>) -> DecryptMetadataResult261 fn allocate_decrypted_metadata_handle(metadata: Vec<u8>) -> DecryptMetadataResult {
262     let allocate_result = DecryptedMetadata::allocate(move || DecryptedMetadataInternals {
263         decrypted_bytes: metadata.into_boxed_slice(),
264     });
265     match allocate_result {
266         Ok(decrypted) => DecryptMetadataResult::Success(decrypted),
267         Err(_) => DecryptMetadataResult::Error,
268     }
269 }
270 
271 impl DecryptedMetadata {
272     /// Gets the raw parts, pointer + length representation of the metadata byte buffer. This uses
273     /// the handle but does not take ownership of it.
get_metadata_buffer_parts(&self) -> GetMetadataBufferPartsResult274     pub fn get_metadata_buffer_parts(&self) -> GetMetadataBufferPartsResult {
275         match self.get() {
276             Ok(metadata_internals) => {
277                 let result = MetadataBufferParts {
278                     ptr: metadata_internals.decrypted_bytes.as_ptr(),
279                     len: metadata_internals.decrypted_bytes.len(),
280                 };
281                 GetMetadataBufferPartsResult::Success(result)
282             }
283             Err(_) => GetMetadataBufferPartsResult::Error,
284         }
285     }
286 
287     /// Frees the underlying decrypted metadata buffer. This takes ownership of the handle.
deallocate_metadata(self) -> DeallocateResult288     pub fn deallocate_metadata(self) -> DeallocateResult {
289         self.deallocate().map(|_| ()).into()
290     }
291 }
292