aurora/
lib.rs

1#![deny(unexpected_cfgs)]
2
3#[macro_use]
4extern crate log;
5
6pub(crate) use ::function_name::named;
7use std::ffi::{CStr, CString};
8use std::sync::LazyLock;
9
10pub type Error = anyhow::Error;
11
12macro_rules! function_path {
13    () => {
14        concat!(module_path!(), "::", function_name!(), "()")
15    };
16}
17
18macro_rules! log_target {
19    () => {
20        function_path!()
21    };
22}
23
24pub(crate) mod adapters;
25pub(crate) mod forge;
26mod init;
27mod query;
28pub(crate) mod random;
29
30pub(crate) mod asn_definitions;
31
32#[cfg(test)]
33pub(crate) mod tests;
34
35use bindings::dispatch_table_entry;
36use bindings::OSSL_PARAM;
37use bindings::{
38    OSSL_FUNC_provider_get_capabilities_fn, OSSL_FUNC_provider_get_params_fn,
39    OSSL_FUNC_provider_gettable_params_fn, OSSL_FUNC_provider_query_operation_fn,
40    OSSL_FUNC_provider_teardown_fn, OSSL_DISPATCH, OSSL_FUNC_PROVIDER_GETTABLE_PARAMS,
41    OSSL_FUNC_PROVIDER_GET_CAPABILITIES, OSSL_FUNC_PROVIDER_GET_PARAMS,
42    OSSL_FUNC_PROVIDER_QUERY_OPERATION, OSSL_FUNC_PROVIDER_TEARDOWN, OSSL_PROV_PARAM_BUILDINFO,
43    OSSL_PROV_PARAM_NAME, OSSL_PROV_PARAM_VERSION,
44};
45use forge::{bindings, osslparams, upcalls};
46use osslparams::{OSSLParam, OSSLParamData, Utf8PtrData, OSSL_PARAM_END};
47use upcalls::traits::{CoreUpcaller, CoreUpcallerWithCoreHandle};
48use upcalls::OSSL_CORE_HANDLE;
49pub use upcalls::{CoreDispatch, CoreDispatchWithCoreHandle};
50
51/// This is an abstract representation of one Provider instance.
52/// Remember that a single provider module could be loaded multiple
53/// times within the same process, either in the same OpenSSL libctx or
54/// within different libctx's.
55///
56/// At the moment a single instance holds nothing of relevance, but in
57/// the future all the context which is specific to an instance should
58/// be encapsulated within it, so that different instances could have
59/// different configurations, and their own separate state.
60#[derive(Debug)]
61pub struct ProviderInstance<'a> {
62    pub data: [u8; 10],
63    core_handle: *const OSSL_CORE_HANDLE,
64    core_dispatch: CoreDispatch<'a>,
65    pub name: &'a str,
66    pub version: &'a str,
67    params: Vec<OSSLParam<'a>>,
68    param_array_ptr: Option<*mut [OSSL_PARAM]>,
69    pub(crate) adapters_ctx: adapters::FinalizedAdaptersHandle,
70}
71
72/// We implement the Drop trait to make it explicit when a provider
73/// instance is dropped: this should only happen after `teardown()` has
74/// been called.
75impl<'a> Drop for ProviderInstance<'a> {
76    #[named]
77    fn drop(&mut self) {
78        let tname = std::any::type_name_of_val(self);
79        let name = self.name;
80        trace!(
81            target: log_target!(),
82            "🗑️\tDropping {tname} named {name}",
83        )
84    }
85}
86
87pub static PROV_NAME: &str = env!("CARGO_PKG_NAME");
88pub static PROV_VER: &str = env!("CARGO_PKG_VERSION");
89pub static PROV_BUILDINFO: &str = env!("CARGO_GIT_DESCRIBE");
90
91impl<'a> ProviderInstance<'a> {
92    pub fn new(handle: *const OSSL_CORE_HANDLE, core_dispatch: CoreDispatch<'a>) -> Self {
93        let upcaller: CoreDispatchWithCoreHandle<'a> = (core_dispatch, handle).into();
94
95        let adapters_ctx = { adapters::FinalizedAdaptersHandle::new(&upcaller) };
96
97        let core_dispatch: CoreDispatch = upcaller.into();
98
99        Self {
100            data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
101            core_handle: handle,
102            core_dispatch,
103            name: PROV_NAME,
104            version: PROV_VER,
105            param_array_ptr: None,
106            params: vec![
107                OSSLParam::Utf8Ptr(Utf8PtrData::new_null(OSSL_PROV_PARAM_NAME)),
108                OSSLParam::Utf8Ptr(Utf8PtrData::new_null(OSSL_PROV_PARAM_VERSION)),
109                OSSLParam::Utf8Ptr(Utf8PtrData::new_null(OSSL_PROV_PARAM_BUILDINFO)),
110            ],
111            adapters_ctx,
112        }
113    }
114
115    /// Retrieve a heap allocated `OSSL_DISPATCH` table associated with this provider instance.
116    pub fn get_provider_dispatch(&mut self) -> *const OSSL_DISPATCH {
117        let ret = Box::new([
118            dispatch_table_entry!(
119                OSSL_FUNC_PROVIDER_TEARDOWN,
120                OSSL_FUNC_provider_teardown_fn,
121                crate::init::provider_teardown
122            ),
123            dispatch_table_entry!(
124                OSSL_FUNC_PROVIDER_GETTABLE_PARAMS,
125                OSSL_FUNC_provider_gettable_params_fn,
126                crate::init::gettable_params
127            ),
128            dispatch_table_entry!(
129                OSSL_FUNC_PROVIDER_GET_PARAMS,
130                OSSL_FUNC_provider_get_params_fn,
131                crate::init::get_params
132            ),
133            dispatch_table_entry!(
134                OSSL_FUNC_PROVIDER_QUERY_OPERATION,
135                OSSL_FUNC_provider_query_operation_fn,
136                crate::query::query_operation
137            ),
138            dispatch_table_entry!(
139                OSSL_FUNC_PROVIDER_GET_CAPABILITIES,
140                OSSL_FUNC_provider_get_capabilities_fn,
141                crate::query::get_capabilities
142            ),
143            OSSL_DISPATCH::END,
144        ]);
145        Box::into_raw(ret).cast()
146    }
147
148    fn get_params_array(&mut self) -> *const OSSL_PARAM {
149        // This is kind of like a poor man's std::sync::Once
150        let raw_ptr = match self.param_array_ptr {
151            Some(raw_ptr) => raw_ptr,
152            None => {
153                let slice = self
154                    .params
155                    .iter_mut()
156                    .map(|p| unsafe { *p.get_c_struct() })
157                    .chain(std::iter::once(OSSL_PARAM_END))
158                    .collect::<Vec<_>>()
159                    .into_boxed_slice();
160                let raw_ptr = Box::into_raw(slice);
161                self.param_array_ptr = Some(raw_ptr);
162                raw_ptr
163            }
164        };
165        raw_ptr.cast()
166    }
167
168    pub fn c_prov_name(&self) -> &CStr {
169        #[expect(clippy::let_and_return)]
170        static L: LazyLock<CString> = LazyLock::new(|| {
171            let _s = CString::new(crate::PROV_NAME).expect("Error parsing cPROV_NAME");
172            _s
173        });
174        L.as_ref()
175    }
176
177    pub fn c_prov_version(&self) -> &CStr {
178        #[expect(clippy::let_and_return)]
179        static L: LazyLock<CString> = LazyLock::new(|| {
180            let _s = CString::new(crate::PROV_VER).expect("Error parsing cPROV_VER");
181            _s
182        });
183        L.as_ref()
184    }
185
186    pub fn c_prov_buildinfo(&self) -> &CStr {
187        #[expect(clippy::let_and_return)]
188        static L: LazyLock<CString> = LazyLock::new(|| {
189            let _s = CString::new(crate::PROV_BUILDINFO).expect("Error parsing cPROV_BUILDINFO");
190            _s
191        });
192        L.as_ref()
193    }
194}
195
196impl<'a> TryFrom<*mut core::ffi::c_void> for &mut ProviderInstance<'a> {
197    type Error = Error;
198
199    #[named]
200    fn try_from(vctx: *mut core::ffi::c_void) -> Result<Self, Self::Error> {
201        trace!(target: log_target!(), "Called for {}",
202        "impl<'a> TryFrom<*mut core::ffi::c_void> for &mut ProviderInstance<'a>"
203        );
204        let provp = vctx as *mut ProviderInstance;
205        if provp.is_null() {
206            return Err(anyhow::anyhow!("vctx was null"));
207        }
208        Ok(unsafe { &mut *provp })
209    }
210}
211
212impl<'a> TryFrom<*mut core::ffi::c_void> for &ProviderInstance<'a> {
213    type Error = Error;
214
215    #[named]
216    fn try_from(vctx: *mut core::ffi::c_void) -> Result<Self, Self::Error> {
217        trace!(target: log_target!(), "Called for {}", "impl<'a> TryFrom<*mut core::ffi::c_void> for &ProviderInstance<'a>");
218        let r: &mut ProviderInstance<'a> = vctx.try_into()?;
219        Ok(r)
220    }
221}
222
223/// Match on a `Result`, evaluating to the wrapped value if it is `Ok` or
224/// returning `ERROR_RET` (which must already be defined) if it is `Err`.
225///
226/// This macro should be used in `extern "C"` functions that will be directly
227/// called by OpenSSL. In other functions, `Result`s should be handled in the
228/// usual Rust way.
229///
230/// If invoked with an `Err` value, this macro also calls [`log::error!`] to log
231/// the error.
232///
233/// Before invoking this macro, an identifier `ERROR_RET` must be in scope, and
234/// the type of its value must be the same as (or coercible to) the return type
235/// of the function in which `handleResult!` is being invoked.
236#[macro_export]
237macro_rules! handleResult {
238    ($e:expr) => { match ($e)
239        {
240            Ok(r) => r,
241            Err(e) => {
242                error!(target: log_target!(), "{:#?}", e);
243                return ERROR_RET;
244            }
245        }
246    };
247    //($e:expr, $errhandler:expr) => { match ($e)
248    //    {
249    //        Ok(r) => r,
250    //        Err(e) => {
251    //            errhandler
252    //        }
253    //    }
254    //};
255}
256
257impl CoreUpcaller for ProviderInstance<'_> {
258    fn fn_from_core_dispatch(&self, id: u32) -> Option<unsafe extern "C" fn()> {
259        self.core_dispatch.fn_from_core_dispatch(id)
260    }
261}
262
263impl CoreUpcallerWithCoreHandle for ProviderInstance<'_> {
264    fn get_core_handle(&self) -> *const OSSL_CORE_HANDLE {
265        self.core_handle
266    }
267}
268
269pub mod traits {
270    pub use super::upcalls::traits::{CoreUpcaller, CoreUpcallerWithCoreHandle};
271}