1#![no_std]
15extern crate liboscore_cryptobackend;
17extern crate liboscore_msgbackend;
18
19use core::mem::MaybeUninit;
20
21mod platform;
22
23pub mod raw;
25
26mod impl_message;
27pub use impl_message::ProtectedMessage;
28
29mod oscore_option;
30pub use oscore_option::OscoreOption;
31
32mod algorithms;
33pub use algorithms::{AeadAlg, AlgorithmNotSupported, HkdfAlg};
34
35mod primitive;
36pub use primitive::{DeriveError, PrimitiveContext, PrimitiveImmutables};
37
38#[track_caller]
39#[inline]
40fn poll_once_expect_immediate<R>(future: impl core::future::Future<Output = R>) -> R {
41 let future = core::pin::pin!(future);
42 let mut context = core::task::Context::from_waker(core::task::Waker::noop());
43 match future.poll(&mut context) {
44 core::task::Poll::Ready(r) => r,
45 core::task::Poll::Pending => unreachable!("The function's only await point is in the callback, and the provided callback has none."),
46 }
47}
48
49#[non_exhaustive]
50#[derive(Debug, Copy, Clone)]
51pub enum PrepareError {
52 SecurityContextUnavailable,
54}
55
56impl PrepareError {
57 fn new(input: raw::oscore_prepare_result) -> Result<(), Self> {
61 match input {
62 raw::oscore_prepare_result_OSCORE_PREPARE_OK => Ok(()),
63 raw::oscore_prepare_result_OSCORE_PREPARE_SECCTX_UNAVAILABLE => {
64 Err(PrepareError::SecurityContextUnavailable)
65 }
66 _ => unreachable!(),
67 }
68 }
69}
70
71#[non_exhaustive]
72#[derive(Debug, Copy, Clone)]
73pub enum FinishError {
74 Size,
75 Crypto,
76}
77
78impl FinishError {
79 fn new(input: raw::oscore_finish_result) -> Result<(), Self> {
83 match input {
84 raw::oscore_finish_result_OSCORE_FINISH_OK => Ok(()),
85 raw::oscore_finish_result_OSCORE_FINISH_ERROR_SIZE => Err(FinishError::Size),
86 raw::oscore_finish_result_OSCORE_FINISH_ERROR_CRYPTO => Err(FinishError::Crypto),
87 _ => unreachable!(),
88 }
89 }
90}
91
92#[derive(Debug, Copy, Clone)]
93pub enum ProtectError {
94 Prepare(PrepareError),
95 Finish(FinishError),
96}
97
98impl From<PrepareError> for ProtectError {
99 fn from(e: PrepareError) -> Self {
100 ProtectError::Prepare(e)
101 }
102}
103
104impl From<FinishError> for ProtectError {
105 fn from(e: FinishError) -> Self {
106 ProtectError::Finish(e)
107 }
108}
109
110#[non_exhaustive]
111#[derive(Debug, Copy, Clone)]
112pub enum UnprotectRequestError {
113 Duplicate,
114 Invalid,
115}
116
117impl UnprotectRequestError {
118 fn new(input: raw::oscore_unprotect_request_result) -> Result<(), Self> {
122 match input {
123 raw::oscore_unprotect_request_result_OSCORE_UNPROTECT_REQUEST_OK => Ok(()),
124 raw::oscore_unprotect_request_result_OSCORE_UNPROTECT_REQUEST_DUPLICATE => {
125 Err(UnprotectRequestError::Duplicate)
126 }
127 raw::oscore_unprotect_request_result_OSCORE_UNPROTECT_REQUEST_INVALID => {
128 Err(UnprotectRequestError::Invalid)
129 }
130 _ => unreachable!(),
131 }
132 }
133}
134
135#[non_exhaustive]
136#[derive(Debug, Copy, Clone)]
137pub enum UnprotectResponseError {
138 Invalid,
139}
140
141impl UnprotectResponseError {
142 fn new(input: raw::oscore_unprotect_response_result) -> Result<(), Self> {
146 match input {
147 raw::oscore_unprotect_response_result_OSCORE_UNPROTECT_RESPONSE_OK => Ok(()),
148 raw::oscore_unprotect_response_result_OSCORE_UNPROTECT_RESPONSE_INVALID => {
149 Err(UnprotectResponseError::Invalid)
150 }
151 _ => unreachable!(),
152 }
153 }
154}
155
156pub async fn async_protect_request<R>(
168 request: impl liboscore_msgbackend::WithMsgNative,
169 ctx: &mut PrimitiveContext,
170 writer: impl AsyncFnOnce(&mut ProtectedMessage) -> R,
171) -> Result<(raw::oscore_requestid_t, R), ProtectError> {
172 request
173 .async_with_msg_native(async |msg| {
174 let mut plaintext = MaybeUninit::uninit();
175 let mut request_data = MaybeUninit::uninit();
176 let prepare_ok = unsafe {
178 raw::oscore_prepare_request(
179 msg,
180 plaintext.as_mut_ptr(),
181 ctx.as_mut(),
182 request_data.as_mut_ptr(),
183 )
184 };
185 PrepareError::new(prepare_ok)?;
186 let plaintext = unsafe { plaintext.assume_init() };
188 let request_data = unsafe { request_data.assume_init() };
189
190 let mut plaintext = crate::ProtectedMessage::new(plaintext);
191 let user_carry = writer(&mut plaintext).await;
192 plaintext.flush();
193 let mut plaintext = plaintext.into_inner();
194
195 let mut returned_msg = MaybeUninit::uninit();
196 let finish_ok =
198 unsafe { raw::oscore_encrypt_message(&mut plaintext, returned_msg.as_mut_ptr()) };
199 FinishError::new(finish_ok)?;
200 Ok((request_data, user_carry))
205 })
206 .await
207}
208
209pub fn protect_request<R>(
211 request: impl liboscore_msgbackend::WithMsgNative,
212 ctx: &mut PrimitiveContext,
213 writer: impl FnOnce(&mut ProtectedMessage) -> R,
214) -> Result<(raw::oscore_requestid_t, R), ProtectError> {
215 poll_once_expect_immediate(async_protect_request(request, ctx, async |m| writer(m)))
216}
217
218pub async fn async_unprotect_request<R>(
230 request: impl liboscore_msgbackend::WithMsgNative,
231 oscoreoption: OscoreOption<'_>, ctx: &mut PrimitiveContext,
238 reader: impl AsyncFnOnce(&ProtectedMessage) -> R,
239) -> Result<(raw::oscore_requestid_t, R), UnprotectRequestError> {
240 request
241 .async_with_msg_native(async |nativemsg| {
242 let mut plaintext = MaybeUninit::uninit();
243 let mut request_data = MaybeUninit::uninit();
244 let decrypt_ok = unsafe {
245 raw::oscore_unprotect_request(
246 nativemsg,
247 plaintext.as_mut_ptr(),
248 &oscoreoption.into_inner(),
249 ctx.as_mut(),
250 request_data.as_mut_ptr(),
251 )
252 };
253 UnprotectRequestError::new(decrypt_ok)?;
256
257 let plaintext = unsafe { plaintext.assume_init() };
258 let request_data = unsafe { request_data.assume_init() };
259
260 let plaintext = ProtectedMessage::new(plaintext);
261
262 let user_data = reader(&plaintext).await;
263
264 unsafe { raw::oscore_release_unprotected(&mut plaintext.into_inner()) };
265
266 Ok((request_data, user_data))
267 })
268 .await
269}
270
271pub fn unprotect_request<R>(
273 request: impl liboscore_msgbackend::WithMsgNative,
274 oscoreoption: OscoreOption<'_>,
275 ctx: &mut PrimitiveContext,
276 reader: impl FnOnce(&ProtectedMessage) -> R,
277) -> Result<(raw::oscore_requestid_t, R), UnprotectRequestError> {
278 poll_once_expect_immediate(async_unprotect_request(
279 request,
280 oscoreoption,
281 ctx,
282 async |m| reader(m),
283 ))
284}
285
286pub async fn async_protect_response<R>(
295 response: impl liboscore_msgbackend::WithMsgNative,
296 ctx: &mut PrimitiveContext,
297 correlation: &mut raw::oscore_requestid_t,
298 writer: impl AsyncFnOnce(&mut ProtectedMessage) -> R,
299) -> Result<R, ProtectError> {
300 response
301 .async_with_msg_native(async |nativemsg| {
302 let mut plaintext = MaybeUninit::uninit();
303 let prepare_ok = unsafe {
305 raw::oscore_prepare_response(
306 nativemsg,
307 plaintext.as_mut_ptr(),
308 ctx.as_mut(),
309 correlation,
310 )
311 };
312 PrepareError::new(prepare_ok)?;
313 let plaintext = unsafe { plaintext.assume_init() };
315
316 let mut plaintext = crate::ProtectedMessage::new(plaintext);
317 let user_data = writer(&mut plaintext).await;
318 plaintext.flush();
319 let mut plaintext = plaintext.into_inner();
320
321 let mut returned_msg = MaybeUninit::uninit();
322 let finish_ok =
324 unsafe { raw::oscore_encrypt_message(&mut plaintext, returned_msg.as_mut_ptr()) };
325 FinishError::new(finish_ok)?;
326 Ok(user_data)
331 })
332 .await
333}
334
335pub fn protect_response<R>(
337 response: impl liboscore_msgbackend::WithMsgNative,
338 ctx: &mut PrimitiveContext,
339 correlation: &mut raw::oscore_requestid_t,
340 writer: impl FnOnce(&mut ProtectedMessage) -> R,
341) -> Result<R, ProtectError> {
342 poll_once_expect_immediate(async_protect_response(
343 response,
344 ctx,
345 correlation,
346 async |m| writer(m),
347 ))
348}
349
350pub async fn async_unprotect_response<R>(
364 response: impl liboscore_msgbackend::WithMsgNative,
365 ctx: &mut PrimitiveContext,
366 oscoreoption: OscoreOption<'_>,
367 correlation: &mut raw::oscore_requestid_t,
368 reader: impl AsyncFnOnce(&ProtectedMessage) -> R,
369) -> Result<R, UnprotectResponseError> {
370 response
371 .async_with_msg_native(async |nativemsg| {
372 let mut plaintext = MaybeUninit::uninit();
373 let decrypt_ok = unsafe {
374 raw::oscore_unprotect_response(
375 nativemsg,
376 plaintext.as_mut_ptr(),
377 &oscoreoption.into_inner(),
378 ctx.as_mut(),
379 correlation,
380 )
381 };
382 UnprotectResponseError::new(decrypt_ok)?;
383
384 let plaintext = unsafe { plaintext.assume_init() };
385
386 let plaintext = ProtectedMessage::new(plaintext);
387
388 let user_data = reader(&plaintext).await;
389
390 unsafe { raw::oscore_release_unprotected(&mut plaintext.into_inner()) };
391
392 Ok(user_data)
393 })
394 .await
395}
396
397pub fn unprotect_response<R>(
399 response: impl liboscore_msgbackend::WithMsgNative,
400 ctx: &mut PrimitiveContext,
401 oscoreoption: OscoreOption<'_>,
402 correlation: &mut raw::oscore_requestid_t,
403 reader: impl FnOnce(&ProtectedMessage) -> R,
404) -> Result<R, UnprotectResponseError> {
405 poll_once_expect_immediate(async_unprotect_response(
406 response,
407 ctx,
408 oscoreoption,
409 correlation,
410 async |m| reader(m),
411 ))
412}