Parameters
Overview
OpenSSL 3.x passes configuration to algorithms and contexts through arrays of OSSL_PARAM
structures. Each entry is a key-value pair. The ParamBuilder<'a> type provides a fluent,
typed API for constructing these arrays, and Params<'a> provides typed getters for reading
values back out.
Most callers never need ParamBuilder directly — it is used internally by algorithm
constructors and KDF builders. You need it when:
- Setting AEAD tag length or AAD before cipher operations
- Configuring RSA-OAEP padding mode and digest
- Passing scrypt/PBKDF2 parameters at derive time
- Customising KMAC with a customisation string
- Importing or querying key material via
Pkey::from_params/Pkey::get_params
ParamBuilder<'a>
#![allow(unused)]
fn main() {
pub struct ParamBuilder<'a> { /* OSSL_PARAM_BLD* */ }
impl<'a> ParamBuilder<'a> {
/// Allocate a new empty builder. Returns Err on OOM.
pub fn new() -> Result<Self, ErrorStack>;
// Integer parameters — values are copied into builder-internal storage
pub fn push_int(self, key: &CStr, val: i32) -> Result<Self, ErrorStack>;
pub fn push_uint(self, key: &CStr, val: u32) -> Result<Self, ErrorStack>;
pub fn push_uint64(self, key: &CStr, val: u64) -> Result<Self, ErrorStack>;
pub fn push_size(self, key: &CStr, val: usize) -> Result<Self, ErrorStack>;
// Octet string — copies val into builder-internal storage
pub fn push_octet_slice(self, key: &CStr, val: &[u8]) -> Result<Self, ErrorStack>;
// Octet string — stores a pointer into val (zero-copy)
// The lifetime of the resulting Params<'b> is narrowed to 'b ≤ 'a
pub fn push_octet_ptr<'b>(self, key: &CStr, val: &'b [u8])
-> Result<ParamBuilder<'b>, ErrorStack>
where
'a: 'b;
// UTF-8 string — copies val into builder-internal storage
pub fn push_utf8_string(self, key: &CStr, val: &CStr) -> Result<Self, ErrorStack>;
// UTF-8 string — accepts a &'static CStr; copies in practice (see notes)
pub fn push_utf8_ptr(self, key: &CStr, val: &'static CStr) -> Result<Self, ErrorStack>;
// BIGNUM from big-endian bytes — copies into builder-internal storage
pub fn push_bn(self, key: &CStr, bigendian_bytes: &[u8]) -> Result<Self, ErrorStack>;
/// Finalise and return the OSSL_PARAM array. Consumes the builder.
pub fn build(self) -> Result<Params<'a>, ErrorStack>;
}
}
Params<'a>
#![allow(unused)]
fn main() {
pub struct Params<'a> { /* OSSL_PARAM* */ }
impl<'a> Params<'a> {
// Adopt an OpenSSL-allocated array (e.g. from EVP_PKEY_todata).
// SAFETY: ptr must be a valid OSSL_PARAM_END-terminated array.
pub unsafe fn from_owned_ptr(ptr: *mut OSSL_PARAM) -> Params<'static>;
// Mutable pointer — pass to EVP_PKEY_get_params for in-place query fill.
pub fn as_mut_ptr(&mut self) -> *mut OSSL_PARAM;
// Membership test
pub fn has_param(&self, key: &CStr) -> bool;
// Integer getters
pub fn get_int(&self, key: &CStr) -> Result<i32, ErrorStack>;
pub fn get_uint(&self, key: &CStr) -> Result<u32, ErrorStack>;
pub fn get_size_t(&self, key: &CStr) -> Result<usize, ErrorStack>;
pub fn get_i64(&self, key: &CStr) -> Result<i64, ErrorStack>;
pub fn get_u64(&self, key: &CStr) -> Result<u64, ErrorStack>;
// BIGNUM — allocates a Vec<u8> of big-endian bytes
pub fn get_bn(&self, key: &CStr) -> Result<Vec<u8>, ErrorStack>;
// Zero-copy borrows — valid for the lifetime of &self
pub fn get_octet_string(&self, key: &CStr) -> Result<&[u8], ErrorStack>;
pub fn get_utf8_string(&self, key: &CStr) -> Result<&CStr, ErrorStack>;
// In-place setters — require &mut self; the element must already exist with
// compatible type (built with the corresponding push_* method).
pub fn set_int(&mut self, key: &CStr, val: i32) -> Result<(), ErrorStack>;
pub fn set_uint(&mut self, key: &CStr, val: u32) -> Result<(), ErrorStack>;
pub fn set_size(&mut self, key: &CStr, val: usize) -> Result<(), ErrorStack>;
// Read a C `long` (64-bit on LP64 Linux, 32-bit on Windows); widened to i64.
pub fn get_long(&self, key: &CStr) -> Result<i64, ErrorStack>;
// True if this element was written by a get_params call (OSSL_PARAM_modified).
// Returns false if the key is absent.
pub fn was_modified(&self, key: &CStr) -> bool;
}
}
Params is Send + Sync. Pass it to any OpenSSL function that accepts const OSSL_PARAM[].
The lifetime 'a covers any borrowed slice stored via push_octet_ptr.
Copy vs. Pointer Reference (Building)
| Method | Copies data? | Use when |
|---|---|---|
push_octet_slice | Yes | Slice may be dropped before Params is consumed |
push_octet_ptr | No | Slice is guaranteed to outlive Params |
push_utf8_string | Yes | Short runtime strings |
push_utf8_ptr | No (intent) | 'static string literals like c"oaep" |
push_int/uint/… | n/a | Integer values always copied |
push_bn | Yes | Bytes converted to BIGNUM; caller’s slice not retained |
Note on
push_utf8_ptr: The underlying C functionOSSL_PARAM_BLD_push_utf8_ptris not reliably available across OpenSSL builds. This method falls back topush_utf8_string, which copies. The'staticsignature documents intent; the copy of a short literal is negligible.
Allocation vs. Zero-Copy (Reading)
| Getter | Allocates? | Notes |
|---|---|---|
get_int / get_uint / get_size_t / get_i64 / get_u64 / get_long | No | Scalar read |
get_bn | Yes — Vec<u8> | Must convert the internal BIGNUM to bytes |
get_octet_string | No | Returns &[u8] borrowing from the Params array |
get_utf8_string | No | Returns &CStr borrowing from the Params array |
get_octet_string and get_utf8_string return references whose lifetime is tied
to &self. They cannot outlive the Params value they were read from.
In-place Setters and was_modified
After filling a pre-prepared query array with EVP_PKEY_get_params (or any other
get_params variant), you can update individual fields in place without rebuilding
the entire array:
#![allow(unused)]
fn main() {
// Overwrite an int field that was previously pushed with push_int.
params.set_int(c"key_bits", 4096)?;
params.set_uint(c"flags", 3u32)?;
params.set_size(c"chunk", 4096usize)?;
}
set_int, set_uint, and set_size require &mut self and look up the element
by key at runtime. They fail with Err if the key is absent or the stored type
is incompatible with the requested setter.
get_long reads a C long value — 64 bits on LP64 Linux/macOS, 32 bits on
Windows — and widens it to i64:
#![allow(unused)]
fn main() {
let n: i64 = params.get_long(c"iterations")?;
}
was_modified lets you check whether a particular element was populated by the
last get_params call. OpenSSL marks each element as “modified” when it writes
a value into it, so a false return means the provider left that field untouched:
#![allow(unused)]
fn main() {
let mut query = ParamBuilder::new()?
.push_octet_slice(c"e", &[])?
.build()?;
// Before get_params — not yet populated.
assert!(!query.was_modified(c"e"));
key.get_params(&mut query)?;
// OpenSSL filled the element.
assert!(query.was_modified(c"e"));
}
Returns false if the key does not exist in the array at all.
from_owned_ptr and as_mut_ptr
These two methods cover the ownership-transfer patterns needed when interacting
directly with OpenSSL functions that allocate or fill OSSL_PARAM arrays.
from_owned_ptr — use when OpenSSL returns a freshly allocated array and you
want Params to own and free it:
// EVP_PKEY_todata allocates a new OSSL_PARAM array.
// Params::from_owned_ptr wraps it and will call OSSL_PARAM_free on drop.
let exported: Params<'static> = unsafe { Params::from_owned_ptr(raw_ptr) };
as_mut_ptr — use when you pre-build a query array (with null data pointers)
and pass it to EVP_PKEY_get_params for in-place fill:
// Build a query array asking only for the public exponent.
let mut query = ParamBuilder::new()?
.push_octet_slice(c"e", &[])? // placeholder — OpenSSL will fill this
.build()?;
key.get_params(&mut query)?;
let e_bytes = query.get_bn(c"e")?;
In practice, prefer Pkey::export() and Pkey::get_params() over raw pointer
manipulation. See Asymmetric Keys for examples.
RSA-OAEP Example
#![allow(unused)]
fn main() {
use native_ossl::params::ParamBuilder;
let oaep = ParamBuilder::new()?
.push_utf8_ptr(c"pad-mode", c"oaep")?
.push_utf8_ptr(c"oaep-digest", c"SHA-256")?
.build()?;
let mut enc = PkeyEncryptCtx::new(&pub_key, Some(&oaep))?;
}
AEAD Tag Length Example
#![allow(unused)]
fn main() {
// AES-128-CCM requires the tag length to be set before any data
let tag_params = ParamBuilder::new()?
.push_size(c"tag-len", 16)?
.build()?;
let mut enc = AeadEncryptCtx::new(&alg, &key, &nonce, Some(&tag_params))?;
}
Reading Exported Key Parameters
After calling Pkey::export(), inspect the returned Params<'static> with
the getter methods. The example reads the public exponent and modulus from an
RSA key pair:
use native_ossl::pkey::{KeygenCtx, Pkey, Private};
use native_ossl::params::ParamBuilder;
let mut ctx = KeygenCtx::new(c"RSA")?;
let bits = ParamBuilder::new()?.push_uint(c"bits", 2048)?.build()?;
ctx.set_params(&bits)?;
let key: Pkey<Private> = ctx.generate()?;
// Export all parameters (private + public material).
let exported = key.export()?;
// Check presence before reading.
assert!(exported.has_param(c"e"));
assert!(exported.has_param(c"n"));
// get_bn returns big-endian bytes; allocates a Vec<u8>.
let modulus = exported.get_bn(c"n")?;
let exponent = exported.get_bn(c"e")?;
println!("RSA modulus : {} bytes", modulus.len());
println!("RSA exponent : {:?}", exponent);
For a full round-trip (export then re-import), see Asymmetric Keys.
Design Notes
ParamBuilder::new()returnsResult— unlike typical builders,OSSL_PARAM_BLDcan fail to allocate immediately. Always propagate with?.- Builder consumes
selfon each push — if a push fails, the builder is dropped and the error returned. There is no way to recover a partially-constructed builder. build()usesmem::forget— to prevent double-free after transferring the raw pointer toOSSL_PARAM_BLD_to_param.OSSL_PARAM_ENDis automatic —OSSL_PARAM_BLD_to_paramappends the terminator. Never add it manually.push_bncopies the BIGNUM —OSSL_PARAM_BLD_push_BNcopies the value into the builder’s internal storage, so the caller’s byte slice is not retained after the call.get_bnallocates —OSSL_PARAM_get_BNallocates a newBIGNUMinternally;Paramsthen converts it to aVec<u8>and frees theBIGNUM. For all other numeric types, getters are copy-free scalar reads.