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