Skip to content

Commit

Permalink
Merge pull request #2144 from trail-of-forks/deterministic-nonce
Browse files Browse the repository at this point in the history
Add support for setting the nonce type and digest on a PKEY_CTX
  • Loading branch information
alex authored Feb 8, 2024
2 parents 5e10531 + 14c8247 commit 84162bf
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 0 deletions.
5 changes: 5 additions & 0 deletions openssl-sys/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## [Unreleased]

### Added

* Added `OSSL_PARAM`, `OSSL_PARAM_construct_uint` , `OSSL_PARAM_construct_end`.
* Added `EVP_PKEY_CTX_set_params` and `EVP_PKEY_CTX_get_params`.

## [v0.9.99] - 2024-01-19

### Added
Expand Down
6 changes: 6 additions & 0 deletions openssl-sys/src/handwritten/evp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,12 @@ extern "C" {
#[cfg(ossl300)]
pub fn EVP_PKEY_CTX_set_signature_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int;

#[cfg(ossl300)]
pub fn EVP_PKEY_CTX_set_params(ctx: *mut EVP_PKEY_CTX, params: *const OSSL_PARAM) -> c_int;

#[cfg(ossl300)]
pub fn EVP_PKEY_CTX_get_params(ctx: *mut EVP_PKEY_CTX, params: *mut OSSL_PARAM) -> c_int;

pub fn EVP_PKEY_new_mac_key(
type_: c_int,
e: *mut ENGINE,
Expand Down
2 changes: 2 additions & 0 deletions openssl-sys/src/handwritten/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub use self::hmac::*;
pub use self::kdf::*;
pub use self::object::*;
pub use self::ocsp::*;
pub use self::params::*;
pub use self::pem::*;
pub use self::pkcs12::*;
pub use self::pkcs7::*;
Expand Down Expand Up @@ -51,6 +52,7 @@ mod hmac;
mod kdf;
mod object;
mod ocsp;
mod params;
mod pem;
mod pkcs12;
mod pkcs7;
Expand Down
9 changes: 9 additions & 0 deletions openssl-sys/src/handwritten/params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use super::super::*;
use libc::*;

extern "C" {
#[cfg(ossl300)]
pub fn OSSL_PARAM_construct_uint(key: *const c_char, buf: *mut c_uint) -> OSSL_PARAM;
#[cfg(ossl300)]
pub fn OSSL_PARAM_construct_end() -> OSSL_PARAM;
}
10 changes: 10 additions & 0 deletions openssl-sys/src/handwritten/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1093,3 +1093,13 @@ pub enum OSSL_PROVIDER {}

#[cfg(ossl300)]
pub enum OSSL_LIB_CTX {}

#[cfg(ossl300)]
#[repr(C)]
pub struct OSSL_PARAM {
key: *const c_char,
data_type: c_uchar,
data: *mut c_void,
data_size: size_t,
return_size: size_t,
}
4 changes: 4 additions & 0 deletions openssl/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

* Added `PkeyCtxRef::{nonce_type, set_nonce_type}`.

## [v0.10.63] - 2024-01-19

### Added
Expand Down
108 changes: 108 additions & 0 deletions openssl/src/pkey_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ use crate::{cvt, cvt_p};
use foreign_types::{ForeignType, ForeignTypeRef};
#[cfg(not(boringssl))]
use libc::c_int;
#[cfg(ossl320)]
use libc::c_uint;
use openssl_macros::corresponds;
use std::convert::TryFrom;
#[cfg(ossl320)]
use std::ffi::CStr;
use std::ptr;

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

/// Nonce type for ECDSA and DSA.
#[cfg(ossl320)]
#[derive(Debug, PartialEq)]
pub struct NonceType(c_uint);

#[cfg(ossl320)]
impl NonceType {
/// This is the default mode. It uses a random value for the nonce k as defined in FIPS 186-4 Section 6.3
/// “Secret Number Generation”.
pub const RANDOM_K: Self = NonceType(0);

/// Uses a deterministic value for the nonce k as defined in RFC #6979 (See Section 3.2 “Generation of k”).
pub const DETERMINISTIC_K: Self = NonceType(1);
}

generic_foreign_type_and_impl_send_sync! {
type CType = ffi::EVP_PKEY_CTX;
fn drop = ffi::EVP_PKEY_CTX_free;
Expand Down Expand Up @@ -714,6 +733,53 @@ impl<T> PkeyCtxRef<T> {
Ok(PKey::from_ptr(key))
}
}

/// Sets the nonce type for a private key context.
///
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
///
/// This is only useful for DSA and ECDSA.
/// Requires OpenSSL 3.2.0 or newer.
#[cfg(ossl320)]
#[corresponds(EVP_PKEY_CTX_set_params)]
pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> {
let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap();
let mut nonce_type = nonce_type.0;
unsafe {
let param_nonce =
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
let param_end = ffi::OSSL_PARAM_construct_end();

let params = [param_nonce, param_end];
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
}
Ok(())
}

/// Gets the nonce type for a private key context.
///
/// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979).
///
/// This is only useful for DSA and ECDSA.
/// Requires OpenSSL 3.2.0 or newer.
#[cfg(ossl320)]
#[corresponds(EVP_PKEY_CTX_get_params)]
pub fn nonce_type(&mut self) -> Result<NonceType, ErrorStack> {
let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap();
let mut nonce_type: c_uint = 0;
unsafe {
let param_nonce =
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
let param_end = ffi::OSSL_PARAM_construct_end();

let mut params = [param_nonce, param_end];
cvt(ffi::EVP_PKEY_CTX_get_params(
self.as_ptr(),
params.as_mut_ptr(),
))?;
}
Ok(NonceType(nonce_type))
}
}

#[cfg(test)]
Expand Down Expand Up @@ -999,4 +1065,46 @@ mod test {
// The digest is the end of the DigestInfo structure.
assert_eq!(result_buf[length - digest.len()..length], digest);
}

#[test]
#[cfg(ossl320)]
fn set_nonce_type() {
let key1 =
EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
let key1 = PKey::from_ec_key(key1).unwrap();

let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.sign_init().unwrap();
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();
let nonce_type = ctx.nonce_type().unwrap();
assert_eq!(nonce_type, NonceType::DETERMINISTIC_K);
assert!(ErrorStack::get().errors().is_empty());
}

// Test vector from
// https://github.com/openssl/openssl/blob/openssl-3.2.0/test/recipes/30-test_evp_data/evppkey_ecdsa_rfc6979.txt
#[test]
#[cfg(ossl320)]
fn ecdsa_deterministic_signature() {
let private_key_pem = "-----BEGIN PRIVATE KEY-----
MDkCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEHzAdAgEBBBhvqwNJNOTA/Jrmf1tWWanX0f79GH7g
n9Q=
-----END PRIVATE KEY-----";

let key1 = EcKey::private_key_from_pem(private_key_pem.as_bytes()).unwrap();
let key1 = PKey::from_ec_key(key1).unwrap();
let input = "sample";
let expected_output = hex::decode("303502190098C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF021857A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64").unwrap();

let hashed_input = hash(MessageDigest::sha1(), input.as_bytes()).unwrap();
let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.sign_init().unwrap();
ctx.set_signature_md(Md::sha1()).unwrap();
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();

let mut output = vec![];
ctx.sign_to_vec(&hashed_input, &mut output).unwrap();
assert_eq!(output, expected_output);
assert!(ErrorStack::get().errors().is_empty());
}
}

0 comments on commit 84162bf

Please sign in to comment.