1 // Copyright 2023 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 //! NP Rust FFI structures and methods for V0 advertisement serialization.
15
16 use crate::common::*;
17 use crate::credentials::V0BroadcastCredential;
18 use crate::serialize::AdvertisementBuilderKind;
19 use crate::utils::FfiEnum;
20 use crate::v0::V0DataElement;
21 use crypto_provider_default::CryptoProviderImpl;
22 use handle_map::{declare_handle_map, HandleLike, HandleMapFullError};
23 use np_adv_dynamic::legacy::BoxedAdvConstructionError;
24
25 /// A handle to a builder for V0 advertisements.
26 #[derive(Clone, Copy)]
27 #[repr(C)]
28 pub struct V0AdvertisementBuilder {
29 kind: AdvertisementBuilderKind,
30 handle: V0AdvertisementBuilderHandle,
31 }
32
33 impl V0AdvertisementBuilder {
34 /// Gets the kind of advertisement builder (public/encrypted).
kind(&self) -> AdvertisementBuilderKind35 pub fn kind(&self) -> AdvertisementBuilderKind {
36 self.kind
37 }
38
39 /// Attempts to add the given data element to the V0 advertisement builder behind this handle.
40 /// This function does not take ownership of the handle.
add_de(&self, de: V0DataElement) -> Result<AddV0DEResult, InvalidStackDataStructure>41 pub fn add_de(&self, de: V0DataElement) -> Result<AddV0DEResult, InvalidStackDataStructure> {
42 match self.handle.get_mut() {
43 Ok(mut adv_builder_write_guard) => adv_builder_write_guard.add_de(de),
44 Err(_) => Ok(AddV0DEResult::InvalidAdvertisementBuilderHandle),
45 }
46 }
47 /// Attempts to serialize the contents of the advertisement builder behind this handle to
48 /// bytes. This function takes ownership of the handle.
into_advertisement(self) -> SerializeV0AdvertisementResult49 pub fn into_advertisement(self) -> SerializeV0AdvertisementResult {
50 match self.handle.deallocate() {
51 Ok(adv_builder) => adv_builder.into_advertisement(),
52 Err(_) => SerializeV0AdvertisementResult::InvalidAdvertisementBuilderHandle,
53 }
54 }
55 /// Attempts to deallocate the V0 advertisement builder behind this handle. This function takes
56 /// ownership of the handle.
deallocate(self) -> DeallocateResult57 pub fn deallocate(self) -> DeallocateResult {
58 self.handle.deallocate().map(|_| ()).into()
59 }
60 }
61
62 /// Discriminant for `CreateV0AdvertisementBuilderResult`
63 #[derive(Copy, Clone)]
64 #[repr(u8)]
65 pub enum CreateV0AdvertisementBuilderResultKind {
66 /// The attempt to create a new advertisement builder
67 /// failed since there are no more available
68 /// slots for V0 advertisement builders in their handle-map.
69 NoSpaceLeft = 0,
70 /// The attempt succeeded. The wrapped advertisement builder
71 /// may be obtained via
72 /// `CreateV0AdvertisementBuilderResult#into_success`.
73 Success = 1,
74 }
75
76 /// The result of attempting to create a new V0 advertisement builder.
77 #[repr(C)]
78 #[allow(missing_docs)]
79 pub enum CreateV0AdvertisementBuilderResult {
80 NoSpaceLeft,
81 Success(V0AdvertisementBuilder),
82 }
83
84 impl From<Result<V0AdvertisementBuilder, HandleMapFullError>>
85 for CreateV0AdvertisementBuilderResult
86 {
from(result: Result<V0AdvertisementBuilder, HandleMapFullError>) -> Self87 fn from(result: Result<V0AdvertisementBuilder, HandleMapFullError>) -> Self {
88 match result {
89 Ok(builder) => CreateV0AdvertisementBuilderResult::Success(builder),
90 Err(_) => CreateV0AdvertisementBuilderResult::NoSpaceLeft,
91 }
92 }
93 }
94
95 impl FfiEnum for CreateV0AdvertisementBuilderResult {
96 type Kind = CreateV0AdvertisementBuilderResultKind;
kind(&self) -> Self::Kind97 fn kind(&self) -> Self::Kind {
98 match self {
99 CreateV0AdvertisementBuilderResult::NoSpaceLeft => {
100 CreateV0AdvertisementBuilderResultKind::NoSpaceLeft
101 }
102 CreateV0AdvertisementBuilderResult::Success(_) => {
103 CreateV0AdvertisementBuilderResultKind::Success
104 }
105 }
106 }
107 }
108
109 impl CreateV0AdvertisementBuilderResult {
110 declare_enum_cast! {into_success, Success, V0AdvertisementBuilder }
111 }
112
113 /// Creates a new V0 advertisement builder for a public advertisement. The caller is given
114 /// ownership of the created handle.
create_v0_public_advertisement_builder() -> CreateV0AdvertisementBuilderResult115 pub fn create_v0_public_advertisement_builder() -> CreateV0AdvertisementBuilderResult {
116 V0AdvertisementBuilderHandle::allocate(V0AdvertisementBuilderInternals::new_public)
117 .map(|handle| V0AdvertisementBuilder { kind: AdvertisementBuilderKind::Public, handle })
118 .into()
119 }
120
121 /// Creates a new V0 advertisement builder for an encrypted advertisement. The caller is given
122 /// ownership of the created handle.
create_v0_encrypted_advertisement_builder( broadcast_cred: V0BroadcastCredential, salt: FixedSizeArray<2>, ) -> CreateV0AdvertisementBuilderResult123 pub fn create_v0_encrypted_advertisement_builder(
124 broadcast_cred: V0BroadcastCredential,
125 salt: FixedSizeArray<2>,
126 ) -> CreateV0AdvertisementBuilderResult {
127 V0AdvertisementBuilderHandle::allocate(move || {
128 V0AdvertisementBuilderInternals::new_ldt(broadcast_cred, salt.into_array())
129 })
130 .map(|handle| V0AdvertisementBuilder { kind: AdvertisementBuilderKind::Encrypted, handle })
131 .into()
132 }
133
134 /// Discriminant for `SerializeV0AdvertisementResult`.
135 #[repr(u8)]
136 pub enum SerializeV0AdvertisementResultKind {
137 /// Serializing the advertisement to bytes was successful.
138 Success = 0,
139 /// The advertisement builder handle was invalid.
140 InvalidAdvertisementBuilderHandle = 1,
141 /// Serializing the advertisement to bytes failed
142 /// because the data in the advertisement wasn't
143 /// of an appropriate size for LDT encryption
144 /// to succeed.
145 LdtError = 2,
146 /// Serializing an unencrypted adv failed because the adv data didn't meet the length
147 /// requirements.
148 UnencryptedError = 3,
149 }
150
151 /// The result of attempting to serialize the contents
152 /// of a V0 advertisement builder to raw bytes.
153 #[repr(C)]
154 #[allow(missing_docs)]
155 pub enum SerializeV0AdvertisementResult {
156 Success(ByteBuffer<24>),
157 InvalidAdvertisementBuilderHandle,
158 LdtError,
159 UnencryptedError,
160 }
161
162 impl SerializeV0AdvertisementResult {
163 declare_enum_cast! { into_success, Success, ByteBuffer<24> }
164 }
165
166 impl FfiEnum for SerializeV0AdvertisementResult {
167 type Kind = SerializeV0AdvertisementResultKind;
kind(&self) -> SerializeV0AdvertisementResultKind168 fn kind(&self) -> SerializeV0AdvertisementResultKind {
169 match self {
170 Self::Success(_) => SerializeV0AdvertisementResultKind::Success,
171 Self::InvalidAdvertisementBuilderHandle => {
172 SerializeV0AdvertisementResultKind::InvalidAdvertisementBuilderHandle
173 }
174 Self::LdtError => SerializeV0AdvertisementResultKind::LdtError,
175 Self::UnencryptedError => SerializeV0AdvertisementResultKind::UnencryptedError,
176 }
177 }
178 }
179
180 /// Internal Rust-side implementation of a V0 advertisement builder.
181 pub struct V0AdvertisementBuilderInternals {
182 adv_builder: np_adv_dynamic::legacy::BoxedAdvBuilder<CryptoProviderImpl>,
183 }
184
185 impl V0AdvertisementBuilderInternals {
new_public() -> Self186 pub(crate) fn new_public() -> Self {
187 Self::new(np_adv::legacy::serialize::UnencryptedEncoder.into())
188 }
new_ldt(broadcast_cred: V0BroadcastCredential, salt: [u8; 2]) -> Self189 pub(crate) fn new_ldt(broadcast_cred: V0BroadcastCredential, salt: [u8; 2]) -> Self {
190 // TODO: What do about salts? Need to prevent re-use fo the same salt,
191 // but have no current rich representation of used salts...
192 let salt = ldt_np_adv::V0Salt::from(salt);
193 let internal_broadcast_cred = broadcast_cred.into_internal();
194 let identity = np_adv::legacy::serialize::LdtEncoder::new(salt, &internal_broadcast_cred);
195 Self::new(identity.into())
196 }
new(encoder: np_adv_dynamic::legacy::BoxedEncoder<CryptoProviderImpl>) -> Self197 fn new(encoder: np_adv_dynamic::legacy::BoxedEncoder<CryptoProviderImpl>) -> Self {
198 let adv_builder =
199 np_adv_dynamic::legacy::BoxedAdvBuilder::<CryptoProviderImpl>::new(encoder);
200 Self { adv_builder }
201 }
add_de(&mut self, de: V0DataElement) -> Result<AddV0DEResult, InvalidStackDataStructure>202 fn add_de(&mut self, de: V0DataElement) -> Result<AddV0DEResult, InvalidStackDataStructure> {
203 let to_boxed = np_adv_dynamic::legacy::ToBoxedSerializeDataElement::try_from(de)?;
204 use np_adv::legacy::serialize::AddDataElementError;
205 use np_adv_dynamic::legacy::BoxedAddDataElementError;
206 match self.adv_builder.add_data_element(to_boxed) {
207 Ok(_) => Ok(AddV0DEResult::Success),
208 Err(BoxedAddDataElementError::FlavorMismatchError) => {
209 Ok(AddV0DEResult::InvalidIdentityTypeForDataElement)
210 }
211 Err(BoxedAddDataElementError::UnderlyingError(
212 AddDataElementError::InsufficientAdvSpace,
213 )) => Ok(AddV0DEResult::InsufficientAdvertisementSpace),
214 }
215 }
into_advertisement(self) -> SerializeV0AdvertisementResult216 fn into_advertisement(self) -> SerializeV0AdvertisementResult {
217 self.adv_builder
218 .into_advertisement()
219 .map(|serialized_bytes| {
220 SerializeV0AdvertisementResult::Success(ByteBuffer::from_array_view(
221 serialized_bytes,
222 ))
223 })
224 .unwrap_or_else(|e| match e {
225 BoxedAdvConstructionError::Ldt(_) => SerializeV0AdvertisementResult::LdtError,
226 BoxedAdvConstructionError::Unencrypted(_) => {
227 SerializeV0AdvertisementResult::UnencryptedError
228 }
229 })
230 }
231 }
232
233 /// A `#[repr(C)]` handle to a value of type `V0AdvertisementBuilderInternals`
234 #[repr(C)]
235 #[derive(Clone, Copy, PartialEq, Eq)]
236 struct V0AdvertisementBuilderHandle {
237 handle_id: u64,
238 }
239
240 declare_handle_map!(
241 advertisement_builder,
242 crate::common::default_handle_map_dimensions(),
243 super::V0AdvertisementBuilderHandle,
244 super::V0AdvertisementBuilderInternals
245 );
246
247 /// Result code for the operation of adding a DE to a V0
248 /// advertisement builder.
249 #[derive(Clone, Copy)]
250 #[repr(u8)]
251 pub enum AddV0DEResult {
252 /// The DE was successfully added to the advertisement builder
253 /// behind the given handle.
254 Success = 0,
255 /// The handle for the advertisement builder was invalid.
256 InvalidAdvertisementBuilderHandle = 1,
257 /// There was not enough available space left in the advertisement
258 /// to append the given data element.
259 InsufficientAdvertisementSpace = 2,
260 /// The passed data element is not broadcastable under the
261 /// identity type of the advertisement (public/private).
262 InvalidIdentityTypeForDataElement = 3,
263 }
264
265 impl From<np_adv_dynamic::legacy::BoxedAddDataElementError> for AddV0DEResult {
from(err: np_adv_dynamic::legacy::BoxedAddDataElementError) -> Self266 fn from(err: np_adv_dynamic::legacy::BoxedAddDataElementError) -> Self {
267 use np_adv_dynamic::legacy::BoxedAddDataElementError;
268 match err {
269 BoxedAddDataElementError::UnderlyingError(_) => Self::InsufficientAdvertisementSpace,
270 BoxedAddDataElementError::FlavorMismatchError => {
271 Self::InvalidIdentityTypeForDataElement
272 }
273 }
274 }
275 }
276