Skip to content

Commit 78b2e98

Browse files
committed
Add support for setting the nonce type and digest on a PKEY_CTX
1 parent 0743e6a commit 78b2e98

File tree

4 files changed

+187
-0
lines changed

4 files changed

+187
-0
lines changed

openssl-sys/src/handwritten/evp.rs

+19
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,12 @@ extern "C" {
538538
#[cfg(ossl300)]
539539
pub fn EVP_PKEY_CTX_set_signature_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int;
540540

541+
#[cfg(ossl300)]
542+
pub fn EVP_PKEY_CTX_set_params(ctx: *mut EVP_PKEY_CTX, params: *const OSSL_PARAM) -> c_int;
543+
544+
#[cfg(ossl300)]
545+
pub fn EVP_PKEY_CTX_get_params(ctx: *mut EVP_PKEY_CTX, params: *mut OSSL_PARAM) -> c_int;
546+
541547
pub fn EVP_PKEY_new_mac_key(
542548
type_: c_int,
543549
e: *mut ENGINE,
@@ -646,3 +652,16 @@ extern "C" {
646652
pub fn EVP_EncodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int;
647653
pub fn EVP_DecodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int;
648654
}
655+
656+
extern "C" {
657+
#[cfg(ossl300)]
658+
pub fn OSSL_PARAM_construct_uint(key: *const c_char, buf: *mut c_uint) -> OSSL_PARAM;
659+
#[cfg(ossl300)]
660+
pub fn OSSL_PARAM_construct_utf8_string(
661+
key: *const c_char,
662+
buf: *mut c_char,
663+
bsize: size_t,
664+
) -> OSSL_PARAM;
665+
#[cfg(ossl300)]
666+
pub fn OSSL_PARAM_construct_end() -> OSSL_PARAM;
667+
}

openssl-sys/src/handwritten/types.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1093,3 +1093,13 @@ pub enum OSSL_PROVIDER {}
10931093

10941094
#[cfg(ossl300)]
10951095
pub enum OSSL_LIB_CTX {}
1096+
1097+
#[cfg(ossl300)]
1098+
#[repr(C)]
1099+
pub struct OSSL_PARAM {
1100+
key: *const c_char,
1101+
data_type: c_uchar,
1102+
data: *mut c_void,
1103+
data_size: size_t,
1104+
return_size: size_t,
1105+
}

openssl/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
* Added `PkeyCtxRef::{digest, set_digest, nonce_type, set_nonce_type}`.
6+
* Added `OSSL_PARAM`, `OSSL_PARAM_construct_uint` , `OSSL_PARAM_construct_utf8_string`, `OSSL_PARAM_construct_end` to openssl-sys.
7+
* Added `EVP_PKEY_CTX_set_params` and `EVP_PKEY_CTX_get_params` to openssl-sys.
8+
59
## [v0.10.62] - 2023-12-22
610

711
### Added

openssl/src/pkey_ctx.rs

+154
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ let cmac_key = ctx.keygen().unwrap();
6767
#[cfg(not(boringssl))]
6868
use crate::cipher::CipherRef;
6969
use crate::error::ErrorStack;
70+
#[cfg(ossl300)]
71+
use crate::hash::MessageDigest;
7072
use crate::md::MdRef;
7173
use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private};
7274
use crate::rsa::Padding;
@@ -75,8 +77,12 @@ use crate::{cvt, cvt_p};
7577
use foreign_types::{ForeignType, ForeignTypeRef};
7678
#[cfg(not(boringssl))]
7779
use libc::c_int;
80+
#[cfg(ossl320)]
81+
use libc::c_uint;
7882
use openssl_macros::corresponds;
7983
use std::convert::TryFrom;
84+
#[cfg(ossl300)]
85+
use std::ffi::CString;
8086
use std::ptr;
8187

8288
/// HKDF modes of operation.
@@ -105,6 +111,21 @@ impl HkdfMode {
105111
pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
106112
}
107113

114+
/// Nonce type for ECDSA and DSA.
115+
#[cfg(ossl320)]
116+
#[derive(Debug, PartialEq)]
117+
pub struct NonceType(c_uint);
118+
119+
#[cfg(ossl320)]
120+
impl NonceType {
121+
/// This is the default mode. It uses a random value for the nonce k as defined in FIPS 186-4 Section 6.3
122+
/// “Secret Number Generation”.
123+
pub const RANDOM_K: Self = NonceType(0);
124+
125+
/// Uses a deterministic value for the nonce k as defined in RFC #6979 (See Section 3.2 “Generation of k”).
126+
pub const DETERMINISTIC_K: Self = NonceType(1);
127+
}
128+
108129
generic_foreign_type_and_impl_send_sync! {
109130
type CType = ffi::EVP_PKEY_CTX;
110131
fn drop = ffi::EVP_PKEY_CTX_free;
@@ -714,6 +735,109 @@ impl<T> PkeyCtxRef<T> {
714735
Ok(PKey::from_ptr(key))
715736
}
716737
}
738+
739+
/// Sets the digest algorithm for a private key context.
740+
///
741+
/// Requires OpenSSL 3.0.0 or newer.
742+
#[cfg(ossl300)]
743+
#[corresponds(EVP_PKEY_CTX_set_params)]
744+
pub fn set_digest(&mut self, hash_algorithm: MessageDigest) -> Result<(), ErrorStack> {
745+
let digest_name = hash_algorithm.type_().short_name()?;
746+
let digest = CString::new(digest_name).unwrap().into_raw();
747+
let digest_field_name = CString::new("digest").unwrap();
748+
unsafe {
749+
let param_digest = ffi::OSSL_PARAM_construct_utf8_string(
750+
digest_field_name.as_ptr(),
751+
digest,
752+
digest_name.len(),
753+
);
754+
let param_end = ffi::OSSL_PARAM_construct_end();
755+
756+
let params = [param_digest, param_end];
757+
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
758+
759+
// retake pointer to free memory
760+
let _ = CString::from_raw(digest);
761+
}
762+
Ok(())
763+
}
764+
765+
/// Gets the digest algorithm for a private key context.
766+
///
767+
/// Requires OpenSSL 3.0.0 or newer.
768+
#[cfg(ossl300)]
769+
#[corresponds(EVP_PKEY_CTX_get_params)]
770+
pub fn digest(&mut self) -> Result<Option<MessageDigest>, ErrorStack> {
771+
use libc::c_char;
772+
// From openssl/internal/sizes.h
773+
let ossl_max_name_size = 50usize;
774+
let digest_field_name = CString::new("digest").unwrap();
775+
let digest: *mut c_char = CString::new(vec![1; ossl_max_name_size])
776+
.unwrap()
777+
.into_raw();
778+
unsafe {
779+
let param_digest = ffi::OSSL_PARAM_construct_utf8_string(
780+
digest_field_name.as_ptr(),
781+
digest,
782+
ossl_max_name_size,
783+
);
784+
let param_end = ffi::OSSL_PARAM_construct_end();
785+
let mut params = [param_digest, param_end];
786+
cvt(ffi::EVP_PKEY_CTX_get_params(
787+
self.as_ptr(),
788+
params.as_mut_ptr(),
789+
))?;
790+
let digest_str = CString::from_raw(digest);
791+
Ok(MessageDigest::from_name(digest_str.to_str().unwrap()))
792+
}
793+
}
794+
795+
/// Sets the nonce type for a private key context.
796+
///
797+
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
798+
///
799+
/// This is only useful for DSA and ECDSA.
800+
/// Requires OpenSSL 3.2.0 or newer.
801+
#[cfg(ossl320)]
802+
#[corresponds(EVP_PKEY_CTX_set_params)]
803+
pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> {
804+
let nonce_field_name = CString::new("nonce-type").unwrap();
805+
let mut nonce_type = nonce_type.0;
806+
unsafe {
807+
let param_nonce =
808+
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
809+
let param_end = ffi::OSSL_PARAM_construct_end();
810+
811+
let params = [param_nonce, param_end];
812+
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
813+
}
814+
Ok(())
815+
}
816+
817+
/// Gets the nonce type for a private key context.
818+
///
819+
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
820+
///
821+
/// This is only useful for DSA and ECDSA.
822+
/// Requires OpenSSL 3.2.0 or newer.
823+
#[cfg(ossl320)]
824+
#[corresponds(EVP_PKEY_CTX_get_params)]
825+
pub fn nonce_type(&mut self) -> Result<NonceType, ErrorStack> {
826+
let nonce_field_name = CString::new("nonce-type").unwrap();
827+
let mut nonce_type: c_uint = 0;
828+
unsafe {
829+
let param_nonce =
830+
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
831+
let param_end = ffi::OSSL_PARAM_construct_end();
832+
833+
let mut params = [param_nonce, param_end];
834+
cvt(ffi::EVP_PKEY_CTX_get_params(
835+
self.as_ptr(),
836+
params.as_mut_ptr(),
837+
))?;
838+
}
839+
Ok(NonceType(nonce_type))
840+
}
717841
}
718842

719843
#[cfg(test)]
@@ -999,4 +1123,34 @@ mod test {
9991123
// The digest is the end of the DigestInfo structure.
10001124
assert_eq!(result_buf[length - digest.len()..length], digest);
10011125
}
1126+
1127+
#[test]
1128+
#[cfg(ossl300)]
1129+
fn set_digest() {
1130+
let key1 =
1131+
EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
1132+
let key1 = PKey::from_ec_key(key1).unwrap();
1133+
1134+
let mut ctx = PkeyCtx::new(&key1).unwrap();
1135+
ctx.sign_init().unwrap();
1136+
ctx.set_digest(MessageDigest::sha224()).unwrap();
1137+
let digest_name = ctx.digest().unwrap().unwrap().type_();
1138+
assert_eq!(digest_name, MessageDigest::sha224().type_());
1139+
assert!(ErrorStack::get().errors().is_empty());
1140+
}
1141+
1142+
#[test]
1143+
#[cfg(ossl320)]
1144+
fn set_nonce_type() {
1145+
let key1 =
1146+
EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
1147+
let key1 = PKey::from_ec_key(key1).unwrap();
1148+
1149+
let mut ctx = PkeyCtx::new(&key1).unwrap();
1150+
ctx.sign_init().unwrap();
1151+
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();
1152+
let nonce_type = ctx.nonce_type().unwrap();
1153+
assert_eq!(nonce_type, NonceType::DETERMINISTIC_K);
1154+
assert!(ErrorStack::get().errors().is_empty());
1155+
}
10021156
}

0 commit comments

Comments
 (0)