1use crate::cvt_p;
8use crate::sys::OSSL_PARAM;
9use crate::sys::OSSL_PARAM_END;
10use crate::sys::OSSL_PARAM_construct_int;
11use crate::sys::OSSL_PARAM_construct_octet_string;
12use crate::sys::OSSL_PARAM_construct_utf8_string;
13use libc::c_char;
14use libc::c_int;
15use libc::c_void;
16use openssl::error::ErrorStack;
17use openssl_sys as ffi;
18use std::ffi::CStr;
19use std::fmt;
20use std::ptr;
21
22enum Param {
23 I32(*mut c_int),
24 String(*mut c_char, usize),
25 Vec(*mut c_void, usize),
26}
27
28impl Param {
29 fn alloc_i32(val: i32) -> Result<Param, ErrorStack> {
30 let p = (unsafe {
32 cvt_p(ffi::CRYPTO_malloc(
33 size_of::<c_int>(),
34 concat!(file!(), "\0").as_ptr().cast(),
35 line!() as c_int,
36 ))
37 }?)
38 .cast::<c_int>();
39 unsafe { *p = val };
41
42 Ok(Param::I32(p))
43 }
44
45 fn alloc_string(val: &CStr) -> Result<Param, ErrorStack> {
46 Ok(Param::String(
47 (alloc_slice_inner(val.to_bytes_with_nul())?).cast(),
48 val.to_bytes_with_nul().len(),
49 ))
50 }
51
52 fn alloc_vec(val: &[u8]) -> Result<Param, ErrorStack> {
53 Ok(Param::Vec(alloc_slice_inner(val)?, val.len()))
54 }
55}
56
57fn alloc_slice_inner(val: &[u8]) -> Result<*mut c_void, ErrorStack> {
58 Ok(if val.is_empty() {
59 ptr::null_mut()
60 } else {
61 let p = unsafe {
63 cvt_p(ffi::CRYPTO_malloc(
64 val.len(),
65 concat!(file!(), "\0").as_ptr().cast(),
66 line!() as c_int,
67 ))
68 }?;
69 unsafe { ptr::copy_nonoverlapping(val.as_ptr(), p.cast::<u8>(), val.len()) };
71 p
72 })
73}
74
75macro_rules! drop_param {
76 ($p:ident) => {{
77 ffi::CRYPTO_free(
78 $p.cast::<c_void>(),
79 concat!(file!(), "\0").as_ptr().cast(),
80 line!() as c_int,
81 );
82 }};
83}
84
85impl Drop for Param {
86 fn drop(&mut self) {
87 unsafe {
89 match *self {
90 Param::I32(p) => drop_param!(p),
91 Param::String(p, _) => drop_param!(p),
92 Param::Vec(p, _) => drop_param!(p),
93 }
94 }
95 }
96}
97
98pub struct ParamsBuilder(Vec<(&'static CStr, Param)>);
99
100impl ParamsBuilder {
101 pub fn with_capacity(capacity: usize) -> Self {
102 let params = Vec::with_capacity(capacity);
103 Self(params)
104 }
105
106 pub fn build(self) -> Params {
107 let len = self.0.len();
108
109 let mut params = Params {
110 fixed: self.0,
111 output: Vec::with_capacity(len + 1),
112 };
113
114 for (name, p) in &mut params.fixed {
121 use Param::*;
122 let v = unsafe {
125 match p {
126 I32(v) => OSSL_PARAM_construct_int(name.as_ptr(), *v),
127 Vec(buf, len) => OSSL_PARAM_construct_octet_string(name.as_ptr(), *buf, *len),
128 String(buf, len) => OSSL_PARAM_construct_utf8_string(name.as_ptr(), *buf, *len),
129 }
130 };
131 params.output.push(v);
132 }
133 params.output.push(OSSL_PARAM_END);
134 params
135 }
136}
137
138macro_rules! add_construct {
139 ($func:ident, $name:ident, $ty:ty) => {
140 impl ParamsBuilder {
141 pub fn $func(&mut self, key: &'static CStr, val: $ty) -> Result<(), ErrorStack> {
142 self.0.push((key, Param::$name(val)?));
143 Ok(())
144 }
145 }
146 };
147}
148
149add_construct!(add_i32, alloc_i32, i32);
150add_construct!(add_string, alloc_string, &CStr);
151add_construct!(add_slice, alloc_vec, &[u8]);
152pub struct Params {
155 fixed: Vec<(&'static CStr, Param)>,
156 output: Vec<OSSL_PARAM>,
157}
158
159impl Params {
160 pub fn len(&self) -> usize {
161 self.output.len()
162 }
163
164 pub fn as_mut_ptr(&mut self) -> *mut OSSL_PARAM {
165 self.output.as_mut_ptr()
166 }
167
168 pub fn as_ptr(&mut self) -> *const OSSL_PARAM {
169 self.output.as_ptr()
170 }
171}
172
173impl fmt::Debug for Params {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 write!(f, "Params([")?;
176 for o in &self.output {
177 write!(f, "OSSL_PARAM {{")?;
178 if o.data_type != 0 {
179 write!(f, "name = {:?}, ", unsafe { CStr::from_ptr(o.key) })?;
181 write!(f, "buf = {:?}, ", o.data)?;
182 write!(f, "len = {:?}", o.data_size)?;
183 } else {
184 write!(f, "END")?;
185 }
186
187 write!(f, "}}, ")?;
188 }
189 write!(f, "])")
190 }
191}