Skip to content

Commit f89c20b

Browse files
authored
Merge pull request #2076 from jmayclin/temp-key
add temp key bindings
2 parents 9db259a + 4965ce9 commit f89c20b

File tree

4 files changed

+117
-1
lines changed

4 files changed

+117
-1
lines changed

openssl-sys/src/ssl.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94;
349349
pub const SSL_CTRL_SET_SIGALGS_LIST: c_int = 98;
350350
#[cfg(ossl102)]
351351
pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106;
352+
#[cfg(ossl300)]
353+
pub const SSL_CTRL_GET_PEER_TMP_KEY: c_int = 109;
352354
#[cfg(ossl110)]
353355
pub const SSL_CTRL_GET_EXTMS_SUPPORT: c_int = 122;
354356
#[cfg(any(ossl110, libressl261))]
@@ -359,6 +361,8 @@ pub const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124;
359361
pub const SSL_CTRL_GET_MIN_PROTO_VERSION: c_int = 130;
360362
#[cfg(any(ossl110g, libressl270))]
361363
pub const SSL_CTRL_GET_MAX_PROTO_VERSION: c_int = 131;
364+
#[cfg(ossl300)]
365+
pub const SSL_CTRL_GET_TMP_KEY: c_int = 133;
362366

363367
pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long {
364368
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void)
@@ -506,6 +510,17 @@ cfg_if! {
506510
}
507511
}
508512
}
513+
cfg_if! {
514+
if #[cfg(ossl300)] {
515+
pub unsafe fn SSL_get_peer_tmp_key(ssl: *mut SSL, key: *mut *mut EVP_PKEY) -> c_long {
516+
SSL_ctrl(ssl, SSL_CTRL_GET_PEER_TMP_KEY, 0, key as *mut c_void)
517+
}
518+
519+
pub unsafe fn SSL_get_tmp_key(ssl: *mut SSL, key: *mut *mut EVP_PKEY) -> c_long {
520+
SSL_ctrl(ssl, SSL_CTRL_GET_TMP_KEY, 0, key as *mut c_void)
521+
}
522+
}
523+
}
509524

510525
#[cfg(ossl111)]
511526
pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1;

openssl/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@
125125
pub use ffi::init;
126126

127127
use libc::c_int;
128+
#[cfg(ossl300)]
129+
use libc::c_long;
128130

129131
use crate::error::ErrorStack;
130132

@@ -212,6 +214,19 @@ fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
212214
}
213215
}
214216

217+
// cvt_long is currently only used in functions that require openssl >= 3.0.0,
218+
// so this cfg statement is used to avoid "unused function" errors when
219+
// compiling with openssl < 3.0.0
220+
#[inline]
221+
#[cfg(ossl300)]
222+
fn cvt_long(r: c_long) -> Result<c_long, ErrorStack> {
223+
if r <= 0 {
224+
Err(ErrorStack::get())
225+
} else {
226+
Ok(r)
227+
}
228+
}
229+
215230
#[inline]
216231
fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
217232
if r < 0 {

openssl/src/ssl/mod.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
//! }
5858
//! }
5959
//! ```
60+
#[cfg(ossl300)]
61+
use crate::cvt_long;
6062
use crate::dh::{Dh, DhRef};
6163
#[cfg(all(ossl101, not(ossl110)))]
6264
use crate::ec::EcKey;
@@ -68,6 +70,8 @@ use crate::hash::MessageDigest;
6870
#[cfg(any(ossl110, libressl270))]
6971
use crate::nid::Nid;
7072
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
73+
#[cfg(ossl300)]
74+
use crate::pkey::{PKey, Public};
7175
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
7276
use crate::ssl::bio::BioMethod;
7377
use crate::ssl::callbacks::*;
@@ -3445,6 +3449,38 @@ impl SslRef {
34453449
pub fn security_level(&self) -> u32 {
34463450
unsafe { ffi::SSL_get_security_level(self.as_ptr()) as u32 }
34473451
}
3452+
3453+
/// Get the temporary key provided by the peer that is used during key
3454+
/// exchange.
3455+
// We use an owned value because EVP_KEY free need to be called when it is
3456+
// dropped
3457+
#[corresponds(SSL_get_peer_tmp_key)]
3458+
#[cfg(ossl300)]
3459+
pub fn peer_tmp_key(&self) -> Result<PKey<Public>, ErrorStack> {
3460+
unsafe {
3461+
let mut key = ptr::null_mut();
3462+
match cvt_long(ffi::SSL_get_peer_tmp_key(self.as_ptr(), &mut key)) {
3463+
Ok(_) => Ok(PKey::<Public>::from_ptr(key)),
3464+
Err(e) => Err(e),
3465+
}
3466+
}
3467+
}
3468+
3469+
/// Returns the temporary key from the local end of the connection that is
3470+
/// used during key exchange.
3471+
// We use an owned value because EVP_KEY free need to be called when it is
3472+
// dropped
3473+
#[corresponds(SSL_get_tmp_key)]
3474+
#[cfg(ossl300)]
3475+
pub fn tmp_key(&self) -> Result<PKey<Private>, ErrorStack> {
3476+
unsafe {
3477+
let mut key = ptr::null_mut();
3478+
match cvt_long(ffi::SSL_get_tmp_key(self.as_ptr(), &mut key)) {
3479+
Ok(_) => Ok(PKey::<Private>::from_ptr(key)),
3480+
Err(e) => Err(e),
3481+
}
3482+
}
3483+
}
34483484
}
34493485

34503486
/// An SSL stream midway through the handshake process.

openssl/src/ssl/test/mod.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::error::ErrorStack;
1919
use crate::hash::MessageDigest;
2020
#[cfg(not(boringssl))]
2121
use crate::ocsp::{OcspResponse, OcspResponseStatus};
22-
use crate::pkey::PKey;
22+
use crate::pkey::{Id, PKey};
2323
use crate::srtp::SrtpProfileId;
2424
use crate::ssl::test::server::Server;
2525
#[cfg(any(ossl110, ossl111, libressl261))]
@@ -322,6 +322,56 @@ fn state() {
322322
);
323323
}
324324

325+
// when a connection uses ECDHE P-384 key exchange, then the temp key APIs
326+
// return P-384 keys, and the peer and local keys are different.
327+
#[test]
328+
#[cfg(ossl300)]
329+
fn peer_tmp_key_p384() {
330+
let mut server = Server::builder();
331+
server.ctx().set_groups_list("P-384").unwrap();
332+
let server = server.build();
333+
let s = server.client().connect();
334+
let peer_temp = s.ssl().peer_tmp_key().unwrap();
335+
assert_eq!(peer_temp.id(), Id::EC);
336+
assert_eq!(peer_temp.bits(), 384);
337+
338+
let local_temp = s.ssl().tmp_key().unwrap();
339+
assert_eq!(local_temp.id(), Id::EC);
340+
assert_eq!(local_temp.bits(), 384);
341+
342+
assert_ne!(
343+
peer_temp.ec_key().unwrap().public_key_to_der().unwrap(),
344+
local_temp.ec_key().unwrap().public_key_to_der().unwrap(),
345+
);
346+
}
347+
348+
// when a connection uses RSA key exchange, then the peer (server) temp key is
349+
// an Error because there is no temp key, and the local (client) temp key is the
350+
// temp key sent in the initial key share.
351+
#[test]
352+
#[cfg(ossl300)]
353+
fn peer_tmp_key_rsa() {
354+
let mut server = Server::builder();
355+
server.ctx().set_cipher_list("RSA").unwrap();
356+
// RSA key exchange is not allowed in TLS 1.3, so force the connection
357+
// to negotiate TLS 1.2
358+
server
359+
.ctx()
360+
.set_max_proto_version(Some(SslVersion::TLS1_2))
361+
.unwrap();
362+
let server = server.build();
363+
let mut client = server.client();
364+
client.ctx().set_groups_list("P-521").unwrap();
365+
let s = client.connect();
366+
let peer_temp = s.ssl().peer_tmp_key();
367+
assert!(peer_temp.is_err());
368+
369+
// this is the temp key that the client sent in the initial key share
370+
let local_temp = s.ssl().tmp_key().unwrap();
371+
assert_eq!(local_temp.id(), Id::EC);
372+
assert_eq!(local_temp.bits(), 521);
373+
}
374+
325375
/// Tests that when both the client as well as the server use SRTP and their
326376
/// lists of supported protocols have an overlap -- with only ONE protocol
327377
/// being valid for both.

0 commit comments

Comments
 (0)