Unverified Commit f89c20b7 authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #2076 from jmayclin/temp-key

add temp key bindings
parents 9db259a1 4965ce9f
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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))]
@@ -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)
@@ -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;
+15 −0
Original line number Diff line number Diff line
@@ -125,6 +125,8 @@
pub use ffi::init;

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

use crate::error::ErrorStack;

@@ -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 {
+36 −0
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@
//!     }
//! }
//! ```
#[cfg(ossl300)]
use crate::cvt_long;
use crate::dh::{Dh, DhRef};
#[cfg(all(ossl101, not(ossl110)))]
use crate::ec::EcKey;
@@ -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::*;
@@ -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.
+51 −1
Original line number Diff line number Diff line
@@ -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))]
@@ -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.