Skip to content

Commit 8e01f8d

Browse files
committed
Handle zero-length reads/writes
This commit adds some short-circuits for zero-length reads/writes to `SslStream`. Because OpenSSL returns 0 on error, then we could mistakenly confuse a 0-length success as an actual error, so we avoid writing or reading 0 bytes by returning quickly with a success.
1 parent 3cfcf13 commit 8e01f8d

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

openssl/src/ssl/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,15 @@ impl<S: Read + Write> SslStream<S> {
15061506
/// This is particularly useful with a nonblocking socket, where the error
15071507
/// value will identify if OpenSSL is waiting on read or write readiness.
15081508
pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
1509+
// The intepretation of the return code here is a little odd with a
1510+
// zero-length write. OpenSSL will likely correctly report back to us
1511+
// that it read zero bytes, but zero is also the sentinel for "error".
1512+
// To avoid that confusion short-circuit that logic and return quickly
1513+
// if `buf` has a length of zero.
1514+
if buf.len() == 0 {
1515+
return Ok(0)
1516+
}
1517+
15091518
let ret = self.ssl.read(buf);
15101519
if ret > 0 {
15111520
Ok(ret as usize)
@@ -1523,6 +1532,11 @@ impl<S: Read + Write> SslStream<S> {
15231532
/// This is particularly useful with a nonblocking socket, where the error
15241533
/// value will identify if OpenSSL is waiting on read or write readiness.
15251534
pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
1535+
// See above for why we short-circuit on zero-length buffers
1536+
if buf.len() == 0 {
1537+
return Ok(0)
1538+
}
1539+
15261540
let ret = self.ssl.write(buf);
15271541
if ret > 0 {
15281542
Ok(ret as usize)

openssl/src/ssl/tests/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,16 @@ fn test_write() {
421421
stream.flush().unwrap();
422422
}
423423

424+
#[test]
425+
fn zero_length_buffers() {
426+
let (_s, stream) = Server::new();
427+
let ctx = SslContext::builder(SslMethod::tls()).unwrap();
428+
let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
429+
430+
assert_eq!(stream.write(b"").unwrap(), 0);
431+
assert_eq!(stream.read(&mut []).unwrap(), 0);
432+
}
433+
424434
run_test!(get_peer_certificate, |method, stream| {
425435
let ctx = SslContext::builder(method).unwrap();
426436
let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();

0 commit comments

Comments
 (0)