Skip to content

Commit 84162bf

Browse files
authored
Merge pull request #2144 from trail-of-forks/deterministic-nonce
Add support for setting the nonce type and digest on a PKEY_CTX
2 parents 5e10531 + 14c8247 commit 84162bf

File tree

7 files changed

+144
-0
lines changed

7 files changed

+144
-0
lines changed

openssl-sys/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
* Added `OSSL_PARAM`, `OSSL_PARAM_construct_uint` , `OSSL_PARAM_construct_end`.
8+
* Added `EVP_PKEY_CTX_set_params` and `EVP_PKEY_CTX_get_params`.
9+
510
## [v0.9.99] - 2024-01-19
611

712
### Added

openssl-sys/src/handwritten/evp.rs

+6
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,

openssl-sys/src/handwritten/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub use self::hmac::*;
1515
pub use self::kdf::*;
1616
pub use self::object::*;
1717
pub use self::ocsp::*;
18+
pub use self::params::*;
1819
pub use self::pem::*;
1920
pub use self::pkcs12::*;
2021
pub use self::pkcs7::*;
@@ -51,6 +52,7 @@ mod hmac;
5152
mod kdf;
5253
mod object;
5354
mod ocsp;
55+
mod params;
5456
mod pem;
5557
mod pkcs12;
5658
mod pkcs7;

openssl-sys/src/handwritten/params.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use super::super::*;
2+
use libc::*;
3+
4+
extern "C" {
5+
#[cfg(ossl300)]
6+
pub fn OSSL_PARAM_construct_uint(key: *const c_char, buf: *mut c_uint) -> OSSL_PARAM;
7+
#[cfg(ossl300)]
8+
pub fn OSSL_PARAM_construct_end() -> OSSL_PARAM;
9+
}

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
6+
7+
* Added `PkeyCtxRef::{nonce_type, set_nonce_type}`.
8+
59
## [v0.10.63] - 2024-01-19
610

711
### Added

openssl/src/pkey_ctx.rs

+108
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,12 @@ use crate::{cvt, cvt_p};
7575
use foreign_types::{ForeignType, ForeignTypeRef};
7676
#[cfg(not(boringssl))]
7777
use libc::c_int;
78+
#[cfg(ossl320)]
79+
use libc::c_uint;
7880
use openssl_macros::corresponds;
7981
use std::convert::TryFrom;
82+
#[cfg(ossl320)]
83+
use std::ffi::CStr;
8084
use std::ptr;
8185

8286
/// HKDF modes of operation.
@@ -105,6 +109,21 @@ impl HkdfMode {
105109
pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
106110
}
107111

112+
/// Nonce type for ECDSA and DSA.
113+
#[cfg(ossl320)]
114+
#[derive(Debug, PartialEq)]
115+
pub struct NonceType(c_uint);
116+
117+
#[cfg(ossl320)]
118+
impl NonceType {
119+
/// This is the default mode. It uses a random value for the nonce k as defined in FIPS 186-4 Section 6.3
120+
/// “Secret Number Generation”.
121+
pub const RANDOM_K: Self = NonceType(0);
122+
123+
/// Uses a deterministic value for the nonce k as defined in RFC #6979 (See Section 3.2 “Generation of k”).
124+
pub const DETERMINISTIC_K: Self = NonceType(1);
125+
}
126+
108127
generic_foreign_type_and_impl_send_sync! {
109128
type CType = ffi::EVP_PKEY_CTX;
110129
fn drop = ffi::EVP_PKEY_CTX_free;
@@ -714,6 +733,53 @@ impl<T> PkeyCtxRef<T> {
714733
Ok(PKey::from_ptr(key))
715734
}
716735
}
736+
737+
/// Sets the nonce type for a private key context.
738+
///
739+
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
740+
///
741+
/// This is only useful for DSA and ECDSA.
742+
/// Requires OpenSSL 3.2.0 or newer.
743+
#[cfg(ossl320)]
744+
#[corresponds(EVP_PKEY_CTX_set_params)]
745+
pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> {
746+
let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap();
747+
let mut nonce_type = nonce_type.0;
748+
unsafe {
749+
let param_nonce =
750+
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
751+
let param_end = ffi::OSSL_PARAM_construct_end();
752+
753+
let params = [param_nonce, param_end];
754+
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
755+
}
756+
Ok(())
757+
}
758+
759+
/// Gets the nonce type for a private key context.
760+
///
761+
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
762+
///
763+
/// This is only useful for DSA and ECDSA.
764+
/// Requires OpenSSL 3.2.0 or newer.
765+
#[cfg(ossl320)]
766+
#[corresponds(EVP_PKEY_CTX_get_params)]
767+
pub fn nonce_type(&mut self) -> Result<NonceType, ErrorStack> {
768+
let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap();
769+
let mut nonce_type: c_uint = 0;
770+
unsafe {
771+
let param_nonce =
772+
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
773+
let param_end = ffi::OSSL_PARAM_construct_end();
774+
775+
let mut params = [param_nonce, param_end];
776+
cvt(ffi::EVP_PKEY_CTX_get_params(
777+
self.as_ptr(),
778+
params.as_mut_ptr(),
779+
))?;
780+
}
781+
Ok(NonceType(nonce_type))
782+
}
717783
}
718784

719785
#[cfg(test)]
@@ -999,4 +1065,46 @@ mod test {
9991065
// The digest is the end of the DigestInfo structure.
10001066
assert_eq!(result_buf[length - digest.len()..length], digest);
10011067
}
1068+
1069+
#[test]
1070+
#[cfg(ossl320)]
1071+
fn set_nonce_type() {
1072+
let key1 =
1073+
EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
1074+
let key1 = PKey::from_ec_key(key1).unwrap();
1075+
1076+
let mut ctx = PkeyCtx::new(&key1).unwrap();
1077+
ctx.sign_init().unwrap();
1078+
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();
1079+
let nonce_type = ctx.nonce_type().unwrap();
1080+
assert_eq!(nonce_type, NonceType::DETERMINISTIC_K);
1081+
assert!(ErrorStack::get().errors().is_empty());
1082+
}
1083+
1084+
// Test vector from
1085+
// https://github.com/openssl/openssl/blob/openssl-3.2.0/test/recipes/30-test_evp_data/evppkey_ecdsa_rfc6979.txt
1086+
#[test]
1087+
#[cfg(ossl320)]
1088+
fn ecdsa_deterministic_signature() {
1089+
let private_key_pem = "-----BEGIN PRIVATE KEY-----
1090+
MDkCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEHzAdAgEBBBhvqwNJNOTA/Jrmf1tWWanX0f79GH7g
1091+
n9Q=
1092+
-----END PRIVATE KEY-----";
1093+
1094+
let key1 = EcKey::private_key_from_pem(private_key_pem.as_bytes()).unwrap();
1095+
let key1 = PKey::from_ec_key(key1).unwrap();
1096+
let input = "sample";
1097+
let expected_output = hex::decode("303502190098C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF021857A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64").unwrap();
1098+
1099+
let hashed_input = hash(MessageDigest::sha1(), input.as_bytes()).unwrap();
1100+
let mut ctx = PkeyCtx::new(&key1).unwrap();
1101+
ctx.sign_init().unwrap();
1102+
ctx.set_signature_md(Md::sha1()).unwrap();
1103+
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();
1104+
1105+
let mut output = vec![];
1106+
ctx.sign_to_vec(&hashed_input, &mut output).unwrap();
1107+
assert_eq!(output, expected_output);
1108+
assert!(ErrorStack::get().errors().is_empty());
1109+
}
10021110
}

0 commit comments

Comments
 (0)