From 193d8c25c9eeb5260217de03c83a9ced47b287f5 Mon Sep 17 00:00:00 2001 From: Alex Melan <59925151+AlexMelanFromRingo@users.noreply.github.com> Date: Thu, 7 May 2026 19:19:29 +0000 Subject: [PATCH] Use subtle::ConstantTimeEq for MAC and key comparisons --- Cargo.lock | 1 + boringtun/Cargo.toml | 1 + boringtun/src/noise/handshake.rs | 16 +++++++++++----- boringtun/src/noise/rate_limiter.rs | 9 +++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5d02c3c4..9b0f03b1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,6 +151,7 @@ dependencies = [ "rand_core", "ring", "socket2", + "subtle", "thiserror 1.0.69", "tracing", "tracing-subscriber", diff --git a/boringtun/Cargo.toml b/boringtun/Cargo.toml index 9fb56f598..cedcd0243 100644 --- a/boringtun/Cargo.toml +++ b/boringtun/Cargo.toml @@ -33,6 +33,7 @@ tracing-subscriber = { version = "0.3", features = ["fmt"], optional = true } ip_network = "0.4.1" ip_network_table = "0.2.0" ring = "0.17" +subtle = "2.6" x25519-dalek = { version = "2.0.1", features = [ "reusable_secrets", "static_secrets", diff --git a/boringtun/src/noise/handshake.rs b/boringtun/src/noise/handshake.rs index 40ed8037d..e9c1f6765 100644 --- a/boringtun/src/noise/handshake.rs +++ b/boringtun/src/noise/handshake.rs @@ -15,6 +15,7 @@ use rand_core::OsRng; use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305}; use std::convert::TryInto; use std::time::{Duration, SystemTime}; +use subtle::ConstantTimeEq; #[cfg(feature = "mock-instant")] use mock_instant::Instant; @@ -521,11 +522,16 @@ impl Handshake { &hash, )?; - ring::constant_time::verify_slices_are_equal( - self.params.peer_static_public.as_bytes(), - &peer_static_public_decrypted, - ) - .map_err(|_| WireGuardError::WrongKey)?; + if self + .params + .peer_static_public + .as_bytes() + .ct_eq(&peer_static_public_decrypted) + .unwrap_u8() + != 1 + { + return Err(WireGuardError::WrongKey); + } // initiator.hash = HASH(initiator.hash || msg.encrypted_static) hash = b2s_hash(&hash, packet.encrypted_static); diff --git a/boringtun/src/noise/rate_limiter.rs b/boringtun/src/noise/rate_limiter.rs index 421d5680f..f9d079e9f 100644 --- a/boringtun/src/noise/rate_limiter.rs +++ b/boringtun/src/noise/rate_limiter.rs @@ -15,7 +15,7 @@ use aead::{AeadInPlace, KeyInit}; use chacha20poly1305::{Key, XChaCha20Poly1305}; use parking_lot::Mutex; use rand_core::{OsRng, RngCore}; -use ring::constant_time::verify_slices_are_equal; +use subtle::ConstantTimeEq; const COOKIE_REFRESH: u64 = 128; // Use 128 and not 120 so the compiler can optimize out the division const COOKIE_SIZE: usize = 16; @@ -166,8 +166,9 @@ impl RateLimiter { let (mac1, mac2) = macs.split_at(16); let computed_mac1 = b2s_keyed_mac_16(&self.mac1_key, msg); - verify_slices_are_equal(&computed_mac1[..16], mac1) - .map_err(|_| TunnResult::Err(WireGuardError::InvalidMac))?; + if computed_mac1[..16].ct_eq(mac1).unwrap_u8() != 1 { + return Err(TunnResult::Err(WireGuardError::InvalidMac)); + } if self.is_under_load() { let addr = match src_addr { @@ -179,7 +180,7 @@ impl RateLimiter { let cookie = self.current_cookie(addr); let computed_mac2 = b2s_keyed_mac_16_2(&cookie, msg, mac1); - if verify_slices_are_equal(&computed_mac2[..16], mac2).is_err() { + if computed_mac2[..16].ct_eq(mac2).unwrap_u8() != 1 { let cookie_packet = self .format_cookie_reply(sender_idx, cookie, mac1, dst) .map_err(TunnResult::Err)?;