diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..da70c8eb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] +members = [ + "parsec-openssl-sys2", + "parsec-openssl2", + "parsec-openssl-provider", + "parsec-openssl-provider-shared", +] diff --git a/ci.sh b/ci.sh index e704f6b8..ad53359c 100755 --- a/ci.sh +++ b/ci.sh @@ -7,3 +7,26 @@ set -ex echo "OpenSSL version being used:" openssl version + +# Build parsec provider shared library +pushd parsec-openssl-provider-shared/ && +cargo build +popd + +# Try loading the build parsec provider +provider_load_result=$(openssl list -providers -provider-path ./target/debug/ -provider libparsec_openssl_provider_shared) +echo $provider_load_result + +test_string='Providers: + libparsec_openssl_provider_shared + name: Parsec OpenSSL Provider + version: 0.1.0 + status: active' + +if [[ $test_string == $provider_load_result ]]; then + echo "Parsec OpenSSL Provider loaded successfully!!!!" + exit 0; +fi + +echo "Loaded Provider has unexpected parameters!!!!" +exit 1 diff --git a/parsec-openssl-provider-shared/Cargo.toml b/parsec-openssl-provider-shared/Cargo.toml new file mode 100644 index 00000000..51e04c4a --- /dev/null +++ b/parsec-openssl-provider-shared/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "parsec-openssl-provider-shared" +version = "0.1.0" +authors = ["Parsec Project Contributors"] +description = "A parsec openssl provider dynamic library" +license = "Apache-2.0" +readme = "README.md" +keywords = ["security", "service"] +categories = ["cryptography", "hardware-support"] +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +parsec-openssl-provider = { path ="../parsec-openssl-provider" } diff --git a/parsec-openssl-provider-shared/src/catch.rs b/parsec-openssl-provider-shared/src/catch.rs new file mode 100644 index 00000000..d3e5b08c --- /dev/null +++ b/parsec-openssl-provider-shared/src/catch.rs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft. All rights reserved. + +/** +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE +*/ + +// The function has been copied from https://github.com/Azure/iot-identity-service/blob/91e0588/key/aziot-key-openssl-engine/src/lib.rs#L98 +// after getting the permission from the project maintainers. + +/// Catches the error, if any, from evaluating the given callback and converts it to a unit sentinel. +/// If an openssl error function reference is provided, it is used to push the error onto the openssl error stack. +/// Otherwise, the error is logged to stderr. +/// +/// Intended to be used at FFI boundaries, where a Rust error cannot pass through and must be converted to an integer, nullptr, etc. +use parsec_openssl_provider::openssl_errors; + +pub fn r#catch( + function: Option openssl_errors::Function>, + f: impl FnOnce() -> Result>, +) -> Result { + match f() { + Ok(value) => Ok(value), + Err(err) => { + // Technically, the order the errors should be put onto the openssl error stack is from root cause to top error. + // Unfortunately this is backwards from how Rust errors work, since they are top error to root cause. + // + // We could do it the right way by collect()ing into a Vec<&dyn Error> and iterating it backwards, + // but it seems too wasteful to be worth it. So just put them in the wrong order. + + if let Some(function) = function { + openssl_errors::put_error!(function(), super::Error::MESSAGE, "{}", err); + } else { + eprintln!("[parsec-openssl-provider-shared] error: {}", err); + } + + let mut source = err.source(); + while let Some(err) = source { + if let Some(function) = function { + openssl_errors::put_error!(function(), super::Error::MESSAGE, "{}", err); + } else { + eprintln!("[parsec-openssl-provider-shared] caused by: {}", err); + } + + source = err.source(); + } + + Err(()) + } + } +} diff --git a/parsec-openssl-provider-shared/src/lib.rs b/parsec-openssl-provider-shared/src/lib.rs new file mode 100644 index 00000000..50c01510 --- /dev/null +++ b/parsec-openssl-provider-shared/src/lib.rs @@ -0,0 +1,45 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use parsec_openssl_provider::{ + openssl_errors, parsec_provider_provider_init, +}; + +use parsec_openssl_provider::parsec_openssl2::{OPENSSL_SUCCESS,OPENSSL_ERROR}; +use parsec_openssl_provider::parsec_openssl2::types::VOID_PTR_PTR; +use parsec_openssl_provider::parsec_openssl2::openssl_binding::{OSSL_CORE_HANDLE, OSSL_DISPATCH}; +mod catch; +use catch::r#catch; + +#[no_mangle] +// The function name needs to be unique for dynamic libraries as the openssl core +// looks for OSSL_provider_init symbol while loading the provider. +unsafe extern "C" fn OSSL_provider_init( + handle: *const OSSL_CORE_HANDLE, + in_: *const OSSL_DISPATCH, + out: *mut *const OSSL_DISPATCH, + provctx: VOID_PTR_PTR, +) -> ::std::os::raw::c_int { + let result = r#catch(Some(|| Error::PROVIDER_INIT), || { + parsec_provider_provider_init(handle, in_, out, provctx)?; + + Ok(OPENSSL_SUCCESS) + }); + match result { + Ok(result) => result, + Err(()) => OPENSSL_ERROR, + } +} + +openssl_errors::openssl_errors! { + #[allow(clippy::empty_enum)] + library Error("parsec_openssl_provider_shared") { + functions { + PROVIDER_INIT("parsec_provider_init"); + } + + reasons { + MESSAGE(""); + } + } +} diff --git a/parsec-openssl-provider/Cargo.toml b/parsec-openssl-provider/Cargo.toml new file mode 100644 index 00000000..2a412583 --- /dev/null +++ b/parsec-openssl-provider/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "parsec-openssl-provider" +version = "0.1.0" +authors = ["Parsec Project Contributors"] +description = "A parsec openssl provider static library" +license = "Apache-2.0" +readme = "README.md" +keywords = ["security", "service"] +categories = ["cryptography", "hardware-support"] +edition = "2021" + +[dependencies] +parsec-openssl2 = { path = "../parsec-openssl2" } +openssl-errors = "0.2.0" +log = "0.4" diff --git a/parsec-openssl-provider/src/catch.rs b/parsec-openssl-provider/src/catch.rs new file mode 100644 index 00000000..ab76aaa8 --- /dev/null +++ b/parsec-openssl-provider/src/catch.rs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft. All rights reserved. + +/** +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE +*/ + +// The function has been copied from https://github.com/Azure/iot-identity-service/blob/91e0588/key/aziot-key-openssl-engine/src/lib.rs#L98 +// after getting the permission from the project maintainers. + +/// Catches the error, if any, from evaluating the given callback and converts it to a unit sentinel. +/// If an openssl error function reference is provided, it is used to push the error onto the openssl error stack. +/// Otherwise, the error is logged to stderr. +/// +/// Intended to be used at FFI boundaries, where a Rust error cannot pass through and must be converted to an integer, nullptr, etc. + +pub fn r#catch( + function: Option openssl_errors::Function>, + f: impl FnOnce() -> Result>, +) -> Result { + match f() { + Ok(value) => Ok(value), + Err(err) => { + // Technically, the order the errors should be put onto the openssl error stack is from root cause to top error. + // Unfortunately this is backwards from how Rust errors work, since they are top error to root cause. + // + // We could do it the right way by collect()ing into a Vec<&dyn Error> and iterating it backwards, + // but it seems too wasteful to be worth it. So just put them in the wrong order. + + if let Some(function) = function { + openssl_errors::put_error!(function(), crate::Error::MESSAGE, "{}", err); + } else { + log::error!("[parsec-openssl-provider] error: {}", err); + } + + let mut source = err.source(); + while let Some(err) = source { + if let Some(function) = function { + openssl_errors::put_error!(function(), crate::Error::MESSAGE, "{}", err); + } else { + log::error!("[parsec-openssl-provider] caused by: {}", err); + } + + source = err.source(); + } + + Err(()) + } + } +} diff --git a/parsec-openssl-provider/src/lib.rs b/parsec-openssl-provider/src/lib.rs new file mode 100644 index 00000000..78c22d7c --- /dev/null +++ b/parsec-openssl-provider/src/lib.rs @@ -0,0 +1,77 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use std::mem; + +pub use openssl_errors; +pub use parsec_openssl2; + +use parsec_openssl2::{openssl_binding, types}; + +use openssl_binding::{ + OSSL_CORE_HANDLE, OSSL_DISPATCH, OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, + OSSL_FUNC_PROVIDER_GET_PARAMS, OSSL_FUNC_PROVIDER_QUERY_OPERATION, +}; + +mod provider; +use provider::*; + +mod catch; +use catch::r#catch; + +// The init function populates the dispatch table and returns a NULL pointer +// to the provider context. This needs to be changed when key management and +// crypto support is added to the provider. +pub unsafe fn parsec_provider_provider_init( + _handle: *const OSSL_CORE_HANDLE, + _in_: *const OSSL_DISPATCH, + out: *mut *const OSSL_DISPATCH, + provctx: types::VOID_PTR_PTR, +) -> Result<(), parsec_openssl2::Error> { + let parsec_provider_gettable_params_ptr: ProviderGettableParamsPtr = + parsec_provider_gettable_params; + + let parsec_provider_get_params_ptr: ProviderGetParamsPtr = parsec_provider_get_params; + + let parsec_provider_query_ptr: ProviderQueryPtr = parsec_provider_query; + + static mut DISPATCH_TABLE: [OSSL_DISPATCH; 4] = [parsec_openssl2::ossl_dispatch!(); 4]; + static RESULT_INIT: std::sync::Once = std::sync::Once::new(); + + RESULT_INIT.call_once(|| { + DISPATCH_TABLE = [ + parsec_openssl2::ossl_dispatch!( + OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, + parsec_provider_gettable_params_ptr + ), + parsec_openssl2::ossl_dispatch!( + OSSL_FUNC_PROVIDER_GET_PARAMS, + parsec_provider_get_params_ptr + ), + parsec_openssl2::ossl_dispatch!( + OSSL_FUNC_PROVIDER_QUERY_OPERATION, + parsec_provider_query_ptr + ), + parsec_openssl2::ossl_dispatch!(), + ]; + }); + + *out = DISPATCH_TABLE.as_ptr(); + *provctx = std::ptr::null_mut(); + + Ok(()) +} + +openssl_errors::openssl_errors! { + #[allow(clippy::empty_enum)] + library Error("parsec_openssl_provider") { + functions { + PROVIDER_GETTABLE_PARAMS("parsec_provider_gettable_params"); + PROVIDER_GET_PARAMS("parsec_provider_get_params"); + PROVIDER_QUERY("parsec_provider_query"); + } + + reasons { + MESSAGE(""); + } + } +} diff --git a/parsec-openssl-provider/src/provider.rs b/parsec-openssl-provider/src/provider.rs new file mode 100644 index 00000000..c21865f0 --- /dev/null +++ b/parsec-openssl-provider/src/provider.rs @@ -0,0 +1,90 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use parsec_openssl2::openssl_provider_param::{ + OSSL_PROV_PARAM_BUILDINFO, OSSL_PROV_PARAM_NAME, OSSL_PROV_PARAM_STATUS, + OSSL_PROV_PARAM_VERSION, +}; + +use parsec_openssl2::{ + locate_and_set_provider_status_param, locate_and_set_utf8_param, ossl_param, OPENSSL_ERROR, + OPENSSL_SUCCESS, OSSL_PROVIDER, +}; + +use crate::openssl_binding::{ + OSSL_ALGORITHM, OSSL_PARAM, OSSL_PARAM_INTEGER, OSSL_PARAM_UTF8_PTR, +}; +// Parsec provider parameters +pub const PARSEC_PROVIDER_NAME: &[u8; 24] = b"Parsec OpenSSL Provider\0"; +pub const PARSEC_PROVIDER_VERSION: &[u8; 6] = b"0.1.0\0"; + +// The types of parameters the provider supplies to the openssl library +const PARSEC_PROVIDER_PARAM_TYPES: [OSSL_PARAM; 5] = [ + // Provider name + ossl_param!(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR), + // Provider version + ossl_param!(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR), + // Build info + ossl_param!(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR), + // Provider Status + ossl_param!(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER), + ossl_param!(), +]; + +// Returns an array of OpenSSL parameter types that the +// provider supports +pub unsafe extern "C" fn parsec_provider_gettable_params( + _provider: *const OSSL_PROVIDER, +) -> *const OSSL_PARAM { + PARSEC_PROVIDER_PARAM_TYPES.as_ptr() +} + +// Populates the provider's name, version and the status to parameter structure +pub unsafe extern "C" fn parsec_provider_get_params( + _provctx: *const OSSL_PROVIDER, + params: *mut OSSL_PARAM, +) -> ::std::os::raw::c_int { + let result = super::r#catch(Some(|| super::Error::PROVIDER_GET_PARAMS), || { + // Find parameter of type OSSL_PROV_PARAM_NAME and populate it with PARSEC_PROVIDER_NAME + locate_and_set_utf8_param(OSSL_PROV_PARAM_NAME, PARSEC_PROVIDER_NAME, params)?; + + // Find parameter of type OSSL_PROV_PARAM_VERSION and populate it with PARSEC_PROVIDER_VERSION + locate_and_set_utf8_param(OSSL_PROV_PARAM_VERSION, PARSEC_PROVIDER_VERSION, params)?; + + // Find parameter of type OSSL_PROV_PARAM_STATUS and populate it with status 1 + locate_and_set_provider_status_param(params)?; + + Ok(OPENSSL_SUCCESS) + }); + match result { + Ok(result) => result, + Err(()) => OPENSSL_ERROR, + } +} + +// Function pointer of type OSSL_FUNC_PROVIDER_GETTABLE_PARAMS +pub type ProviderGettableParamsPtr = + unsafe extern "C" fn(*const OSSL_PROVIDER) -> *const OSSL_PARAM; + +// Function pointer of type OSSL_FUNC_PROVIDER_GET_PARAMS +pub type ProviderGetParamsPtr = unsafe extern "C" fn( + provctx: *const OSSL_PROVIDER, + params: *mut OSSL_PARAM, +) -> ::std::os::raw::c_int; + +// Function pointer of type OSSL_FUNC_PROVIDER_QUERY_OPERATION +pub type ProviderQueryPtr = unsafe extern "C" fn( + prov: *mut OSSL_PROVIDER, + operation_id: ::std::os::raw::c_int, + no_cache: *mut ::std::os::raw::c_int, +) -> *const OSSL_ALGORITHM; + +// The null provider implementation currently doesn't supply any algorithms to the core +pub unsafe extern "C" fn parsec_provider_query( + _prov: *mut OSSL_PROVIDER, + _operation_id: ::std::os::raw::c_int, + no_cache: *mut ::std::os::raw::c_int, +) -> *const OSSL_ALGORITHM { + *no_cache = 0; + std::ptr::null_mut() +} diff --git a/parsec-openssl-sys2/Cargo.toml b/parsec-openssl-sys2/Cargo.toml new file mode 100644 index 00000000..cd2c86b0 --- /dev/null +++ b/parsec-openssl-sys2/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "parsec-openssl-sys2" +version = "0.1.0" +license = "Apache-2.0" +authors = ["Parsec Project Contributors"] +edition = "2021" + +[build-dependencies] +bindgen = { version = "0.66.1" } diff --git a/parsec-openssl-sys2/build.rs b/parsec-openssl-sys2/build.rs new file mode 100644 index 00000000..aaffc817 --- /dev/null +++ b/parsec-openssl-sys2/build.rs @@ -0,0 +1,22 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use std::env; +use std::io::{Error, ErrorKind}; +use std::path::PathBuf; + +fn main() -> std::io::Result<()> { + let openssl_builder = bindgen::Builder::default() + .header("src/c/openssl.h") + .generate_comments(false) + .size_t_is_usize(true); + + // Build the bindings + let openssl_bindings = openssl_builder + .generate() + .map_err(|_| Error::new(ErrorKind::Other, "Unable to generate bindings to openssl"))?; + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + openssl_bindings.write_to_file(out_path.join("openssl_bindings.rs"))?; + + Ok(()) +} diff --git a/parsec-openssl-sys2/src/c/openssl.h b/parsec-openssl-sys2/src/c/openssl.h new file mode 100644 index 00000000..893c5cc4 --- /dev/null +++ b/parsec-openssl-sys2/src/c/openssl.h @@ -0,0 +1,74 @@ +// Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// This file contains all the openssl structures, constants +// and function signatures needed for generating the required +// provider bindings. + +#include + +# define OSSL_PARAM_INTEGER 1 +# define OSSL_PARAM_UTF8_PTR 6 + +/* Functions provided by the provider to the Core, reserved numbers 1024-1535 */ +# define OSSL_FUNC_PROVIDER_TEARDOWN 1024 +# define OSSL_FUNC_PROVIDER_GETTABLE_PARAMS 1025 +# define OSSL_FUNC_PROVIDER_GET_PARAMS 1026 +# define OSSL_FUNC_PROVIDER_QUERY_OPERATION 1027 +# define OSSL_FUNC_PROVIDER_UNQUERY_OPERATION 1028 +# define OSSL_FUNC_PROVIDER_GET_REASON_STRINGS 1029 +# define OSSL_FUNC_PROVIDER_GET_CAPABILITIES 1030 +# define OSSL_FUNC_PROVIDER_SELF_TEST 1031 + +/* Opaque handles to be used with core upcall functions from providers */ +typedef struct ossl_core_handle_st OSSL_CORE_HANDLE; + +/* + * Dispatch table element. function_id numbers and the functions are defined + * in core_dispatch.h, see macros with 'OSSL_CORE_MAKE_FUNC' in their names. + * + * An array of these is always terminated by function_id == 0 + */ +struct ossl_dispatch_st { + int function_id; + void (*function)(void); +}; + +typedef struct ossl_dispatch_st OSSL_DISPATCH; + +/* + * Type to pass object data in a uniform way, without exposing the object + * structure. + * + * An array of these is always terminated by key == NULL + */ +struct ossl_param_st { + const char *key; /* the name of the parameter */ + unsigned int data_type; /* declare what kind of content is in buffer */ + void *data; /* value being passed in or out */ + size_t data_size; /* data size */ + size_t return_size; /* returned content size */ +}; + +typedef struct ossl_param_st OSSL_PARAM; + +/* + * Type to tie together algorithm names, property definition string and + * the algorithm implementation in the form of a dispatch table. + * + * An array of these is always terminated by algorithm_names == NULL + */ +struct ossl_algorithm_st { + const char *algorithm_names; /* key */ + const char *property_definition; /* key */ + const OSSL_DISPATCH *implementation; + const char *algorithm_description; +}; + +typedef struct ossl_algorithm_st OSSL_ALGORITHM; + +OSSL_PARAM *OSSL_PARAM_locate(OSSL_PARAM *p, const char *key); + +int OSSL_PARAM_set_utf8_ptr(OSSL_PARAM *p, const char *val); + +int OSSL_PARAM_set_int(OSSL_PARAM *p, int val); diff --git a/parsec-openssl-sys2/src/lib.rs b/parsec-openssl-sys2/src/lib.rs new file mode 100644 index 00000000..5541eef2 --- /dev/null +++ b/parsec-openssl-sys2/src/lib.rs @@ -0,0 +1,10 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(non_camel_case_types)] + +pub mod param; + +pub mod openssl_binding { + include!(concat!(env!("OUT_DIR"), "/openssl_bindings.rs")); +} diff --git a/parsec-openssl-sys2/src/param.rs b/parsec-openssl-sys2/src/param.rs new file mode 100644 index 00000000..8ea08a1b --- /dev/null +++ b/parsec-openssl-sys2/src/param.rs @@ -0,0 +1,8 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +// Parameter names that Providers can define +pub const OSSL_PROV_PARAM_NAME: &[u8; 5] = b"name\0"; +pub const OSSL_PROV_PARAM_VERSION: &[u8; 8] = b"version\0"; +pub const OSSL_PROV_PARAM_BUILDINFO: &[u8; 10] = b"buildinfo\0"; +pub const OSSL_PROV_PARAM_STATUS: &[u8; 7] = b"status\0"; diff --git a/parsec-openssl2/Cargo.toml b/parsec-openssl2/Cargo.toml new file mode 100644 index 00000000..98cd8c4b --- /dev/null +++ b/parsec-openssl2/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "parsec-openssl2" +version = "0.1.0" +license = "Apache-2.0" +authors = ["Parsec Project Contributors"] +edition = "2021" + +[dependencies] +parsec-openssl-sys2 = { path = "../parsec-openssl-sys2" } +openssl = "0.10.63" +openssl2 = { git = "https://github.com/Azure/iot-identity-service.git", rev = "91e0588" } +openssl-sys = "0.9.99" diff --git a/parsec-openssl2/src/lib.rs b/parsec-openssl2/src/lib.rs new file mode 100644 index 00000000..13507093 --- /dev/null +++ b/parsec-openssl2/src/lib.rs @@ -0,0 +1,86 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +pub use openssl_sys::OSSL_PROVIDER; +pub use parsec_openssl_sys2::openssl_binding; +pub use parsec_openssl_sys2::param as openssl_provider_param; +pub mod types; + +pub use openssl2::*; + +// OpenSSL expects an integer return value of 1 and 0 for success and error +pub const OPENSSL_SUCCESS: std::os::raw::c_int = 1; +pub const OPENSSL_ERROR: std::os::raw::c_int = 0; + +#[macro_export] +macro_rules! ossl_dispatch { + () => { + OSSL_DISPATCH { + function_id: 0, + function: None, + } + }; + ($function_id:ident, $function:ident) => { + OSSL_DISPATCH { + function_id: $function_id as i32, + function: Some(mem::transmute($function)), + } + }; +} + +#[macro_export] +macro_rules! ossl_param { + () => { + OSSL_PARAM { + key: std::ptr::null_mut(), + data_type: 0, + data: std::ptr::null_mut(), + data_size: 0, + return_size: 0, + } + }; + ($key:ident, $data_type:ident) => { + OSSL_PARAM { + key: $key.as_ptr() as *const std::os::raw::c_char, + data_type: $data_type, + data: std::ptr::null_mut(), + data_size: 0, + return_size: usize::MAX, + } + }; +} + +// Finds the OpenSSL parameter type in the parameter array "params" and sets the value +// to the provider specific value +pub unsafe fn locate_and_set_utf8_param( + openssl_param: &[u8], + provider_param: &[u8], + params: *mut openssl_binding::OSSL_PARAM, +) -> Result<(), Error> { + let ptr = openssl_returns_nonnull(openssl_binding::OSSL_PARAM_locate( + params, + openssl_param.as_ptr() as *const std::os::raw::c_char, + ))?; + + // OpenSSL returns OPENSSL_SUCCESS + openssl_returns_1(openssl_binding::OSSL_PARAM_set_utf8_ptr( + ptr, + provider_param.as_ptr() as *const std::os::raw::c_char, + ))?; + Ok(()) +} + +// Finds the OpenSSL parameter "OSSL_PROV_PARAM_STATUS" in the parameter array "params" and sets it +// to active status +pub unsafe fn locate_and_set_provider_status_param( + params: *mut openssl_binding::OSSL_PARAM, +) -> Result<(), Error> { + let ptr = openssl_returns_nonnull(openssl_binding::OSSL_PARAM_locate( + params, + openssl_provider_param::OSSL_PROV_PARAM_STATUS.as_ptr() as *const std::os::raw::c_char, + ))?; + + // OpenSSL returns OPENSSL_SUCCESS + openssl_returns_1(openssl_binding::OSSL_PARAM_set_int(ptr, 1))?; + Ok(()) +} diff --git a/parsec-openssl2/src/types.rs b/parsec-openssl2/src/types.rs new file mode 100644 index 00000000..f82e9985 --- /dev/null +++ b/parsec-openssl2/src/types.rs @@ -0,0 +1,5 @@ +// Copyright 2024 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +#![allow(non_camel_case_types)] +pub type VOID_PTR = *mut std::os::raw::c_void; +pub type VOID_PTR_PTR = *mut VOID_PTR;