Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)

MethodCopies data?Use when
push_octet_sliceYesSlice may be dropped before Params is consumed
push_octet_ptrNoSlice is guaranteed to outlive Params
push_utf8_stringYesShort runtime strings
push_utf8_ptrNo (intent)'static string literals like c"oaep"
push_int/uint/…n/aInteger values always copied
push_bnYesBytes converted to BIGNUM; caller’s slice not retained

Note on push_utf8_ptr: The underlying C function OSSL_PARAM_BLD_push_utf8_ptr is not reliably available across OpenSSL builds. This method falls back to push_utf8_string, which copies. The 'static signature documents intent; the copy of a short literal is negligible.

Allocation vs. Zero-Copy (Reading)

GetterAllocates?Notes
get_int / get_uint / get_size_t / get_i64 / get_u64 / get_longNoScalar read
get_bnYesVec<u8>Must convert the internal BIGNUM to bytes
get_octet_stringNoReturns &[u8] borrowing from the Params array
get_utf8_stringNoReturns &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() returns Result — unlike typical builders, OSSL_PARAM_BLD can fail to allocate immediately. Always propagate with ?.
  • Builder consumes self on 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() uses mem::forget — to prevent double-free after transferring the raw pointer to OSSL_PARAM_BLD_to_param.
  • OSSL_PARAM_END is automaticOSSL_PARAM_BLD_to_param appends the terminator. Never add it manually.
  • push_bn copies the BIGNUMOSSL_PARAM_BLD_push_BN copies the value into the builder’s internal storage, so the caller’s byte slice is not retained after the call.
  • get_bn allocatesOSSL_PARAM_get_BN allocates a new BIGNUM internally; Params then converts it to a Vec<u8> and frees the BIGNUM. For all other numeric types, getters are copy-free scalar reads.