Merge pull request #920 from Ralith/max-early-data-accessors
TLS1.3 early data support
This commit is contained in:
commit
c7db3d18ad
|
|
@ -2839,4 +2839,7 @@ extern "C" {
|
||||||
|
|
||||||
pub fn EVP_MD_size(md: *const EVP_MD) -> c_int;
|
pub fn EVP_MD_size(md: *const EVP_MD) -> c_int;
|
||||||
pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER;
|
pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER;
|
||||||
|
|
||||||
|
pub fn SSL_set_connect_state(s: *mut SSL);
|
||||||
|
pub fn SSL_set_accept_state(s: *mut SSL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,9 @@ pub const SSL_EXT_TLS1_3_CERTIFICATE: c_uint = 0x1000;
|
||||||
pub const SSL_EXT_TLS1_3_NEW_SESSION_TICKET: c_uint = 0x2000;
|
pub const SSL_EXT_TLS1_3_NEW_SESSION_TICKET: c_uint = 0x2000;
|
||||||
pub const SSL_EXT_TLS1_3_CERTIFICATE_REQUEST: c_uint = 0x4000;
|
pub const SSL_EXT_TLS1_3_CERTIFICATE_REQUEST: c_uint = 0x4000;
|
||||||
|
|
||||||
|
pub const SSL_READ_EARLY_DATA_ERROR: c_int = 0;
|
||||||
|
pub const SSL_READ_EARLY_DATA_SUCCESS: c_int = 1;
|
||||||
|
pub const SSL_READ_EARLY_DATA_FINISH: c_int = 2;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn SSL_CTX_set_keylog_callback(ctx: *mut ::SSL_CTX, cb: SSL_CTX_keylog_cb_func);
|
pub fn SSL_CTX_set_keylog_callback(ctx: *mut ::SSL_CTX, cb: SSL_CTX_keylog_cb_func);
|
||||||
|
|
@ -82,4 +85,24 @@ extern "C" {
|
||||||
cookie_len: size_t
|
cookie_len: size_t
|
||||||
) -> c_int>
|
) -> c_int>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pub fn SSL_CTX_set_max_early_data(ctx: *mut ::SSL_CTX, max_early_data: u32) -> c_int;
|
||||||
|
pub fn SSL_CTX_get_max_early_data(ctx: *const ::SSL_CTX) -> u32;
|
||||||
|
pub fn SSL_set_max_early_data(ctx: *mut ::SSL, max_early_data: u32) -> c_int;
|
||||||
|
pub fn SSL_get_max_early_data(ctx: *const ::SSL) -> u32;
|
||||||
|
pub fn SSL_SESSION_set_max_early_data(ctx: *mut ::SSL_SESSION, max_early_data: u32) -> c_int;
|
||||||
|
pub fn SSL_SESSION_get_max_early_data(ctx: *const ::SSL_SESSION) -> u32;
|
||||||
|
|
||||||
|
pub fn SSL_export_keying_material_early(
|
||||||
|
s: *mut ::SSL,
|
||||||
|
out: *mut c_uchar,
|
||||||
|
olen: size_t,
|
||||||
|
label: *const c_char,
|
||||||
|
llen: size_t,
|
||||||
|
context: *const c_uchar,
|
||||||
|
contextlen: size_t,
|
||||||
|
) -> c_int;
|
||||||
|
|
||||||
|
pub fn SSL_write_early_data(s: *mut ::SSL, buf: *const c_void, num: size_t, written: *mut size_t) -> c_int;
|
||||||
|
pub fn SSL_read_early_data(s: *mut ::SSL, buf: *mut c_void, num: size_t, readbytes: *mut size_t) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1490,6 +1490,24 @@ impl SslContextBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum amount of early data that will be accepted on incoming connections.
|
||||||
|
///
|
||||||
|
/// Defaults to 0.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_CTX_set_max_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_CTX_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_max_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
|
||||||
|
if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorStack::get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes the builder, returning a new `SslContext`.
|
/// Consumes the builder, returning a new `SslContext`.
|
||||||
pub fn build(self) -> SslContext {
|
pub fn build(self) -> SslContext {
|
||||||
self.0
|
self.0
|
||||||
|
|
@ -1644,6 +1662,18 @@ impl SslContextRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the maximum amount of early data that will be accepted on incoming connections.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_CTX_get_max_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_CTX_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_max_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn max_early_data(&self) -> u32 {
|
||||||
|
unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the state of a cipher.
|
/// Information about the state of a cipher.
|
||||||
|
|
@ -1874,6 +1904,18 @@ impl SslSessionRef {
|
||||||
unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
|
unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the maximum amount of early data that can be sent on this session.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_SESSION_get_max_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_SESSION_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_max_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn max_early_data(&self) -> u32 {
|
||||||
|
unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) }
|
||||||
|
}
|
||||||
|
|
||||||
to_der! {
|
to_der! {
|
||||||
/// Serializes the session into a DER-encoded structure.
|
/// Serializes the session into a DER-encoded structure.
|
||||||
///
|
///
|
||||||
|
|
@ -2457,6 +2499,36 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derives keying material for application use in accordance to RFC 5705.
|
||||||
|
///
|
||||||
|
/// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no
|
||||||
|
/// context. Therefore, unlike `export_keying_material`, `context` must always be supplied.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_export_keying_material_early`].
|
||||||
|
///
|
||||||
|
/// [`SSL_export_keying_material_early`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material_early.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn export_keying_material_early(
|
||||||
|
&self,
|
||||||
|
out: &mut [u8],
|
||||||
|
label: &str,
|
||||||
|
context: &[u8],
|
||||||
|
) -> Result<(), ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::SSL_export_keying_material_early(
|
||||||
|
self.as_ptr(),
|
||||||
|
out.as_mut_ptr() as *mut c_uchar,
|
||||||
|
out.len(),
|
||||||
|
label.as_ptr() as *const c_char,
|
||||||
|
label.len(),
|
||||||
|
context.as_ptr() as *const c_uchar,
|
||||||
|
context.len(),
|
||||||
|
)).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the session to be used.
|
/// Sets the session to be used.
|
||||||
///
|
///
|
||||||
/// This should be called before the handshake to attempt to reuse a previously established
|
/// This should be called before the handshake to attempt to reuse a previously established
|
||||||
|
|
@ -2595,6 +2667,34 @@ impl SslRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum amount of early data that will be accepted on this connection.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_set_max_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_max_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
|
||||||
|
if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorStack::get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the maximum amount of early data that can be sent on this connection.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_get_max_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn max_early_data(&self) -> u32 {
|
||||||
|
unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An SSL stream midway through the handshake process.
|
/// An SSL stream midway through the handshake process.
|
||||||
|
|
@ -2907,6 +3007,24 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure as an outgoing stream from a client.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_set_connect_state`].
|
||||||
|
///
|
||||||
|
/// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html
|
||||||
|
pub fn set_connect_state(&mut self) {
|
||||||
|
unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure as an incoming stream to a server.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_set_accept_state`].
|
||||||
|
///
|
||||||
|
/// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html
|
||||||
|
pub fn set_accept_state(&mut self) {
|
||||||
|
unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) }
|
||||||
|
}
|
||||||
|
|
||||||
/// See `Ssl::connect`
|
/// See `Ssl::connect`
|
||||||
pub fn connect(self) -> Result<SslStream<S>, HandshakeError<S>> {
|
pub fn connect(self) -> Result<SslStream<S>, HandshakeError<S>> {
|
||||||
let mut stream = self.inner;
|
let mut stream = self.inner;
|
||||||
|
|
@ -2947,7 +3065,74 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future work: early IO methods
|
/// Initiates the handshake.
|
||||||
|
///
|
||||||
|
/// This will fail if `set_accept_state` or `set_connect_state` was not called first.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_do_handshake`].
|
||||||
|
///
|
||||||
|
/// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
|
||||||
|
pub fn handshake(self) -> Result<SslStream<S>, HandshakeError<S>> {
|
||||||
|
let mut stream = self.inner;
|
||||||
|
let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) };
|
||||||
|
if ret > 0 {
|
||||||
|
Ok(stream)
|
||||||
|
} else {
|
||||||
|
let error = stream.make_error(ret);
|
||||||
|
match error.code() {
|
||||||
|
ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
|
||||||
|
Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error }))
|
||||||
|
}
|
||||||
|
_ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream, error })),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read application data transmitted by a client before handshake
|
||||||
|
/// completion.
|
||||||
|
///
|
||||||
|
/// Useful for reducing latency, but vulnerable to replay attacks. Call
|
||||||
|
/// `set_accept_state` first.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(0)` if all early data has been read.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_read_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
let mut read = 0;
|
||||||
|
let ret = unsafe { ffi::SSL_read_early_data(self.inner.ssl.as_ptr(), buf.as_ptr() as *mut c_void, buf.len(), &mut read) };
|
||||||
|
match ret {
|
||||||
|
ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)),
|
||||||
|
ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read),
|
||||||
|
ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send data to the server without blocking on handshake completion.
|
||||||
|
///
|
||||||
|
/// Useful for reducing latency, but vulnerable to replay attacks. Call
|
||||||
|
/// `set_connect_state` first.
|
||||||
|
///
|
||||||
|
/// Requires OpenSSL 1.1.1 or newer.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`SSL_write_early_data`].
|
||||||
|
///
|
||||||
|
/// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
|
let mut written = 0;
|
||||||
|
let ret = unsafe { ffi::SSL_write_early_data(self.inner.ssl.as_ptr(), buf.as_ptr() as *const c_void, buf.len(), &mut written) };
|
||||||
|
if ret > 0 {
|
||||||
|
Ok(written as usize)
|
||||||
|
} else {
|
||||||
|
Err(self.inner.make_error(ret))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> SslStreamBuilder<S> {
|
impl<S> SslStreamBuilder<S> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue