Skip to content

Commit 935f6cf

Browse files
swensonteythoon
andcommitted
ML-KEM/ML-DSA part 2: param builder
Splitting up sfackler#2405 into a few parts as suggest by @alex. This adds the param-builder and other openssl-sys changes. Original commit message: Add internal module to simplify working with OSSL_PARAM structure We discussed that this API is not well suitable for the end users but still, it required for several operations in OpenSSL 3.* so instead of calling to FFI for every use of this API, this introduces simple wrappers that allow building of the params and their usage. Signed-off-by: Jakub Jelen <[email protected]> Co-authored-by: Justus Winter <[email protected]>
1 parent 2d20b57 commit 935f6cf

File tree

8 files changed

+268
-66
lines changed

8 files changed

+268
-66
lines changed

openssl-sys/build/run_bindgen.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const INCLUDES: &str = "
5858
#endif
5959
6060
#if OPENSSL_VERSION_NUMBER >= 0x30000000
61+
#include <openssl/param_build.h>
6162
#include <openssl/provider.h>
6263
#endif
6364

openssl-sys/src/handwritten/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub use self::kdf::*;
1616
pub use self::object::*;
1717
pub use self::ocsp::*;
1818
#[cfg(ossl300)]
19+
pub use self::param_build::*;
20+
#[cfg(ossl300)]
1921
pub use self::params::*;
2022
pub use self::pem::*;
2123
pub use self::pkcs12::*;
@@ -56,6 +58,8 @@ mod kdf;
5658
mod object;
5759
mod ocsp;
5860
#[cfg(ossl300)]
61+
mod param_build;
62+
#[cfg(ossl300)]
5963
mod params;
6064
mod pem;
6165
mod pkcs12;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use super::super::*;
2+
use libc::*;
3+
4+
/* OpenSSL 3.* only */
5+
6+
extern "C" {
7+
pub fn OSSL_PARAM_BLD_new() -> *mut OSSL_PARAM_BLD;
8+
pub fn OSSL_PARAM_BLD_free(bld: *mut OSSL_PARAM_BLD);
9+
pub fn OSSL_PARAM_BLD_push_BN(
10+
bld: *mut OSSL_PARAM_BLD,
11+
key: *const c_char,
12+
bn: *const BIGNUM,
13+
) -> c_int;
14+
pub fn OSSL_PARAM_BLD_push_utf8_string(
15+
bld: *mut OSSL_PARAM_BLD,
16+
key: *const c_char,
17+
buf: *const c_char,
18+
bsize: usize,
19+
) -> c_int;
20+
pub fn OSSL_PARAM_BLD_push_octet_string(
21+
bld: *mut OSSL_PARAM_BLD,
22+
key: *const c_char,
23+
buf: *const c_void,
24+
bsize: usize,
25+
) -> c_int;
26+
pub fn OSSL_PARAM_BLD_push_uint(
27+
bld: *mut OSSL_PARAM_BLD,
28+
key: *const c_char,
29+
buf: c_uint,
30+
) -> c_int;
31+
pub fn OSSL_PARAM_BLD_to_param(bld: *mut OSSL_PARAM_BLD) -> *mut OSSL_PARAM;
32+
}

openssl-sys/src/handwritten/types.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,9 @@ pub struct OSSL_PARAM {
11401140
return_size: size_t,
11411141
}
11421142

1143+
#[cfg(ossl300)]
1144+
pub enum OSSL_PARAM_BLD {}
1145+
11431146
#[cfg(ossl300)]
11441147
pub enum EVP_KDF {}
11451148
#[cfg(ossl300)]

openssl/src/kdf.rs

Lines changed: 42 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,24 @@ impl Drop for EvpKdfCtx {
2525
cfg_if::cfg_if! {
2626
if #[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))] {
2727
use std::cmp;
28-
use std::ffi::c_void;
2928
use std::ffi::CStr;
30-
use std::mem::MaybeUninit;
3129
use std::ptr;
3230
use foreign_types::ForeignTypeRef;
3331
use libc::c_char;
3432
use crate::{cvt, cvt_p};
3533
use crate::lib_ctx::LibCtxRef;
3634
use crate::error::ErrorStack;
35+
use crate::ossl_param::OsslParamBuilder;
36+
37+
const OSSL_KDF_PARAM_PASSWORD: &[u8; 5] = b"pass\0";
38+
const OSSL_KDF_PARAM_SALT: &[u8; 5] = b"salt\0";
39+
const OSSL_KDF_PARAM_SECRET: &[u8; 7] = b"secret\0";
40+
const OSSL_KDF_PARAM_ITER: &[u8; 5] = b"iter\0";
41+
const OSSL_KDF_PARAM_SIZE: &[u8; 5] = b"size\0";
42+
const OSSL_KDF_PARAM_THREADS: &[u8; 8] = b"threads\0";
43+
const OSSL_KDF_PARAM_ARGON2_AD: &[u8; 3] = b"ad\0";
44+
const OSSL_KDF_PARAM_ARGON2_LANES: &[u8; 6] = b"lanes\0";
45+
const OSSL_KDF_PARAM_ARGON2_MEMCOST: &[u8; 8] = b"memcost\0";
3746

3847
#[allow(clippy::too_many_arguments)]
3948
pub fn argon2d(
@@ -94,72 +103,40 @@ cfg_if::cfg_if! {
94103
salt: &[u8],
95104
ad: Option<&[u8]>,
96105
secret: Option<&[u8]>,
97-
mut iter: u32,
98-
mut lanes: u32,
99-
mut memcost: u32,
106+
iter: u32,
107+
lanes: u32,
108+
memcost: u32,
100109
out: &mut [u8],
101110
) -> Result<(), ErrorStack> {
102-
unsafe {
111+
let libctx = ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr);
112+
let max_threads = unsafe {
103113
ffi::init();
104-
let libctx = ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr);
105-
106-
let max_threads = ffi::OSSL_get_max_threads(libctx);
107-
let mut threads = 1;
108-
// If max_threads is 0, then this isn't a threaded build.
109-
// If max_threads is > u32::MAX we need to clamp since
110-
// argon2's threads parameter is a u32.
111-
if max_threads > 0 {
112-
threads = cmp::min(lanes, cmp::min(max_threads, u32::MAX as u64) as u32);
113-
}
114-
let mut params: [ffi::OSSL_PARAM; 10] =
115-
core::array::from_fn(|_| MaybeUninit::<ffi::OSSL_PARAM>::zeroed().assume_init());
116-
let mut idx = 0;
117-
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
118-
b"pass\0".as_ptr() as *const c_char,
119-
pass.as_ptr() as *mut c_void,
120-
pass.len(),
121-
);
122-
idx += 1;
123-
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
124-
b"salt\0".as_ptr() as *const c_char,
125-
salt.as_ptr() as *mut c_void,
126-
salt.len(),
127-
);
128-
idx += 1;
129-
params[idx] =
130-
ffi::OSSL_PARAM_construct_uint(b"threads\0".as_ptr() as *const c_char, &mut threads);
131-
idx += 1;
132-
params[idx] =
133-
ffi::OSSL_PARAM_construct_uint(b"lanes\0".as_ptr() as *const c_char, &mut lanes);
134-
idx += 1;
135-
params[idx] =
136-
ffi::OSSL_PARAM_construct_uint(b"memcost\0".as_ptr() as *const c_char, &mut memcost);
137-
idx += 1;
138-
params[idx] =
139-
ffi::OSSL_PARAM_construct_uint(b"iter\0".as_ptr() as *const c_char, &mut iter);
140-
idx += 1;
141-
let mut size = out.len() as u32;
142-
params[idx] =
143-
ffi::OSSL_PARAM_construct_uint(b"size\0".as_ptr() as *const c_char, &mut size);
144-
idx += 1;
145-
if let Some(ad) = ad {
146-
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
147-
b"ad\0".as_ptr() as *const c_char,
148-
ad.as_ptr() as *mut c_void,
149-
ad.len(),
150-
);
151-
idx += 1;
152-
}
153-
if let Some(secret) = secret {
154-
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
155-
b"secret\0".as_ptr() as *const c_char,
156-
secret.as_ptr() as *mut c_void,
157-
secret.len(),
158-
);
159-
idx += 1;
160-
}
161-
params[idx] = ffi::OSSL_PARAM_construct_end();
162-
114+
ffi::OSSL_get_max_threads(libctx)
115+
};
116+
let mut threads = 1;
117+
// If max_threads is 0, then this isn't a threaded build.
118+
// If max_threads is > u32::MAX we need to clamp since
119+
// argon2id's threads parameter is a u32.
120+
if max_threads > 0 {
121+
threads = cmp::min(lanes, cmp::min(max_threads, u32::MAX as u64) as u32);
122+
}
123+
let bld = OsslParamBuilder::new()?;
124+
bld.add_octet_string(OSSL_KDF_PARAM_PASSWORD, pass)?;
125+
bld.add_octet_string(OSSL_KDF_PARAM_SALT, salt)?;
126+
bld.add_uint(OSSL_KDF_PARAM_THREADS, threads)?;
127+
bld.add_uint(OSSL_KDF_PARAM_ARGON2_LANES, lanes)?;
128+
bld.add_uint(OSSL_KDF_PARAM_ARGON2_MEMCOST, memcost)?;
129+
bld.add_uint(OSSL_KDF_PARAM_ITER, iter)?;
130+
let size = out.len() as u32;
131+
bld.add_uint(OSSL_KDF_PARAM_SIZE, size)?;
132+
if let Some(ad) = ad {
133+
bld.add_octet_string(OSSL_KDF_PARAM_ARGON2_AD, ad)?;
134+
}
135+
if let Some(secret) = secret {
136+
bld.add_octet_string(OSSL_KDF_PARAM_SECRET, secret)?;
137+
}
138+
let params = bld.to_param()?;
139+
unsafe {
163140
let argon2 = EvpKdf(cvt_p(ffi::EVP_KDF_fetch(
164141
libctx,
165142
kdf_identifier.as_ptr() as *const c_char,

openssl/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ pub mod memcmp;
177177
pub mod nid;
178178
#[cfg(not(osslconf = "OPENSSL_NO_OCSP"))]
179179
pub mod ocsp;
180+
#[cfg(ossl300)]
181+
mod ossl_param;
180182
pub mod pkcs12;
181183
pub mod pkcs5;
182184
#[cfg(not(any(boringssl, awslc)))]

openssl/src/ossl_param.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
//! OSSL_PARAM management for OpenSSL 3.*
2+
//!
3+
//! The OSSL_PARAM structure represents generic attribute that can represent various
4+
//! properties in OpenSSL, including keys and operations.
5+
//!
6+
//! For convinience, the OSSL_PARAM_BLD builder can be used to dynamically construct
7+
//! these structure.
8+
//!
9+
//! Note, that this module is available only in OpenSSL 3.* and
10+
//! only internally for this crate!
11+
12+
// Depending on which version of OpenSSL is used, and which algorithms
13+
// are exposed in the bindings, not all of these functions are used.
14+
#![allow(dead_code)]
15+
16+
use crate::bn::{BigNum, BigNumRef};
17+
use crate::error::ErrorStack;
18+
use crate::util;
19+
use crate::{cvt, cvt_p};
20+
use foreign_types::{ForeignType, ForeignTypeRef};
21+
use libc::{c_char, c_uint, c_void};
22+
use openssl_macros::corresponds;
23+
use std::ffi::CStr;
24+
use std::ptr;
25+
26+
foreign_type_and_impl_send_sync! {
27+
type CType = ffi::OSSL_PARAM;
28+
fn drop = ffi::OSSL_PARAM_free;
29+
30+
/// `OsslParam` constructed using `OsslParamBuilder`.
31+
pub struct OsslParam;
32+
/// Reference to `OsslParam`.
33+
pub struct OsslParamRef;
34+
}
35+
36+
impl OsslParam {}
37+
38+
impl OsslParamRef {
39+
/// Locates the `OsslParam` in the `OsslParam` array
40+
#[corresponds(OSSL_PARAM_locate)]
41+
pub fn locate(&self, key: &[u8]) -> Result<&OsslParamRef, ErrorStack> {
42+
unsafe {
43+
let param = cvt_p(ffi::OSSL_PARAM_locate(
44+
self.as_ptr(),
45+
key.as_ptr() as *const c_char,
46+
))?;
47+
Ok(OsslParamRef::from_ptr(param))
48+
}
49+
}
50+
51+
/// Get `BigNum` from the current `OsslParam`
52+
#[corresponds(OSSL_PARAM_get_BN)]
53+
pub fn get_bn(&self) -> Result<BigNum, ErrorStack> {
54+
unsafe {
55+
let mut bn: *mut ffi::BIGNUM = ptr::null_mut();
56+
cvt(ffi::OSSL_PARAM_get_BN(self.as_ptr(), &mut bn))?;
57+
Ok(BigNum::from_ptr(bn))
58+
}
59+
}
60+
61+
/// Get `&str` from the current `OsslParam`
62+
#[corresponds(OSSL_PARAM_get_utf8_string)]
63+
pub fn get_utf8_string(&self) -> Result<&str, ErrorStack> {
64+
unsafe {
65+
let mut val: *const c_char = ptr::null_mut();
66+
cvt(ffi::OSSL_PARAM_get_utf8_string_ptr(self.as_ptr(), &mut val))?;
67+
Ok(CStr::from_ptr(val).to_str().unwrap())
68+
}
69+
}
70+
71+
/// Get octet string (as `&[u8]) from the current `OsslParam`
72+
#[corresponds(OSSL_PARAM_get_octet_string)]
73+
pub fn get_octet_string(&self) -> Result<&[u8], ErrorStack> {
74+
unsafe {
75+
let mut val: *const c_void = ptr::null_mut();
76+
let mut val_len: usize = 0;
77+
cvt(ffi::OSSL_PARAM_get_octet_string_ptr(
78+
self.as_ptr(),
79+
&mut val,
80+
&mut val_len,
81+
))?;
82+
Ok(util::from_raw_parts(val as *const u8, val_len))
83+
}
84+
}
85+
}
86+
87+
foreign_type_and_impl_send_sync! {
88+
type CType = ffi::OSSL_PARAM_BLD;
89+
fn drop = ffi::OSSL_PARAM_BLD_free;
90+
91+
/// Builder used to construct `OsslParam`.
92+
pub struct OsslParamBuilder;
93+
/// Reference to `OsslParamBuilder`.
94+
pub struct OsslParamBuilderRef;
95+
}
96+
97+
impl OsslParamBuilder {
98+
/// Returns a builder for a OsslParam arrays.
99+
///
100+
/// The array is initially empty.
101+
#[corresponds(OSSL_PARAM_BLD_new)]
102+
pub fn new() -> Result<OsslParamBuilder, ErrorStack> {
103+
unsafe {
104+
ffi::init();
105+
106+
cvt_p(ffi::OSSL_PARAM_BLD_new()).map(OsslParamBuilder)
107+
}
108+
}
109+
110+
/// Constructs the `OsslParam`.
111+
#[corresponds(OSSL_PARAM_BLD_to_param)]
112+
pub fn to_param(&self) -> Result<OsslParam, ErrorStack> {
113+
unsafe {
114+
let params = cvt_p(ffi::OSSL_PARAM_BLD_to_param(self.0))?;
115+
Ok(OsslParam::from_ptr(params))
116+
}
117+
}
118+
}
119+
120+
impl OsslParamBuilderRef {
121+
/// Adds a `BigNum` to `OsslParamBuilder`.
122+
///
123+
/// Note, that both key and bn need to exist until the `to_param` is called!
124+
#[corresponds(OSSL_PARAM_BLD_push_BN)]
125+
pub fn add_bn(&self, key: &[u8], bn: &BigNumRef) -> Result<(), ErrorStack> {
126+
unsafe {
127+
cvt(ffi::OSSL_PARAM_BLD_push_BN(
128+
self.as_ptr(),
129+
key.as_ptr() as *const c_char,
130+
bn.as_ptr(),
131+
))
132+
.map(|_| ())
133+
}
134+
}
135+
136+
/// Adds a utf8 string to `OsslParamBuilder`.
137+
///
138+
/// Note, that both `key` and `buf` need to exist until the `to_param` is called!
139+
#[corresponds(OSSL_PARAM_BLD_push_utf8_string)]
140+
pub fn add_utf8_string(&self, key: &[u8], buf: &str) -> Result<(), ErrorStack> {
141+
unsafe {
142+
cvt(ffi::OSSL_PARAM_BLD_push_utf8_string(
143+
self.as_ptr(),
144+
key.as_ptr() as *const c_char,
145+
buf.as_ptr() as *const c_char,
146+
buf.len(),
147+
))
148+
.map(|_| ())
149+
}
150+
}
151+
152+
/// Adds a octet string to `OsslParamBuilder`.
153+
///
154+
/// Note, that both `key` and `buf` need to exist until the `to_param` is called!
155+
#[corresponds(OSSL_PARAM_BLD_push_octet_string)]
156+
pub fn add_octet_string(&self, key: &[u8], buf: &[u8]) -> Result<(), ErrorStack> {
157+
unsafe {
158+
cvt(ffi::OSSL_PARAM_BLD_push_octet_string(
159+
self.as_ptr(),
160+
key.as_ptr() as *const c_char,
161+
buf.as_ptr() as *const c_void,
162+
buf.len(),
163+
))
164+
.map(|_| ())
165+
}
166+
}
167+
168+
/// Adds a unsigned int to `OsslParamBuilder`.
169+
///
170+
/// Note, that both `key` and `buf` need to exist until the `to_param` is called!
171+
#[corresponds(OSSL_PARAM_BLD_push_uint)]
172+
pub fn add_uint(&self, key: &[u8], val: u32) -> Result<(), ErrorStack> {
173+
unsafe {
174+
cvt(ffi::OSSL_PARAM_BLD_push_uint(
175+
self.as_ptr(),
176+
key.as_ptr() as *const c_char,
177+
val as c_uint,
178+
))
179+
.map(|_| ())
180+
}
181+
}
182+
}

0 commit comments

Comments
 (0)