-
-
Notifications
You must be signed in to change notification settings - Fork 790
ML-KEM/ML-DSA part 2: param builder #2451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
69182d1
00e12f7
131cddd
6e4440f
7642cc6
99520b0
20091b3
deae632
21a83a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
//! OSSL_PARAM management for OpenSSL 3.* | ||
//! | ||
//! The OSSL_PARAM structure represents generic attribute that can represent various | ||
//! properties in OpenSSL, including keys and operations. | ||
//! | ||
//! For convinience, the OSSL_PARAM_BLD builder can be used to dynamically construct | ||
//! these structure. | ||
//! | ||
//! Note, that this module is available only in OpenSSL 3.* and | ||
//! only internally for this crate! | ||
|
||
// Depending on which version of OpenSSL is used, and which algorithms | ||
// are exposed in the bindings, not all of these functions are used. | ||
#![allow(dead_code)] | ||
|
||
use crate::bn::{BigNum, BigNumRef}; | ||
use crate::error::ErrorStack; | ||
use crate::util; | ||
use crate::{cvt, cvt_p}; | ||
use foreign_types::{ForeignType, ForeignTypeRef}; | ||
use libc::{c_char, c_uint, c_void}; | ||
use openssl_macros::corresponds; | ||
use std::ffi::CStr; | ||
use std::ptr; | ||
|
||
foreign_type_and_impl_send_sync! { | ||
type CType = ffi::OSSL_PARAM; | ||
fn drop = ffi::OSSL_PARAM_free; | ||
|
||
/// `OsslParam` constructed using `OsslParamBuilder`. | ||
pub struct OsslParam; | ||
/// Reference to `OsslParam`. | ||
pub struct OsslParamRef; | ||
} | ||
|
||
impl OsslParam {} | ||
swenson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
impl OsslParamRef { | ||
/// Locates the `OsslParam` in the `OsslParam` array | ||
#[corresponds(OSSL_PARAM_locate)] | ||
pub fn locate(&self, key: &[u8]) -> Result<&OsslParamRef, ErrorStack> { | ||
unsafe { | ||
let param = cvt_p(ffi::OSSL_PARAM_locate( | ||
self.as_ptr(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't correct either -- There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not quite as bad as that, thankfully -- it looks like it should be terminated with a param with a null key, but the param itself should not be null AFAICT: https://github.com/openssl/openssl/blob/master/include/openssl/core.h#L83 So, I think this array of params will always be okay in Rust? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about this more, this presents a problem I don't see elsewhere in this code base: this conflates a So, while this code is fine as-is if we assume the Currently there is no other way to construct an However, there are some safety concerns with the I think this is problematic if the Rust compiler decides to move the returned I don't think the current So, I see a few options here, but I'm open to suggestions:
I'm happy to move forward with whichever path you think makes the most sense, or if we have some precedent I don't know about, I'm happy to follow that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seeing how the original PR uses these makes me even more worried, since the compiler could be moving these arrays around, e.g., let mut params: *mut ffi::OSSL_PARAM = ptr::null_mut();
cvt(ffi::EVP_PKEY_todata(pkey.as_ptr(), selection, &mut params))?;
Ok(PKeyMlDsaParams::<T> {
params: OsslParam::from_ptr(params),
_m: ::std::marker::PhantomData,
}) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option: we don’t have a bare OsslParam but instead have a wrapper struct that only has *OsslParam, so that the compiler doesn’t “know” about the bare array and try to move it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nevermind -- I realize now my understanding I think after all, the code as-is is probably sound. Sorry for the PR noise as I thought out loud and please correct me if I'm wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fundamentally, I don't think it's correct for us to confuse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. Obviously this bothers me too. Let me think about this a little to come up with a way to represent this. (Open to suggestions.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I renamed this to I think this is correct now. I added clarifying comments as well. |
||
key.as_ptr() as *const c_char, | ||
swenson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
))?; | ||
Ok(OsslParamRef::from_ptr(param)) | ||
} | ||
} | ||
|
||
/// Get `BigNum` from the current `OsslParam` | ||
#[corresponds(OSSL_PARAM_get_BN)] | ||
pub fn get_bn(&self) -> Result<BigNum, ErrorStack> { | ||
unsafe { | ||
let mut bn: *mut ffi::BIGNUM = ptr::null_mut(); | ||
cvt(ffi::OSSL_PARAM_get_BN(self.as_ptr(), &mut bn))?; | ||
Ok(BigNum::from_ptr(bn)) | ||
} | ||
} | ||
|
||
/// Get `&str` from the current `OsslParam` | ||
#[corresponds(OSSL_PARAM_get_utf8_string)] | ||
pub fn get_utf8_string(&self) -> Result<&str, ErrorStack> { | ||
unsafe { | ||
let mut val: *const c_char = ptr::null_mut(); | ||
cvt(ffi::OSSL_PARAM_get_utf8_string_ptr(self.as_ptr(), &mut val))?; | ||
Ok(CStr::from_ptr(val).to_str().unwrap()) | ||
} | ||
} | ||
|
||
/// Get octet string (as `&[u8]) from the current `OsslParam` | ||
#[corresponds(OSSL_PARAM_get_octet_string)] | ||
pub fn get_octet_string(&self) -> Result<&[u8], ErrorStack> { | ||
unsafe { | ||
let mut val: *const c_void = ptr::null_mut(); | ||
let mut val_len: usize = 0; | ||
cvt(ffi::OSSL_PARAM_get_octet_string_ptr( | ||
self.as_ptr(), | ||
&mut val, | ||
&mut val_len, | ||
))?; | ||
Ok(util::from_raw_parts(val as *const u8, val_len)) | ||
} | ||
} | ||
} | ||
|
||
foreign_type_and_impl_send_sync! { | ||
type CType = ffi::OSSL_PARAM_BLD; | ||
fn drop = ffi::OSSL_PARAM_BLD_free; | ||
|
||
/// Builder used to construct `OsslParam`. | ||
pub struct OsslParamBuilder; | ||
/// Reference to `OsslParamBuilder`. | ||
pub struct OsslParamBuilderRef; | ||
} | ||
|
||
impl OsslParamBuilder { | ||
/// Returns a builder for a OsslParam arrays. | ||
/// | ||
/// The array is initially empty. | ||
#[corresponds(OSSL_PARAM_BLD_new)] | ||
pub fn new() -> Result<OsslParamBuilder, ErrorStack> { | ||
unsafe { | ||
ffi::init(); | ||
|
||
cvt_p(ffi::OSSL_PARAM_BLD_new()).map(OsslParamBuilder) | ||
} | ||
} | ||
|
||
/// Constructs the `OsslParam`. | ||
#[corresponds(OSSL_PARAM_BLD_to_param)] | ||
pub fn to_param(&self) -> Result<OsslParam, ErrorStack> { | ||
swenson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
unsafe { | ||
let params = cvt_p(ffi::OSSL_PARAM_BLD_to_param(self.0))?; | ||
Ok(OsslParam::from_ptr(params)) | ||
} | ||
} | ||
} | ||
|
||
impl OsslParamBuilderRef { | ||
/// Adds a `BigNum` to `OsslParamBuilder`. | ||
/// | ||
/// Note, that both key and bn need to exist until the `to_param` is called! | ||
#[corresponds(OSSL_PARAM_BLD_push_BN)] | ||
pub fn add_bn(&self, key: &[u8], bn: &BigNumRef) -> Result<(), ErrorStack> { | ||
swenson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
unsafe { | ||
cvt(ffi::OSSL_PARAM_BLD_push_BN( | ||
self.as_ptr(), | ||
key.as_ptr() as *const c_char, | ||
bn.as_ptr(), | ||
)) | ||
.map(|_| ()) | ||
} | ||
} | ||
|
||
/// Adds a utf8 string to `OsslParamBuilder`. | ||
/// | ||
/// Note, that both `key` and `buf` need to exist until the `to_param` is called! | ||
#[corresponds(OSSL_PARAM_BLD_push_utf8_string)] | ||
pub fn add_utf8_string(&self, key: &[u8], buf: &str) -> Result<(), ErrorStack> { | ||
unsafe { | ||
cvt(ffi::OSSL_PARAM_BLD_push_utf8_string( | ||
self.as_ptr(), | ||
key.as_ptr() as *const c_char, | ||
buf.as_ptr() as *const c_char, | ||
buf.len(), | ||
)) | ||
.map(|_| ()) | ||
} | ||
} | ||
|
||
/// Adds a octet string to `OsslParamBuilder`. | ||
/// | ||
/// Note, that both `key` and `buf` need to exist until the `to_param` is called! | ||
#[corresponds(OSSL_PARAM_BLD_push_octet_string)] | ||
pub fn add_octet_string(&self, key: &[u8], buf: &[u8]) -> Result<(), ErrorStack> { | ||
unsafe { | ||
cvt(ffi::OSSL_PARAM_BLD_push_octet_string( | ||
self.as_ptr(), | ||
key.as_ptr() as *const c_char, | ||
buf.as_ptr() as *const c_void, | ||
buf.len(), | ||
)) | ||
.map(|_| ()) | ||
} | ||
} | ||
|
||
/// Adds a unsigned int to `OsslParamBuilder`. | ||
/// | ||
/// Note, that both `key` and `buf` need to exist until the `to_param` is called! | ||
#[corresponds(OSSL_PARAM_BLD_push_uint)] | ||
pub fn add_uint(&self, key: &[u8], val: u32) -> Result<(), ErrorStack> { | ||
unsafe { | ||
cvt(ffi::OSSL_PARAM_BLD_push_uint( | ||
self.as_ptr(), | ||
key.as_ptr() as *const c_char, | ||
val as c_uint, | ||
)) | ||
.map(|_| ()) | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.