Channel binding support in tokio-postgres

This commit is contained in:
Steven Fackler 2018-06-26 21:17:04 -07:00
parent 705ef7d5b2
commit 6edab70b0e
3 changed files with 65 additions and 7 deletions

View File

@ -11,7 +11,7 @@ extern crate tokio;
use bytes::{Buf, BufMut};
use futures::{Future, IntoFuture, Poll};
use openssl::error::ErrorStack;
use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod};
use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod, SslRef};
use std::error::Error;
use std::io::{self, Read, Write};
use tokio_io::{AsyncRead, AsyncWrite};
@ -124,4 +124,18 @@ impl AsyncWrite for SslStream {
}
}
impl TlsStream for SslStream {}
impl TlsStream for SslStream {
fn tls_unique(&self) -> Option<Vec<u8>> {
let f = if self.0.get_ref().ssl().session_reused() {
SslRef::peer_finished
} else {
SslRef::finished
};
let len = f(self.0.get_ref().ssl(), &mut []);
let mut buf = vec![0; len];
f(self.0.get_ref().ssl(), &mut buf);
Some(buf)
}
}

View File

@ -263,25 +263,49 @@ impl PollHandshake for Handshake {
let pass = state.user.password().ok_or_else(missing_password)?;
let mut has_scram = false;
let mut has_scram_plus = false;
let mut mechanisms = body.mechanisms();
while let Some(mechanism) = mechanisms.next()? {
match mechanism {
sasl::SCRAM_SHA_256 => has_scram = true,
sasl::SCRAM_SHA_256_PLUS => has_scram_plus = true,
_ => {}
}
}
let channel_binding = state
.stream
.get_ref()
.tls_unique()
.map(ChannelBinding::tls_unique)
.or_else(|| {
state
.stream
.get_ref()
.tls_server_end_point()
.map(ChannelBinding::tls_server_end_point)
});
if !has_scram {
let (channel_binding, mechanism) = if has_scram_plus {
match channel_binding {
Some(channel_binding) => (channel_binding, sasl::SCRAM_SHA_256_PLUS),
None => (ChannelBinding::unsupported(), sasl::SCRAM_SHA_256),
}
} else if has_scram {
match channel_binding {
Some(_) => (ChannelBinding::unrequested(), sasl::SCRAM_SHA_256),
None => (ChannelBinding::unsupported(), sasl::SCRAM_SHA_256),
}
} else {
return Err(io::Error::new(
io::ErrorKind::Other,
"unsupported SASL authentication",
).into());
}
};
let mut scram = ScramSha256::new(pass.as_bytes(), ChannelBinding::unsupported())?;
let mut scram = ScramSha256::new(pass.as_bytes(), channel_binding)?;
let mut buf = vec![];
frontend::sasl_initial_response(sasl::SCRAM_SHA_256, scram.message(), &mut buf)?;
frontend::sasl_initial_response(mechanism, scram.message(), &mut buf)?;
transition!(SendingSasl {
future: state.stream.send(buf),

View File

@ -58,6 +58,26 @@ pub trait TlsConnect {
) -> Box<Future<Item = Box<TlsStream>, Error = Box<Error + Sync + Send>> + Sync + Send>;
}
pub trait TlsStream: 'static + Sync + Send + AsyncRead + AsyncWrite {}
pub trait TlsStream: 'static + Sync + Send + AsyncRead + AsyncWrite {
/// Returns the data associated with the `tls-unique` channel binding type as described in
/// [RFC 5929], if supported.
///
/// An implementation only needs to support one of this or `tls_server_end_point`.
///
/// [RFC 5929]: https://tools.ietf.org/html/rfc5929
fn tls_unique(&self) -> Option<Vec<u8>> {
None
}
/// Returns the data associated with the `tls-server-end-point` channel binding type as
/// described in [RFC 5929], if supported.
///
/// An implementation only needs to support one of this or `tls_unique`.
///
/// [RFC 5929]: https://tools.ietf.org/html/rfc5929
fn tls_server_end_point(&self) -> Option<Vec<u8>> {
None
}
}
impl TlsStream for proto::Socket {}