Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions boring/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ impl From<u16> for ExtensionType {
}
}

/// An SSL/TLS protocol version.
/// An SSL/TLS/DTLS protocol version.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct SslVersion(u16);

Expand All @@ -633,6 +633,15 @@ impl SslVersion {

/// TLSv1.3
pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION as _);

/// DTLSv1.0
pub const DTLS1: SslVersion = SslVersion(ffi::DTLS1_VERSION as _);

/// DTLSv1.2
pub const DTLS1_2: SslVersion = SslVersion(ffi::DTLS1_2_VERSION as _);

/// DTLSv1.3
pub const DTLS1_3: SslVersion = SslVersion(ffi::DTLS1_3_VERSION as _);
}

impl TryFrom<u16> for SslVersion {
Expand All @@ -644,7 +653,10 @@ impl TryFrom<u16> for SslVersion {
| ffi::TLS1_VERSION
| ffi::TLS1_1_VERSION
| ffi::TLS1_2_VERSION
| ffi::TLS1_3_VERSION => Ok(Self(value)),
| ffi::TLS1_3_VERSION
| ffi::DTLS1_VERSION
| ffi::DTLS1_2_VERSION
| ffi::DTLS1_3_VERSION => Ok(Self(value)),
_ => Err("Unknown SslVersion"),
}
}
Expand All @@ -658,6 +670,9 @@ impl fmt::Debug for SslVersion {
Self::TLS1_1 => "TLS1_1",
Self::TLS1_2 => "TLS1_2",
Self::TLS1_3 => "TLS1_3",
Self::DTLS1 => "DTLS1",
Self::DTLS1_2 => "DTLS1_2",
Self::DTLS1_3 => "DTLS1_3",
_ => return write!(f, "{:#06x}", self.0),
})
}
Expand All @@ -671,6 +686,9 @@ impl fmt::Display for SslVersion {
Self::TLS1_1 => "TLSv1.1",
Self::TLS1_2 => "TLSv1.2",
Self::TLS1_3 => "TLSv1.3",
Self::DTLS1 => "DTLSv1.0",
Self::DTLS1_2 => "DTLSv1.2",
Self::DTLS1_3 => "DTLSv1.3",
_ => return write!(f, "unknown ({:#06x})", self.0),
})
}
Comment on lines 647 to 694
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR adds DTLS variants to SslVersion’s TryFrom<u16>, Debug, and Display implementations, but the new behavior isn’t directly exercised by a unit test (the added DTLS negotiation test doesn’t cover formatting or TryFrom). Consider adding a small assertion-based test that validates SslVersion::try_from(DTLS*_VERSION as u16) and the expected Debug/Display strings for the new variants.

Copilot uses AI. Check for mistakes.
Expand Down
47 changes: 47 additions & 0 deletions boring/src/ssl/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,53 @@ fn test_connect_with_srtp_ssl() {
assert_eq!(buf[..], buf2[..]);
}

/// Tests that DTLS 1.3 can be enabled and negotiated successfully.
#[test]
fn test_dtls_1_3_version() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();

let guard = thread::spawn(move || {
let stream = listener.accept().unwrap().0;
let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap();
ctx.set_certificate_file(Path::new("test/cert.pem"), SslFiletype::PEM)
.unwrap();
ctx.set_private_key_file(Path::new("test/key.pem"), SslFiletype::PEM)
.unwrap();
// Enable DTLS 1.3
ctx.set_max_proto_version(Some(SslVersion::DTLS1_3))
.unwrap();
let mut ssl = Ssl::new(&ctx.build()).unwrap();
ssl.set_mtu(1500).unwrap();
let stream = ssl.accept(stream).unwrap();

// Verify DTLS 1.3 was negotiated
let version = stream.ssl().version2().unwrap();
assert_eq!(version, SslVersion::DTLS1_3);

stream
});

let stream = TcpStream::connect(addr).unwrap();
let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap();
// Enable DTLS 1.3 on client
ctx.set_max_proto_version(Some(SslVersion::DTLS1_3))
.unwrap();
Comment on lines +249 to +267
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this test, only set_max_proto_version(Some(SslVersion::DTLS1_3)) is set on each side, which still allows negotiating an older DTLS version if DTLS 1.3 ends up disabled/unavailable at runtime. To make the test’s intent (“negotiate DTLS 1.3”) more deterministic, consider also setting the minimum proto version to DTLS1_3 on both client and server contexts.

Copilot uses AI. Check for mistakes.
let mut ssl = Ssl::new(&ctx.build()).unwrap();
ssl.set_mtu(1500).unwrap();
let stream = ssl.connect(stream).unwrap();

// Verify DTLS 1.3 was negotiated on client side
let version = stream.ssl().version2().unwrap();
assert_eq!(version, SslVersion::DTLS1_3);

// Also check version string
let version_str = stream.ssl().version_str();
assert_eq!(version_str, "DTLSv1.3");

guard.join().unwrap();
}

/// Tests that when the `SslStream` is created as a server stream, the protocols
/// are correctly advertised to the client.
#[test]
Expand Down
Loading