From c26187aad2d56e8e7cd5dd96983fc791b4c9cc3e Mon Sep 17 00:00:00 2001 From: Huw Jones Date: Tue, 29 Jul 2025 14:58:17 +0100 Subject: [PATCH 1/3] sys/rsa: add EVP_PKEY_CTX set keygen bits & pubexp --- openssl-sys/src/handwritten/rsa.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openssl-sys/src/handwritten/rsa.rs b/openssl-sys/src/handwritten/rsa.rs index d05edfc301..ec619fc57a 100644 --- a/openssl-sys/src/handwritten/rsa.rs +++ b/openssl-sys/src/handwritten/rsa.rs @@ -4,6 +4,9 @@ use libc::*; cfg_if! { if #[cfg(ossl300)] { extern "C" { + pub fn EVP_PKEY_CTX_set_rsa_keygen_bits(ctx: *mut EVP_PKEY_CTX, bits: c_int) -> c_int; + pub fn EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx: *mut EVP_PKEY_CTX, pubexp: *mut BIGNUM) -> c_int; + pub fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad_mode: c_int) -> c_int; pub fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad_mode: *mut c_int) -> c_int; From 8d7699d351f382aa5cda83bc88a748d3d5b72367 Mon Sep 17 00:00:00 2001 From: Huw Jones Date: Tue, 29 Jul 2025 16:17:50 +0100 Subject: [PATCH 2/3] pkey_ctx: add set rsa keygen set bits & pubexp --- openssl-sys/src/rsa.rs | 22 +++++++++++++++++++++ openssl/src/pkey_ctx.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/openssl-sys/src/rsa.rs b/openssl-sys/src/rsa.rs index 64107cd6b2..36b8564ec2 100644 --- a/openssl-sys/src/rsa.rs +++ b/openssl-sys/src/rsa.rs @@ -7,6 +7,26 @@ pub const RSA_F4: c_long = 0x10001; cfg_if! { if #[cfg(not(ossl300))] { + pub unsafe fn EVP_PKEY_CTX_set_rsa_keygen_bits(ctx: *mut EVP_PKEY_CTX, bits: c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_BITS, + bits, + ptr::null_mut(), + ) + } + pub unsafe fn EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx: *mut EVP_PKEY_CTX, pubexp: *mut BIGNUM) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, + 0, + pubexp as *mut _, + ) + } pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { EVP_PKEY_CTX_ctrl( ctx, @@ -82,6 +102,8 @@ pub unsafe fn EVP_PKEY_CTX_set0_rsa_oaep_label( pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2; +pub const EVP_PKEY_CTRL_RSA_KEYGEN_BITS: c_int = EVP_PKEY_ALG_CTRL + 3; +pub const EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP: c_int = EVP_PKEY_ALG_CTRL + 4; pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5; diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs index 7ad663dee3..243669ce39 100644 --- a/openssl/src/pkey_ctx.rs +++ b/openssl/src/pkey_ctx.rs @@ -64,6 +64,7 @@ let cmac_key = ctx.keygen().unwrap(); //! let valid = ctx.verify(text, &signature).unwrap(); //! assert!(valid); //! ``` +use crate::bn::BigNumRef; #[cfg(not(any(boringssl, awslc)))] use crate::cipher::CipherRef; use crate::error::ErrorStack; @@ -73,6 +74,7 @@ use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Params, Private}; use crate::rsa::Padding; use crate::sign::RsaPssSaltlen; use crate::{cvt, cvt_p}; +use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; #[cfg(not(any(boringssl, awslc)))] use libc::c_int; @@ -544,6 +546,48 @@ impl PkeyCtxRef { Ok(()) } + /// Sets the RSA keygen bits. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set_rsa_keygen_bits)] + #[inline] + pub fn set_rsa_keygen_bits(&mut self, bits: u32) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_keygen_bits( + self.as_ptr(), + bits as i32, + ))?; + } + + Ok(()) + } + + /// Sets the RSA keygen public exponent. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set1_rsa_keygen_pubexp)] + #[inline] + pub fn set_rsa_keygen_pubexp(&mut self, pubexp: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cfg_if! { + if #[cfg(ossl300)] { + cvt(ffi::EVP_PKEY_CTX_set1_rsa_keygen_pubexp( + self.as_ptr(), + pubexp.as_ptr(), + ))?; + } else { + cvt(ffi::EVP_PKEY_CTX_set_rsa_keygen_pubexp( + self.as_ptr(), + // Dupe the BN because the EVP_PKEY_CTX takes ownership of it and will free it. + cvt_p(ffi::BN_dup(pubexp.as_ptr()))?, + ))?; + } + } + } + + Ok(()) + } + /// Sets the RSA PSS salt length. /// /// This is only useful for RSA keys. From a51da3d3fae5f7c7d8a968ae0ded75de11879b86 Mon Sep 17 00:00:00 2001 From: Huw Jones Date: Wed, 30 Jul 2025 10:24:55 +0100 Subject: [PATCH 3/3] pkey_ctx: add rsa key generation test --- openssl/src/pkey_ctx.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs index 243669ce39..1b58108aed 100644 --- a/openssl/src/pkey_ctx.rs +++ b/openssl/src/pkey_ctx.rs @@ -918,6 +918,7 @@ impl PkeyCtxRef { #[cfg(test)] mod test { use super::*; + use crate::bn::BigNum; #[cfg(not(any(boringssl, awslc)))] use crate::cipher::Cipher; use crate::ec::{EcGroup, EcKey}; @@ -1101,6 +1102,18 @@ mod test { assert_eq!(params.size(), 72); } + #[test] + fn rsa_keygen() { + let pubexp = BigNum::from_u32(65537).unwrap(); + let mut ctx = PkeyCtx::new_id(Id::RSA).unwrap(); + ctx.keygen_init().unwrap(); + ctx.set_rsa_keygen_pubexp(&pubexp).unwrap(); + ctx.set_rsa_keygen_bits(2048).unwrap(); + let key = ctx.keygen().unwrap(); + + assert_eq!(key.bits(), 2048); + } + #[test] #[cfg(any(ossl110, boringssl, libressl360, awslc))] fn hkdf() {