pub mod bindings {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(unnecessary_transmutes)]
include!(concat!(env!("OUT_DIR"), "/ossl_bindings.rs"));
}
use std::borrow::Cow;
use std::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, CStr};
use crate::bindings::*;
pub mod asymcipher;
pub mod cipher;
pub mod derive;
pub mod digest;
pub mod mac;
pub mod pkey;
pub mod rand;
pub mod signature;
#[cfg(feature = "fips")]
pub mod fips;
pub fn api_level() -> (u8, u8, u8) {
let patch: u8 = (OPENSSL_API_LEVEL & 0xff) as u8;
let minor: u8 = ((OPENSSL_API_LEVEL & 0xff00) >> 8) as u8;
let major: u8 = ((OPENSSL_API_LEVEL & 0xff0000) >> 16) as u8;
(major, minor, patch)
}
pub fn zeromem(mem: &mut [u8]) {
unsafe {
OPENSSL_cleanse(void_ptr!(mem.as_mut_ptr()), mem.len());
}
}
macro_rules! void_ptr {
($ptr:expr) => {
$ptr as *const _ as *mut ::std::ffi::c_void
};
}
pub(crate) use void_ptr;
macro_rules! cstr {
($str:expr) => {
unsafe {
::std::ffi::CStr::from_ptr(
$str.as_ptr() as *const ::std::ffi::c_char
)
}
};
}
pub(crate) use cstr;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum ErrorKind {
NullPtr,
OsslError,
KeyError,
WrapperError,
BufferSize,
BadArg,
}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
ErrorKind::NullPtr => "OpenSSL returned a NULL ptr as an error",
ErrorKind::OsslError => "OpenSSL returned a 0 c_int as an error",
ErrorKind::KeyError => "A falure resulting from wrong key usage",
ErrorKind::WrapperError => "A wrapper error",
ErrorKind::BufferSize => "A buffer is not of the correct size",
ErrorKind::BadArg => {
"An optional argument is required or has a bad value"
}
})
}
}
#[derive(Debug, Clone)]
pub struct Error {
kind: ErrorKind,
}
impl Error {
pub fn new(k: ErrorKind) -> Error {
Error { kind: k }
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.kind())
}
}
impl From<std::num::TryFromIntError> for Error {
fn from(_error: std::num::TryFromIntError) -> Error {
Error::new(ErrorKind::WrapperError)
}
}
impl From<std::io::Error> for Error {
fn from(_error: std::io::Error) -> Error {
Error::new(ErrorKind::WrapperError)
}
}
#[cfg(all(feature = "log", feature = "fips"))]
pub fn ossl_err_stack() -> String {
"".to_string()
}
#[cfg(all(feature = "log", not(feature = "fips")))]
pub fn ossl_err_stack() -> String {
let mut bio = std::ptr::null_mut();
let bio_method = unsafe { BIO_s_mem() };
if !bio_method.is_null() {
bio = unsafe { BIO_new(bio_method) };
}
if bio.is_null() {
return "Failed to fetch OpenSSL Error Stack".to_string();
}
unsafe { ERR_print_errors(bio) };
let mut raw_mem: *mut c_char = std::ptr::null_mut();
let raw_len = unsafe {
BIO_ctrl(bio, BIO_CTRL_INFO as c_int, 0, void_ptr!(&mut raw_mem))
};
if raw_mem.is_null() || raw_len == 0 {
return "Failed to get error from OpenSSL's Error Stack".to_string();
}
let mut vec = vec![0u8; raw_len as usize];
unsafe {
std::ptr::copy_nonoverlapping(
raw_mem as *const u8,
vec.as_mut_ptr(),
vec.len(),
);
}
while vec[vec.len() - 1] == b'\n' {
let _ = vec.pop();
}
match String::from_utf8(vec) {
Ok(s) => s,
Err(e) => format!("Failed to parse OpenSSL Error Stack: [{:?}]", e),
}
}
macro_rules! trace_ossl {
($name:expr) => {
#[cfg(feature = "log")]
{
use log::error;
error!(
"{}:{}: {} failed: [{}]",
file!(),
line!(),
$name,
crate::ossl_err_stack()
);
}
};
}
pub(crate) use trace_ossl;
pub struct OsslContext {
context: *mut OSSL_LIB_CTX,
providers: Vec<*mut OSSL_PROVIDER>,
#[cfg(feature = "fips")]
is_fips: bool,
}
static LEGACY_PROVIDER_NAME: &CStr = c"legacy";
impl OsslContext {
pub fn new_lib_ctx() -> OsslContext {
OsslContext {
context: unsafe { OSSL_LIB_CTX_new() },
providers: Vec::new(),
#[cfg(feature = "fips")]
is_fips: false,
}
}
#[allow(dead_code)]
pub fn from_ctx(ctx: *mut OSSL_LIB_CTX) -> OsslContext {
OsslContext {
context: ctx,
providers: Vec::new(),
#[cfg(feature = "fips")]
is_fips: false,
}
}
#[cfg(feature = "fips")]
pub fn from_fips(ctx: *mut OSSL_LIB_CTX, prov: *mut c_void) -> OsslContext {
OsslContext {
context: ctx,
providers: vec![prov as *mut OSSL_PROVIDER],
is_fips: true,
}
}
#[cfg(feature = "fips")]
pub(crate) fn fips_provider(&self) -> *const c_void {
if let Some(p) = self.providers.last() {
return *p as *const c_void;
}
return std::ptr::null();
}
pub fn load_configuration_file(
&mut self,
fname: Option<&::std::path::Path>,
) -> Result<(), Error> {
if cfg!(feature = "fips") {
return Err(Error::new(ErrorKind::OsslError));
}
let filename: *const c_char = match fname {
Some(f) => {
f.as_os_str().as_encoded_bytes().as_ptr() as *const c_char
}
None => std::ptr::null(),
};
let ret = unsafe { OSSL_LIB_CTX_load_config(self.ptr(), filename) };
if ret != 1 {
trace_ossl!("OSSL_LIB_CTX_load_config()");
Err(Error::new(ErrorKind::OsslError))
} else {
Ok(())
}
}
pub fn load_default_configuration(&mut self) -> Result<(), Error> {
self.load_configuration_file(None)
}
pub fn load_legacy_provider(&mut self) -> Result<(), Error> {
if cfg!(feature = "fips") {
return Err(Error::new(ErrorKind::OsslError));
}
if unsafe {
OSSL_PROVIDER_available(self.ptr(), LEGACY_PROVIDER_NAME.as_ptr())
} == 1
{
return Ok(());
}
let provider = unsafe {
OSSL_PROVIDER_load(self.ptr(), LEGACY_PROVIDER_NAME.as_ptr())
};
if provider.is_null() {
Err(Error::new(ErrorKind::OsslError))
} else {
self.providers.push(provider);
Ok(())
}
}
pub fn ptr(&self) -> *mut OSSL_LIB_CTX {
self.context
}
}
impl Drop for OsslContext {
fn drop(&mut self) {
#[cfg(feature = "fips")]
if self.is_fips {
return;
}
unsafe {
while let Some(provider) = self.providers.pop() {
OSSL_PROVIDER_unload(provider);
}
OSSL_LIB_CTX_free(self.context);
}
}
}
unsafe impl Send for OsslContext {}
unsafe impl Sync for OsslContext {}
#[derive(Debug)]
struct BigNum {
bn: *mut BIGNUM,
}
impl BigNum {
#[allow(dead_code)]
pub fn as_ptr(&self) -> *const BIGNUM {
self.bn
}
pub fn as_mut_ptr(&mut self) -> *mut BIGNUM {
self.bn
}
pub fn new() -> Result<BigNum, Error> {
let bn = unsafe { BN_secure_new() };
if bn.is_null() {
trace_ossl!("BN_secure_new()");
Err(Error::new(ErrorKind::NullPtr))
} else {
Ok(BigNum { bn })
}
}
pub fn from_bigendian_slice(v: &[u8]) -> Result<BigNum, Error> {
let mut bn = BigNum::new()?;
let ret = unsafe {
BN_bin2bn(
v.as_ptr() as *mut u8,
c_int::try_from(v.len())?,
bn.as_mut_ptr(),
)
};
if ret.is_null() {
trace_ossl!("BN_bin2bn()");
return Err(Error::new(ErrorKind::NullPtr));
}
Ok(bn)
}
pub fn len(&self) -> Result<usize, Error> {
let x = unsafe { (BN_num_bits(self.as_ptr()) + 7) / 8 };
Ok(usize::try_from(x)?)
}
pub fn from_param(p: *const OSSL_PARAM) -> Result<BigNum, Error> {
let mut bn: *mut BIGNUM = std::ptr::null_mut();
if unsafe { OSSL_PARAM_get_BN(p, &mut bn) } != 1 {
return Err(Error::new(ErrorKind::OsslError));
}
Ok(BigNum { bn })
}
pub fn to_native_vec(&self) -> Result<Vec<u8>, Error> {
let mut v = vec![0u8; self.len()?];
if v.len() == 0 {
v.push(0);
}
let ret = unsafe {
BN_bn2nativepad(
self.as_ptr(),
v.as_mut_ptr(),
c_int::try_from(v.len())?,
)
};
if ret < 1 {
trace_ossl!("BN_bn2nativepad()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(v)
}
pub fn to_bigendian_vec(&self) -> Result<Vec<u8>, Error> {
let len = self.len()?;
let mut v = vec![0u8; self.len()?];
let ret = unsafe { BN_bn2bin(self.as_ptr(), v.as_mut_ptr()) };
if usize::try_from(ret)? != len {
return Err(Error::new(ErrorKind::WrapperError));
}
Ok(v)
}
}
impl Drop for BigNum {
fn drop(&mut self) {
unsafe {
BN_free(self.as_mut_ptr());
}
}
}
#[derive(Debug)]
#[allow(dead_code)]
pub enum BorrowedReference<'a> {
CharBool(&'a c_uchar),
Int(&'a c_int),
Slice(&'a [u8]),
Vector(&'a Vec<u8>),
Uint(&'a c_uint),
Ulong(&'a c_ulong),
Usize(&'a usize),
}
#[derive(Debug)]
pub struct OsslParamBuilder<'a> {
v: Vec<Vec<u8>>,
p: Cow<'a, [OSSL_PARAM]>,
zeroize: bool,
freeptr: bool,
br: Vec<BorrowedReference<'a>>,
}
#[derive(Debug)]
pub struct OsslParam<'a>(OsslParamBuilder<'a>);
impl Drop for OsslParamBuilder<'_> {
fn drop(&mut self) {
if self.freeptr {
#[cfg(param_clear_free)]
unsafe {
OSSL_PARAM_clear_free(
self.p.as_ref().as_ptr() as *mut OSSL_PARAM
);
}
#[cfg(not(param_clear_free))]
unsafe {
OSSL_PARAM_free(self.p.as_ref().as_ptr() as *mut OSSL_PARAM);
}
}
if self.zeroize {
while let Some(mut v) = self.v.pop() {
unsafe {
OPENSSL_cleanse(void_ptr!(v.as_mut_ptr()), v.len());
}
}
}
}
}
impl<'a> OsslParamBuilder<'a> {
#[allow(dead_code)]
pub fn new() -> OsslParamBuilder<'a> {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> OsslParamBuilder<'a> {
OsslParamBuilder {
v: Vec::new(),
p: Cow::Owned(Vec::with_capacity(capacity + 1)),
zeroize: false,
freeptr: false,
br: Vec::new(),
}
}
pub fn add_bn(&mut self, key: &CStr, v: &[u8]) -> Result<(), Error> {
let bn = BigNum::from_bigendian_slice(v)?;
let container = bn.to_native_vec()?;
let param = unsafe {
OSSL_PARAM_construct_BN(
key.as_ptr(),
void_ptr!(container.as_ptr()) as *mut u8,
container.len(),
)
};
self.v.push(container);
self.p.to_mut().push(param);
Ok(())
}
#[allow(dead_code)]
pub fn add_utf8_string(
&mut self,
key: &CStr,
v: &'a Vec<u8>,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_utf8_string(
key.as_ptr(),
void_ptr!(v.as_ptr()) as *mut c_char,
0,
)
};
self.p.to_mut().push(param);
self.br.push(BorrowedReference::Vector(v));
Ok(())
}
#[allow(dead_code)]
pub fn add_owned_utf8_string(
&mut self,
key: &CStr,
mut v: Vec<u8>,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_utf8_string(
key.as_ptr(),
void_ptr!(v.as_mut_ptr()) as *mut c_char,
0,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
pub fn add_empty_utf8_string(
&mut self,
key: &CStr,
len: usize,
) -> Result<(), Error> {
let mut v = vec![0u8; len];
let param = unsafe {
OSSL_PARAM_construct_utf8_string(
key.as_ptr(),
void_ptr!(v.as_mut_ptr()) as *mut c_char,
len,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
#[allow(dead_code)]
pub fn add_const_c_string(
&mut self,
key: &CStr,
val: &CStr,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_utf8_string(
key.as_ptr(),
val.as_ptr() as *mut c_char,
0,
)
};
self.p.to_mut().push(param);
Ok(())
}
#[allow(dead_code)]
pub fn add_octet_string(
&mut self,
key: &CStr,
v: &'a Vec<u8>,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_octet_string(
key.as_ptr(),
void_ptr!(v.as_ptr()),
v.len(),
)
};
self.p.to_mut().push(param);
self.br.push(BorrowedReference::Vector(v));
Ok(())
}
pub fn add_octet_slice(
&mut self,
key: &CStr,
s: &'a [u8],
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_octet_string(
key.as_ptr(),
void_ptr!(s.as_ptr()),
s.len(),
)
};
self.p.to_mut().push(param);
self.br.push(BorrowedReference::Slice(s));
Ok(())
}
#[allow(dead_code)]
pub fn add_owned_octet_string(
&mut self,
key: &CStr,
v: Vec<u8>,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_octet_string(
key.as_ptr(),
void_ptr!(v.as_ptr()),
v.len(),
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
#[allow(dead_code)]
pub fn add_size_t(
&mut self,
key: &CStr,
val: &'a usize,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_size_t(
key.as_ptr(),
val as *const _ as *mut usize,
)
};
self.p.to_mut().push(param);
self.br.push(BorrowedReference::Usize(val));
Ok(())
}
#[allow(dead_code)]
pub fn add_uint(
&mut self,
key: &CStr,
val: &'a c_uint,
) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_uint(
key.as_ptr(),
val as *const _ as *mut c_uint,
)
};
self.p.to_mut().push(param);
self.br.push(BorrowedReference::Uint(val));
Ok(())
}
#[allow(dead_code)]
pub fn add_int(&mut self, key: &CStr, val: &'a c_int) -> Result<(), Error> {
let param = unsafe {
OSSL_PARAM_construct_int(
key.as_ptr(),
val as *const _ as *mut c_int,
)
};
self.p.to_mut().push(param);
self.br.push(BorrowedReference::Int(val));
Ok(())
}
pub fn add_owned_size_t(
&mut self,
key: &CStr,
val: usize,
) -> Result<(), Error> {
let v = val.to_ne_bytes().to_vec();
let param = unsafe {
OSSL_PARAM_construct_size_t(
key.as_ptr(),
v.as_ptr() as *const _ as *mut usize,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
pub fn add_owned_uint(
&mut self,
key: &CStr,
val: c_uint,
) -> Result<(), Error> {
let v = val.to_ne_bytes().to_vec();
let param = unsafe {
OSSL_PARAM_construct_uint(
key.as_ptr(),
v.as_ptr() as *const _ as *mut c_uint,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
pub fn add_owned_int(
&mut self,
key: &CStr,
val: c_int,
) -> Result<(), Error> {
let v = val.to_ne_bytes().to_vec();
let param = unsafe {
OSSL_PARAM_construct_int(
key.as_ptr(),
v.as_ptr() as *const _ as *mut c_int,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
pub fn add_owned_i64(&mut self, key: &CStr, val: i64) -> Result<(), Error> {
let v = val.to_ne_bytes().to_vec();
let param = unsafe {
OSSL_PARAM_construct_int64(
key.as_ptr(),
v.as_ptr() as *const _ as *mut i64,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
pub fn add_owned_u64(&mut self, key: &CStr, val: u64) -> Result<(), Error> {
let v = val.to_ne_bytes().to_vec();
let param = unsafe {
OSSL_PARAM_construct_uint64(
key.as_ptr(),
v.as_ptr() as *const _ as *mut u64,
)
};
self.v.push(v);
self.p.to_mut().push(param);
Ok(())
}
pub fn copy_params(&mut self, params: &[OSSL_PARAM]) -> Result<(), Error> {
for p in params {
if p.data.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let k = unsafe { CStr::from_ptr(p.key as *const c_char) };
let key = k.to_bytes_with_nul().to_vec();
let data_size = if p.data_type == OSSL_PARAM_UTF8_STRING {
p.data_size + 1
} else {
p.data_size
};
let val = unsafe {
std::slice::from_raw_parts(p.data as *const u8, data_size)
}
.to_vec();
let param = OSSL_PARAM {
key: key.as_ptr() as *const c_char,
data_type: p.data_type,
data: val.as_ptr() as *mut c_void,
data_size: p.data_size,
return_size: 0,
};
self.v.push(key);
self.v.push(val);
self.p.to_mut().push(param);
}
Ok(())
}
pub fn finalize(mut self) -> OsslParam<'a> {
self.p.to_mut().push(unsafe { OSSL_PARAM_construct_end() });
OsslParam(self)
}
}
impl<'a> OsslParam<'a> {
#[allow(dead_code)]
pub fn empty() -> OsslParam<'static> {
let p = OsslParamBuilder {
v: Vec::new(),
p: Cow::Owned(Vec::with_capacity(1)),
zeroize: false,
freeptr: false,
br: Vec::new(),
};
p.finalize()
}
pub fn from_ptr(ptr: *mut OSSL_PARAM) -> Result<OsslParam<'static>, Error> {
if ptr.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut nelem = 0;
let mut counter = ptr;
unsafe {
while !(*counter).key.is_null() {
nelem += 1;
counter = counter.offset(1);
}
}
Ok(OsslParam(OsslParamBuilder {
v: Vec::new(),
p: Cow::Borrowed(unsafe {
std::slice::from_raw_parts(ptr, nelem + 1)
}),
zeroize: false,
freeptr: true,
br: Vec::new(),
}))
}
#[allow(dead_code)]
pub fn as_ptr(&self) -> *const OSSL_PARAM {
self.0.p.as_ref().as_ptr()
}
#[allow(dead_code)]
pub fn as_mut_ptr(&mut self) -> *mut OSSL_PARAM {
self.0.p.to_mut().as_mut_ptr()
}
unsafe fn int_mut_ptr(&self) -> *mut OSSL_PARAM {
self.as_ptr() as *mut OSSL_PARAM
}
#[allow(dead_code)]
pub fn get_int(&self, key: &CStr) -> Result<c_int, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut val: c_int = 0;
let res = unsafe { OSSL_PARAM_get_int(p, &mut val) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_int()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(val)
}
pub fn get_uint(&self, key: &CStr) -> Result<c_uint, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut val: c_uint = 0;
let res = unsafe { OSSL_PARAM_get_uint(p, &mut val) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_uint()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(val)
}
pub fn get_size_t(&self, key: &CStr) -> Result<usize, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut val: usize = 0;
let res = unsafe { OSSL_PARAM_get_size_t(p, &mut val) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_size_t()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(val)
}
pub fn get_i64(&self, key: &CStr) -> Result<i64, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut val: i64 = 0;
let res = unsafe { OSSL_PARAM_get_int64(p, &mut val) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_int64()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(val)
}
pub fn get_u64(&self, key: &CStr) -> Result<u64, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut val: u64 = 0;
let res = unsafe { OSSL_PARAM_get_uint64(p, &mut val) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_uint64()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(val)
}
#[allow(dead_code)]
pub fn get_long(&self, key: &CStr) -> Result<c_long, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut val: c_long = 0;
let res = unsafe { OSSL_PARAM_get_long(p, &mut val) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_long()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(val)
}
pub fn get_bn(&self, key: &CStr) -> Result<Vec<u8>, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let bn = BigNum::from_param(p)?;
bn.to_bigendian_vec()
}
#[allow(dead_code)]
pub fn get_octet_string(&self, key: &CStr) -> Result<&'a [u8], Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut buf: *const c_void = std::ptr::null_mut();
let mut buf_len: usize = 0;
let res = unsafe {
OSSL_PARAM_get_octet_string_ptr(p, &mut buf, &mut buf_len)
};
if res != 1 {
trace_ossl!("OSSL_PARAM_get_octet_string_ptr()");
return Err(Error::new(ErrorKind::OsslError));
}
let octet =
unsafe { std::slice::from_raw_parts(buf as *const u8, buf_len) };
Ok(octet)
}
#[allow(dead_code)]
pub fn get_utf8_string(&self, key: &CStr) -> Result<&'a CStr, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
if p.is_null() {
return Err(Error::new(ErrorKind::NullPtr));
}
let mut ptr: *const c_char = std::ptr::null_mut();
let res = unsafe { OSSL_PARAM_get_utf8_string_ptr(p, &mut ptr) };
if res != 1 {
trace_ossl!("OSSL_PARAM_get_utf8_string_ptr()");
return Err(Error::new(ErrorKind::OsslError));
}
Ok(unsafe { CStr::from_ptr(ptr) })
}
#[allow(dead_code)]
pub fn has_param(&self, key: &CStr) -> Result<bool, Error> {
let p = unsafe { OSSL_PARAM_locate(self.int_mut_ptr(), key.as_ptr()) };
Ok(!p.is_null())
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.0.p.as_ref().len() - 1
}
}
#[derive(Debug)]
pub struct OsslSecret {
data: Vec<u8>,
}
impl OsslSecret {
pub fn new(size: usize) -> OsslSecret {
OsslSecret {
data: vec![0u8; size],
}
}
pub fn from_slice(secret: &[u8]) -> OsslSecret {
OsslSecret {
data: secret.to_vec(),
}
}
pub fn from_vec(secret: Vec<u8>) -> OsslSecret {
OsslSecret { data: secret }
}
pub fn len(&self) -> usize {
self.data.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn as_ptr(&self) -> *const u8 {
self.data.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.data.as_mut_ptr()
}
pub fn reduce(
&mut self,
new_size: usize,
starting_point: usize,
) -> Result<(), Error> {
let end_point = match starting_point.checked_add(new_size) {
Some(end) => end,
None => return Err(Error::new(ErrorKind::BufferSize)),
};
if end_point > self.len() {
return Err(Error::new(ErrorKind::BufferSize));
}
if new_size == self.len() && starting_point == 0 {
return Ok(());
}
let mut new_data = vec![0u8; new_size];
new_data.copy_from_slice(&self.data[starting_point..end_point]);
unsafe {
OPENSSL_cleanse(void_ptr!(self.data.as_mut_ptr()), self.data.len());
}
std::mem::swap(&mut self.data, &mut new_data);
Ok(())
}
}
impl Drop for OsslSecret {
fn drop(&mut self) {
unsafe {
OPENSSL_cleanse(void_ptr!(self.data.as_mut_ptr()), self.data.len());
}
}
}
impl AsRef<[u8]> for OsslSecret {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
impl AsMut<[u8]> for OsslSecret {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.data
}
}
impl std::ops::Deref for OsslSecret {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl std::ops::DerefMut for OsslSecret {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
#[cfg(test)]
mod tests;