diff options
| author | Marko Lalic <[email protected]> | 2015-03-18 15:50:29 +0100 |
|---|---|---|
| committer | Marko Lalic <[email protected]> | 2015-03-23 08:41:15 +0100 |
| commit | 5689ad9260c8d90a738bf9d830186a1b31c05a7f (patch) | |
| tree | db9d8baba484ed3215209516440b9ed6e2f9cba6 /openssl/src | |
| parent | openssl: Add method for setting protocols to be used in NPN (diff) | |
| download | rust-openssl-5689ad9260c8d90a738bf9d830186a1b31c05a7f.tar.xz rust-openssl-5689ad9260c8d90a738bf9d830186a1b31c05a7f.zip | |
openssl: Implement client-side NPN protocol selection
After the `set_npn_protocols` method of the `SslContext` struct is
called, any future TLS connections established with this context will
perform NPN negotiation.
The chosen protocol is the one with the highest priority in the
server's protocol list that is also in the client's protocol list.
(This is the default behavior provided by OpenSSL's
`SSL_select_next_proto` function.)
If there is no overlap between the two lists, no error is raised.
Diffstat (limited to 'openssl/src')
| -rw-r--r-- | openssl/src/ssl/mod.rs | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 058231ca..e06d613b 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_void, c_long}; +use libc::{c_int, c_void, c_long, c_uint, c_uchar}; use std::ffi::{CStr, CString}; use std::fmt; use std::io; @@ -6,6 +6,7 @@ use std::io::prelude::*; use std::ffi::AsOsStr; use std::mem; use std::net; +use std::slice; use std::num::FromPrimitive; use std::num::Int; use std::path::Path; @@ -220,6 +221,34 @@ extern fn raw_verify_with_data<T>(preverify_ok: c_int, } } +/// The function is given as the callback to `SSL_CTX_set_next_proto_select_cb`. +/// +/// It chooses the protocol that the client wishes to use, out of the given list of protocols +/// supported by the server. It achieves this by delegating to the `SSL_select_next_proto` +/// function. The list of protocols supported by the client is found in the extra data of the +/// OpenSSL context. +#[cfg(feature = "npn")] +extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL, + out: *mut *mut c_uchar, outlen: *mut c_uchar, + inbuf: *const c_uchar, inlen: c_uint, + _arg: *mut c_void) -> c_int { + unsafe { + // First, get the list of protocols (that the client should support) saved in the context + // extra data. + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx()); + let protocols: &Vec<u8> = mem::transmute(protocols); + // Prepare the client list parameters to be passed to the OpenSSL function... + let client = protocols.as_ptr(); + let client_len = protocols.len() as c_uint; + // Finally, let OpenSSL find a protocol to be used, by matching the given server and + // client lists. + ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len); + } + + ffi::SSL_TLSEXT_ERR_OK +} + /// The signature of functions that can be used to manually verify certificates pub type VerifyCallback = fn(preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool; @@ -393,6 +422,10 @@ impl SslContext { // so that we can refer to it within the callback. ffi::SSL_CTX_set_ex_data(*self.ctx, get_npn_protos_idx(), mem::transmute(protocols)); + // Now register the callback that performs the default protocol + // matching based on the client-supported list of protocols that + // has been saved. + ffi::SSL_CTX_set_next_proto_select_cb(*self.ctx, raw_next_proto_select_cb, ptr::null_mut()); } } } |