1use crate::error::ErrorStack;
17use crate::util;
18use crate::{cvt, cvt_p};
19use foreign_types::ForeignType;
20use libc::{c_uint, c_void};
21use openssl_macros::corresponds;
22use std::ffi::CStr;
23use std::marker::PhantomData;
24use std::ptr;
25
26foreign_type_and_impl_send_sync! {
27 type CType = ffi::OSSL_PARAM;
30 fn drop = ffi::OSSL_PARAM_free;
32
33 pub struct OsslParamArray;
37 pub struct OsslParamArrayRef;
39}
40
41impl OsslParamArray {
42 #[corresponds(OSSL_PARAM_get_octet_string)]
48 #[allow(dead_code)] pub(crate) fn locate_octet_string<'a>(&'a self, key: &CStr) -> Result<&'a [u8], ErrorStack> {
50 unsafe {
51 let param = cvt_p(ffi::OSSL_PARAM_locate(self.as_ptr(), key.as_ptr()))?;
52 let mut val: *const c_void = ptr::null_mut();
53 let mut val_len: usize = 0;
54 cvt(ffi::OSSL_PARAM_get_octet_string_ptr(
55 param,
56 &mut val,
57 &mut val_len,
58 ))?;
59 Ok(util::from_raw_parts(val as *const u8, val_len))
60 }
61 }
62}
63
64foreign_type_and_impl_send_sync! {
65 type CType = ffi::OSSL_PARAM_BLD;
66 fn drop = ffi::OSSL_PARAM_BLD_free;
67
68 pub struct OsslParamBuilderInternal;
70 pub struct OsslParamBuilderRefInternal;
72}
73
74pub struct OsslParamBuilder<'a> {
77 builder: OsslParamBuilderInternal,
78 _marker: PhantomData<&'a ()>,
79}
80
81impl<'a> OsslParamBuilder<'a> {
82 #[corresponds(OSSL_PARAM_BLD_new)]
86 #[cfg_attr(any(not(ossl320), osslconf = "OPENSSL_NO_ARGON2"), allow(dead_code))]
87 pub(crate) fn new() -> Result<OsslParamBuilder<'a>, ErrorStack> {
88 unsafe {
89 ffi::init();
90
91 cvt_p(ffi::OSSL_PARAM_BLD_new()).map(|builder| OsslParamBuilder {
92 builder: OsslParamBuilderInternal(builder),
93 _marker: PhantomData,
94 })
95 }
96 }
97
98 #[corresponds(OSSL_PARAM_BLD_to_param)]
100 #[cfg_attr(any(not(ossl320), osslconf = "OPENSSL_NO_ARGON2"), allow(dead_code))]
101 #[allow(clippy::wrong_self_convention)]
102 pub(crate) fn to_param(&'a mut self) -> Result<OsslParamArray, ErrorStack> {
103 unsafe {
104 let params = cvt_p(ffi::OSSL_PARAM_BLD_to_param(self.as_ptr()))?;
105 Ok(OsslParamArray::from_ptr(params))
106 }
107 }
108
109 #[corresponds(OSSL_PARAM_BLD_push_octet_string)]
111 #[cfg_attr(any(not(ossl320), osslconf = "OPENSSL_NO_ARGON2"), allow(dead_code))]
112 pub(crate) fn add_octet_string(
113 &mut self,
114 key: &'a CStr,
115 buf: &'a [u8],
116 ) -> Result<(), ErrorStack> {
117 unsafe {
118 cvt(ffi::OSSL_PARAM_BLD_push_octet_string(
119 self.as_ptr(),
120 key.as_ptr(),
121 buf.as_ptr() as *const c_void,
122 buf.len(),
123 ))
124 .map(|_| ())
125 }
126 }
127
128 #[corresponds(OSSL_PARAM_BLD_push_uint)]
130 #[cfg_attr(any(not(ossl320), osslconf = "OPENSSL_NO_ARGON2"), allow(dead_code))]
131 pub(crate) fn add_uint(&mut self, key: &'a CStr, val: u32) -> Result<(), ErrorStack> {
132 unsafe {
133 cvt(ffi::OSSL_PARAM_BLD_push_uint(
134 self.as_ptr(),
135 key.as_ptr(),
136 val as c_uint,
137 ))
138 .map(|_| ())
139 }
140 }
141
142 pub(crate) unsafe fn as_ptr(&mut self) -> *mut ffi::OSSL_PARAM_BLD {
144 self.builder.as_ptr()
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 #[test]
152 fn test_builder_locate_octet_string() {
153 let mut builder = OsslParamBuilder::new().unwrap();
154 builder
155 .add_octet_string(CStr::from_bytes_with_nul(b"key1\0").unwrap(), b"value1")
156 .unwrap();
157 let params = builder.to_param().unwrap();
158
159 assert!(params
160 .locate_octet_string(CStr::from_bytes_with_nul(b"invalid\0").unwrap())
161 .is_err());
162 assert_eq!(
163 params
164 .locate_octet_string(CStr::from_bytes_with_nul(b"key1\0").unwrap())
165 .unwrap(),
166 b"value1"
167 );
168 }
169}