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 //! Credential-related data-types and functions
15
16 use crate::{panic, unwrap, PanicReason};
17 use core::slice;
18 use np_ffi_core::common::*;
19 use np_ffi_core::credentials::{
20 create_credential_book_from_slab, create_credential_slab, deallocate_credential_book,
21 deallocate_credential_slab, AddV0CredentialToSlabResult, AddV1CredentialToSlabResult,
22 CredentialBook, CredentialSlab, MatchedCredential, V0DiscoveryCredential,
23 V1DiscoveryCredential,
24 };
25 use np_ffi_core::declare_enum_cast;
26 use np_ffi_core::deserialize::DecryptedMetadata;
27 use np_ffi_core::deserialize::{
28 DecryptMetadataResult, DecryptMetadataResultKind, GetMetadataBufferPartsResult,
29 GetMetadataBufferPartsResultKind, MetadataBufferParts,
30 };
31 use np_ffi_core::utils::FfiEnum;
32
33 /// Allocates a new credential-book from the given slab, returning a handle
34 /// to the created object. The slab will be deallocated by this call.
35 #[no_mangle]
np_ffi_create_credential_book_from_slab( slab: CredentialSlab, ) -> CreateCredentialBookResult36 pub extern "C" fn np_ffi_create_credential_book_from_slab(
37 slab: CredentialSlab,
38 ) -> CreateCredentialBookResult {
39 create_credential_book_from_slab(slab).into()
40 }
41
42 /// Result type for `create_credential_book`
43 #[repr(u8)]
44 #[allow(missing_docs)]
45 pub enum CreateCredentialBookResult {
46 Success(CredentialBook) = 0,
47 InvalidSlabHandle = 2,
48 }
49
50 //TODO: unwrap allocation errors at the ffi-core layer and remove this, after design has been
51 // agreed upon
52 impl From<np_ffi_core::credentials::CreateCredentialBookResult> for CreateCredentialBookResult {
from(value: np_ffi_core::credentials::CreateCredentialBookResult) -> Self53 fn from(value: np_ffi_core::credentials::CreateCredentialBookResult) -> Self {
54 match value {
55 np_ffi_core::credentials::CreateCredentialBookResult::Success(v) => {
56 CreateCredentialBookResult::Success(v)
57 }
58 np_ffi_core::credentials::CreateCredentialBookResult::InvalidSlabHandle => {
59 CreateCredentialBookResult::InvalidSlabHandle
60 }
61 np_ffi_core::credentials::CreateCredentialBookResult::NoSpaceLeft => {
62 panic(PanicReason::ExceededMaxHandleAllocations)
63 }
64 }
65 }
66 }
67
68 /// Discriminant for `CreateCredentialBookResult`
69 #[repr(u8)]
70 pub enum CreateCredentialBookResultKind {
71 /// We created a new credential book behind the given handle.
72 /// The associated payload may be obtained via
73 /// `CreateCredentialBookResult#into_success()`.
74 Success = 0,
75 /// The slab that we tried to create a credential-book from
76 /// actually was an invalid handle.
77 InvalidSlabHandle = 1,
78 }
79
80 impl np_ffi_core::utils::FfiEnum for CreateCredentialBookResult {
81 type Kind = CreateCredentialBookResultKind;
kind(&self) -> Self::Kind82 fn kind(&self) -> Self::Kind {
83 match self {
84 CreateCredentialBookResult::Success(_) => CreateCredentialBookResultKind::Success,
85 CreateCredentialBookResult::InvalidSlabHandle => {
86 CreateCredentialBookResultKind::InvalidSlabHandle
87 }
88 }
89 }
90 }
91
92 impl CreateCredentialBookResult {
93 declare_enum_cast! {into_success, Success, CredentialBook}
94 }
95
96 /// Gets the tag of a `CreateCredentialBookResult` tagged enum.
97 #[no_mangle]
np_ffi_CreateCredentialBookResult_kind( result: CreateCredentialBookResult, ) -> CreateCredentialBookResultKind98 pub extern "C" fn np_ffi_CreateCredentialBookResult_kind(
99 result: CreateCredentialBookResult,
100 ) -> CreateCredentialBookResultKind {
101 result.kind()
102 }
103
104 /// Casts a `CreateCredentialBookResult` to the `SUCCESS` variant, panicking in the
105 /// case where the passed value is of a different enum variant.
106 #[no_mangle]
np_ffi_CreateCredentialBookResult_into_SUCCESS( result: CreateCredentialBookResult, ) -> CredentialBook107 pub extern "C" fn np_ffi_CreateCredentialBookResult_into_SUCCESS(
108 result: CreateCredentialBookResult,
109 ) -> CredentialBook {
110 unwrap(result.into_success(), PanicReason::EnumCastFailed)
111 }
112
113 /// Deallocates a credential-slab by its handle.
114 #[no_mangle]
np_ffi_deallocate_credential_slab( credential_slab: CredentialSlab, ) -> DeallocateResult115 pub extern "C" fn np_ffi_deallocate_credential_slab(
116 credential_slab: CredentialSlab,
117 ) -> DeallocateResult {
118 deallocate_credential_slab(credential_slab)
119 }
120
121 /// Deallocates a credential-book by its handle
122 #[no_mangle]
np_ffi_deallocate_credential_book( credential_book: CredentialBook, ) -> DeallocateResult123 pub extern "C" fn np_ffi_deallocate_credential_book(
124 credential_book: CredentialBook,
125 ) -> DeallocateResult {
126 deallocate_credential_book(credential_book)
127 }
128
129 /// Allocates a new credential-slab, returning a handle to the created object
130 #[no_mangle]
np_ffi_create_credential_slab() -> CredentialSlab131 pub extern "C" fn np_ffi_create_credential_slab() -> CredentialSlab {
132 unwrap(create_credential_slab().into_success(), PanicReason::ExceededMaxHandleAllocations)
133 }
134
135 /// Representation of a V0 credential that contains additional data to provide back to caller once it
136 /// is matched. The credential_id can be used by the caller to correlate it back to the full
137 /// credentials details.
138 #[repr(C)]
139 pub struct V0MatchableCredential {
140 discovery_cred: V0DiscoveryCredential,
141 matched_cred: FfiMatchedCredential,
142 }
143
144 /// Representation of a V1 credential that contains additional data to provide back to caller once it
145 /// is matched. The credential_id can be used by the caller to correlate it back to the full
146 /// credentials details.
147 #[repr(C)]
148 pub struct V1MatchableCredential {
149 discovery_cred: V1DiscoveryCredential,
150 matched_cred: FfiMatchedCredential,
151 }
152
153 /// A representation of a MatchedCredential which is passable across the FFI boundary
154 #[repr(C)]
155 pub struct FfiMatchedCredential {
156 cred_id: u32,
157 encrypted_metadata_bytes_buffer: *const u8,
158 encrypted_metadata_bytes_len: usize,
159 }
160
161 /// Adds the given V0 discovery credential with some associated
162 /// match-data to this credential slab.
163 ///
164 /// Safety: this is safe if the provided pointer points to a valid memory address
165 /// which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
166 /// so concurrent modification of the array from another thread would cause undefined behavior.
167 #[no_mangle]
np_ffi_CredentialSlab_add_v0_credential( credential_slab: CredentialSlab, v0_cred: V0MatchableCredential, ) -> AddV0CredentialToSlabResult168 pub extern "C" fn np_ffi_CredentialSlab_add_v0_credential(
169 credential_slab: CredentialSlab,
170 v0_cred: V0MatchableCredential,
171 ) -> AddV0CredentialToSlabResult {
172 #[allow(unsafe_code)]
173 let metadata_slice = unsafe {
174 slice::from_raw_parts(
175 v0_cred.matched_cred.encrypted_metadata_bytes_buffer,
176 v0_cred.matched_cred.encrypted_metadata_bytes_len,
177 )
178 };
179
180 let matched_credential = MatchedCredential::new(v0_cred.matched_cred.cred_id, metadata_slice);
181 credential_slab.add_v0(v0_cred.discovery_cred, matched_credential)
182 }
183
184 /// Adds the given V1 discovery credential with some associated
185 /// match-data to this credential slab.
186 ///
187 /// Safety: this is safe if the provided pointer points to a valid memory address
188 /// which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
189 /// so concurrent modification of the array from another thread would cause undefined behavior.
190 #[no_mangle]
np_ffi_CredentialSlab_add_v1_credential( credential_slab: CredentialSlab, v1_cred: V1MatchableCredential, ) -> AddV1CredentialToSlabResult191 pub extern "C" fn np_ffi_CredentialSlab_add_v1_credential(
192 credential_slab: CredentialSlab,
193 v1_cred: V1MatchableCredential,
194 ) -> AddV1CredentialToSlabResult {
195 #[allow(unsafe_code)]
196 let metadata_slice = unsafe {
197 slice::from_raw_parts(
198 v1_cred.matched_cred.encrypted_metadata_bytes_buffer,
199 v1_cred.matched_cred.encrypted_metadata_bytes_len,
200 )
201 };
202
203 let matched_credential = MatchedCredential::new(v1_cred.matched_cred.cred_id, metadata_slice);
204 credential_slab.add_v1(v1_cred.discovery_cred, matched_credential)
205 }
206
207 /// Frees the underlying resources of the decrypted metadata buffer
208 #[no_mangle]
np_ffi_deallocate_DecryptedMetadata( metadata: DecryptedMetadata, ) -> DeallocateResult209 pub extern "C" fn np_ffi_deallocate_DecryptedMetadata(
210 metadata: DecryptedMetadata,
211 ) -> DeallocateResult {
212 metadata.deallocate_metadata()
213 }
214
215 /// Gets the tag of a `DecryptMetadataResult` tagged-union. On success the wrapped identity
216 /// details may be obtained via `DecryptMetadataResult#into_success`.
217 #[no_mangle]
np_ffi_DecryptMetadataResult_kind( result: DecryptMetadataResult, ) -> DecryptMetadataResultKind218 pub extern "C" fn np_ffi_DecryptMetadataResult_kind(
219 result: DecryptMetadataResult,
220 ) -> DecryptMetadataResultKind {
221 result.kind()
222 }
223
224 /// Casts a `DecryptMetadataResult` to the `Success` variant, panicking in the
225 /// case where the passed value is of a different enum variant.
226 #[no_mangle]
np_ffi_DecryptMetadataResult_into_SUCCESS( result: DecryptMetadataResult, ) -> DecryptedMetadata227 pub extern "C" fn np_ffi_DecryptMetadataResult_into_SUCCESS(
228 result: DecryptMetadataResult,
229 ) -> DecryptedMetadata {
230 unwrap(result.into_success(), PanicReason::EnumCastFailed)
231 }
232
233 /// Gets the pointer and length of the heap allocated byte buffer of decrypted metadata
234 #[no_mangle]
np_ffi_DecryptedMetadata_get_metadata_buffer_parts( metadata: DecryptedMetadata, ) -> GetMetadataBufferPartsResult235 pub extern "C" fn np_ffi_DecryptedMetadata_get_metadata_buffer_parts(
236 metadata: DecryptedMetadata,
237 ) -> GetMetadataBufferPartsResult {
238 metadata.get_metadata_buffer_parts()
239 }
240
241 /// Gets the tag of a `GetMetadataBufferPartsResult` tagged-union. On success the wrapped identity
242 /// details may be obtained via `GetMetadataBufferPartsResult#into_success`.
243 #[no_mangle]
np_ffi_GetMetadataBufferPartsResult_kind( result: GetMetadataBufferPartsResult, ) -> GetMetadataBufferPartsResultKind244 pub extern "C" fn np_ffi_GetMetadataBufferPartsResult_kind(
245 result: GetMetadataBufferPartsResult,
246 ) -> GetMetadataBufferPartsResultKind {
247 result.kind()
248 }
249
250 /// Casts a `GetMetadataBufferPartsResult` to the `Success` variant, panicking in the
251 /// case where the passed value is of a different enum variant. This returns the pointer and length
252 /// of the byte buffer containing the decrypted metadata. There can be a data-race between attempts
253 /// to access the contents of the buffer and attempts to free the handle from different threads.
254 #[no_mangle]
np_ffi_GetMetadataBufferPartsResult_into_SUCCESS( result: GetMetadataBufferPartsResult, ) -> MetadataBufferParts255 pub extern "C" fn np_ffi_GetMetadataBufferPartsResult_into_SUCCESS(
256 result: GetMetadataBufferPartsResult,
257 ) -> MetadataBufferParts {
258 unwrap(result.into_success(), PanicReason::EnumCastFailed)
259 }
260