Skip to content

Commit a056b21

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

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-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

+156
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;
@@ -115,6 +136,8 @@ generic_foreign_type_and_impl_send_sync! {
115136
pub struct PkeyCtxRef<T>;
116137
}
117138

139+
pub const OSSL_MAX_NAME_SIZE: c_int = 50;
140+
118141
impl<T> PkeyCtx<T> {
119142
/// Creates a new pkey context using the provided key.
120143
#[corresponds(EVP_PKEY_CTX_new)]
@@ -714,6 +737,109 @@ impl<T> PkeyCtxRef<T> {
714737
Ok(PKey::from_ptr(key))
715738
}
716739
}
740+
741+
/// Sets the digest algorithm for a private key context.
742+
///
743+
/// Requires OpenSSL 3.0.0 or newer.
744+
#[cfg(ossl300)]
745+
#[corresponds(EVP_PKEY_CTX_set_params)]
746+
pub fn set_digest(&mut self, hash_algorithm: MessageDigest) -> Result<(), ErrorStack> {
747+
let digest_name = hash_algorithm.type_().short_name()?;
748+
let digest = CString::new(digest_name).unwrap().into_raw();
749+
let digest_field_name = CString::new("digest").unwrap();
750+
unsafe {
751+
let param_digest = ffi::OSSL_PARAM_construct_utf8_string(
752+
digest_field_name.as_ptr(),
753+
digest,
754+
digest_name.len(),
755+
);
756+
let param_end = ffi::OSSL_PARAM_construct_end();
757+
758+
let params = [param_digest, param_end];
759+
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
760+
761+
// retake pointer to free memory
762+
let _ = CString::from_raw(digest);
763+
}
764+
Ok(())
765+
}
766+
767+
/// Gets the digest algorithm for a private key context.
768+
///
769+
/// Requires OpenSSL 3.0.0 or newer.
770+
#[cfg(ossl300)]
771+
#[corresponds(EVP_PKEY_CTX_get_params)]
772+
pub fn digest(&mut self) -> Result<Option<MessageDigest>, ErrorStack> {
773+
use libc::c_char;
774+
// From openssl/internal/sizes.h
775+
let ossl_max_name_size = 50usize;
776+
let digest_field_name = CString::new("digest").unwrap();
777+
let digest: *mut c_char = CString::new(vec![1; ossl_max_name_size])
778+
.unwrap()
779+
.into_raw();
780+
unsafe {
781+
let param_digest = ffi::OSSL_PARAM_construct_utf8_string(
782+
digest_field_name.as_ptr(),
783+
digest,
784+
ossl_max_name_size,
785+
);
786+
let param_end = ffi::OSSL_PARAM_construct_end();
787+
let mut params = [param_digest, param_end];
788+
cvt(ffi::EVP_PKEY_CTX_get_params(
789+
self.as_ptr(),
790+
params.as_mut_ptr(),
791+
))?;
792+
let digest_str = CString::from_raw(digest);
793+
Ok(MessageDigest::from_name(digest_str.to_str().unwrap()))
794+
}
795+
}
796+
797+
/// Sets the nonce type for a private key context.
798+
///
799+
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
800+
///
801+
/// This is only useful for DSA and ECDSA.
802+
/// Requires OpenSSL 3.2.0 or newer.
803+
#[cfg(ossl320)]
804+
#[corresponds(EVP_PKEY_CTX_set_params)]
805+
pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> {
806+
let nonce_field_name = CString::new("nonce-type").unwrap();
807+
let mut nonce_type = nonce_type.0;
808+
unsafe {
809+
let param_nonce =
810+
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
811+
let param_end = ffi::OSSL_PARAM_construct_end();
812+
813+
let params = [param_nonce, param_end];
814+
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
815+
}
816+
Ok(())
817+
}
818+
819+
/// Gets the nonce type for a private key context.
820+
///
821+
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
822+
///
823+
/// This is only useful for DSA and ECDSA.
824+
/// Requires OpenSSL 3.2.0 or newer.
825+
#[cfg(ossl320)]
826+
#[corresponds(EVP_PKEY_CTX_get_params)]
827+
pub fn nonce_type(&mut self) -> Result<NonceType, ErrorStack> {
828+
let nonce_field_name = CString::new("nonce-type").unwrap();
829+
let mut nonce_type: c_uint = 0;
830+
unsafe {
831+
let param_nonce =
832+
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
833+
let param_end = ffi::OSSL_PARAM_construct_end();
834+
835+
let mut params = [param_nonce, param_end];
836+
cvt(ffi::EVP_PKEY_CTX_get_params(
837+
self.as_ptr(),
838+
params.as_mut_ptr(),
839+
))?;
840+
}
841+
Ok(NonceType(nonce_type))
842+
}
717843
}
718844

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

0 commit comments

Comments
 (0)