Skip to content

Commit

Permalink
Merge pull request #2076 from jmayclin/temp-key
Browse files Browse the repository at this point in the history
add temp key bindings
  • Loading branch information
sfackler authored Nov 10, 2023
2 parents 9db259a + 4965ce9 commit f89c20b
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 1 deletion.
15 changes: 15 additions & 0 deletions openssl-sys/src/ssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94;
pub const SSL_CTRL_SET_SIGALGS_LIST: c_int = 98;
#[cfg(ossl102)]
pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106;
#[cfg(ossl300)]
pub const SSL_CTRL_GET_PEER_TMP_KEY: c_int = 109;
#[cfg(ossl110)]
pub const SSL_CTRL_GET_EXTMS_SUPPORT: c_int = 122;
#[cfg(any(ossl110, libressl261))]
Expand All @@ -359,6 +361,8 @@ pub const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124;
pub const SSL_CTRL_GET_MIN_PROTO_VERSION: c_int = 130;
#[cfg(any(ossl110g, libressl270))]
pub const SSL_CTRL_GET_MAX_PROTO_VERSION: c_int = 131;
#[cfg(ossl300)]
pub const SSL_CTRL_GET_TMP_KEY: c_int = 133;

pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void)
Expand Down Expand Up @@ -506,6 +510,17 @@ cfg_if! {
}
}
}
cfg_if! {
if #[cfg(ossl300)] {
pub unsafe fn SSL_get_peer_tmp_key(ssl: *mut SSL, key: *mut *mut EVP_PKEY) -> c_long {
SSL_ctrl(ssl, SSL_CTRL_GET_PEER_TMP_KEY, 0, key as *mut c_void)
}

pub unsafe fn SSL_get_tmp_key(ssl: *mut SSL, key: *mut *mut EVP_PKEY) -> c_long {
SSL_ctrl(ssl, SSL_CTRL_GET_TMP_KEY, 0, key as *mut c_void)
}
}
}

#[cfg(ossl111)]
pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1;
Expand Down
15 changes: 15 additions & 0 deletions openssl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@
pub use ffi::init;

use libc::c_int;
#[cfg(ossl300)]
use libc::c_long;

use crate::error::ErrorStack;

Expand Down Expand Up @@ -212,6 +214,19 @@ fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
}
}

// cvt_long is currently only used in functions that require openssl >= 3.0.0,
// so this cfg statement is used to avoid "unused function" errors when
// compiling with openssl < 3.0.0
#[inline]
#[cfg(ossl300)]
fn cvt_long(r: c_long) -> Result<c_long, ErrorStack> {
if r <= 0 {
Err(ErrorStack::get())
} else {
Ok(r)
}
}

#[inline]
fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
if r < 0 {
Expand Down
36 changes: 36 additions & 0 deletions openssl/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
//! }
//! }
//! ```
#[cfg(ossl300)]
use crate::cvt_long;
use crate::dh::{Dh, DhRef};
#[cfg(all(ossl101, not(ossl110)))]
use crate::ec::EcKey;
Expand All @@ -68,6 +70,8 @@ use crate::hash::MessageDigest;
#[cfg(any(ossl110, libressl270))]
use crate::nid::Nid;
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
#[cfg(ossl300)]
use crate::pkey::{PKey, Public};
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
use crate::ssl::bio::BioMethod;
use crate::ssl::callbacks::*;
Expand Down Expand Up @@ -3445,6 +3449,38 @@ impl SslRef {
pub fn security_level(&self) -> u32 {
unsafe { ffi::SSL_get_security_level(self.as_ptr()) as u32 }
}

/// Get the temporary key provided by the peer that is used during key
/// exchange.
// We use an owned value because EVP_KEY free need to be called when it is
// dropped
#[corresponds(SSL_get_peer_tmp_key)]
#[cfg(ossl300)]
pub fn peer_tmp_key(&self) -> Result<PKey<Public>, ErrorStack> {
unsafe {
let mut key = ptr::null_mut();
match cvt_long(ffi::SSL_get_peer_tmp_key(self.as_ptr(), &mut key)) {
Ok(_) => Ok(PKey::<Public>::from_ptr(key)),
Err(e) => Err(e),
}
}
}

/// Returns the temporary key from the local end of the connection that is
/// used during key exchange.
// We use an owned value because EVP_KEY free need to be called when it is
// dropped
#[corresponds(SSL_get_tmp_key)]
#[cfg(ossl300)]
pub fn tmp_key(&self) -> Result<PKey<Private>, ErrorStack> {
unsafe {
let mut key = ptr::null_mut();
match cvt_long(ffi::SSL_get_tmp_key(self.as_ptr(), &mut key)) {
Ok(_) => Ok(PKey::<Private>::from_ptr(key)),
Err(e) => Err(e),
}
}
}
}

/// An SSL stream midway through the handshake process.
Expand Down
52 changes: 51 additions & 1 deletion openssl/src/ssl/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::error::ErrorStack;
use crate::hash::MessageDigest;
#[cfg(not(boringssl))]
use crate::ocsp::{OcspResponse, OcspResponseStatus};
use crate::pkey::PKey;
use crate::pkey::{Id, PKey};
use crate::srtp::SrtpProfileId;
use crate::ssl::test::server::Server;
#[cfg(any(ossl110, ossl111, libressl261))]
Expand Down Expand Up @@ -322,6 +322,56 @@ fn state() {
);
}

// when a connection uses ECDHE P-384 key exchange, then the temp key APIs
// return P-384 keys, and the peer and local keys are different.
#[test]
#[cfg(ossl300)]
fn peer_tmp_key_p384() {
let mut server = Server::builder();
server.ctx().set_groups_list("P-384").unwrap();
let server = server.build();
let s = server.client().connect();
let peer_temp = s.ssl().peer_tmp_key().unwrap();
assert_eq!(peer_temp.id(), Id::EC);
assert_eq!(peer_temp.bits(), 384);

let local_temp = s.ssl().tmp_key().unwrap();
assert_eq!(local_temp.id(), Id::EC);
assert_eq!(local_temp.bits(), 384);

assert_ne!(
peer_temp.ec_key().unwrap().public_key_to_der().unwrap(),
local_temp.ec_key().unwrap().public_key_to_der().unwrap(),
);
}

// when a connection uses RSA key exchange, then the peer (server) temp key is
// an Error because there is no temp key, and the local (client) temp key is the
// temp key sent in the initial key share.
#[test]
#[cfg(ossl300)]
fn peer_tmp_key_rsa() {
let mut server = Server::builder();
server.ctx().set_cipher_list("RSA").unwrap();
// RSA key exchange is not allowed in TLS 1.3, so force the connection
// to negotiate TLS 1.2
server
.ctx()
.set_max_proto_version(Some(SslVersion::TLS1_2))
.unwrap();
let server = server.build();
let mut client = server.client();
client.ctx().set_groups_list("P-521").unwrap();
let s = client.connect();
let peer_temp = s.ssl().peer_tmp_key();
assert!(peer_temp.is_err());

// this is the temp key that the client sent in the initial key share
let local_temp = s.ssl().tmp_key().unwrap();
assert_eq!(local_temp.id(), Id::EC);
assert_eq!(local_temp.bits(), 521);
}

/// Tests that when both the client as well as the server use SRTP and their
/// lists of supported protocols have an overlap -- with only ONE protocol
/// being valid for both.
Expand Down

0 comments on commit f89c20b

Please sign in to comment.