Skip to content
Open
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
10 changes: 10 additions & 0 deletions boring-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ allow-crl-extensions-bad-version = []
# `BORING_BSSL{,_FIPS}_SOURCE_PATH`.
underscore-wildcards = []

# Restores the historical BoringSSL default of not enforcing RSA keyUsage
# during TLS handshakes. BoringSSL starting with `BORINGSSL_API_VERSION`
# 19 (see `include/openssl/base.h`) changed `enforce_rsa_key_usage` to
# `true`, making a client-side RSA leaf whose keyUsage does not include the
# bit required by the negotiated cipher suite a fatal handshake error
# (KEY_USAGE_BIT_INCORRECT). Enabling this feature applies a build-time
# patch that sets the default back to `false`, so RSA keyUsage mismatches
# are non-fatal. Non-RSA keyUsage enforcement is unaffected.
relax-rsa-key-usage = []

[build-dependencies]
bindgen = { workspace = true }
cmake = { workspace = true }
Expand Down
6 changes: 5 additions & 1 deletion boring-sys/build/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub(crate) struct Features {
pub(crate) rpk: bool,
pub(crate) underscore_wildcards: bool,
pub(crate) allow_crl_extensions_bad_version: bool,
pub(crate) relax_rsa_key_usage: bool,
}

pub(crate) struct Env {
Expand Down Expand Up @@ -114,7 +115,9 @@ impl Config {
);
}

let features_with_patches_enabled = self.features.rpk || self.features.underscore_wildcards;
let features_with_patches_enabled = self.features.rpk
|| self.features.underscore_wildcards
|| self.features.relax_rsa_key_usage;

let patches_required = features_with_patches_enabled && !self.env.assume_patched;

Expand All @@ -138,6 +141,7 @@ impl Features {
rpk: cfg!(feature = "rpk"),
underscore_wildcards: cfg!(feature = "underscore-wildcards"),
allow_crl_extensions_bad_version: cfg!(feature = "allow-crl-extensions-bad-version"),
relax_rsa_key_usage: cfg!(feature = "relax-rsa-key-usage"),
}
}

Expand Down
11 changes: 9 additions & 2 deletions boring-sys/build/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,12 +444,14 @@ fn ensure_patches_applied(config: &Config) -> io::Result<()> {
);
return Ok(());
} else if config.env.source_path.is_some()
&& (config.features.rpk || config.features.underscore_wildcards)
&& (config.features.rpk
|| config.features.underscore_wildcards
|| config.features.relax_rsa_key_usage)
{
panic!(
"BORING_BSSL_ASSUME_PATCHED must be set when setting
BORING_BSSL_SOURCE_PATH and using any of the following
features: rpk, underscore-wildcards"
features: rpk, underscore-wildcards, relax-rsa-key-usage"
);
}

Expand Down Expand Up @@ -485,6 +487,11 @@ fn ensure_patches_applied(config: &Config) -> io::Result<()> {
apply_patch(config, "underscore-wildcards.patch")?;
}

if config.features.relax_rsa_key_usage {
println!("cargo:warning=applying RSA key-usage enforcement relaxation patch");
apply_patch(config, "relax-rsa-key-usage-enforcement.patch")?;
}

Ok(())
}

Expand Down
32 changes: 32 additions & 0 deletions boring-sys/patches/relax-rsa-key-usage-enforcement.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Bartlett Guthrie <kbg@cloudflare.com>
Date: Wed, 10 Jun 2026 14:00:00 -0400
Subject: [PATCH] Default enforce_rsa_key_usage to off

BoringSSL starting with BORINGSSL_API_VERSION 19 (see
include/openssl/base.h) flipped the SSL_CONFIG default for
enforce_rsa_key_usage to true. As a client, this makes an RSA leaf whose
keyUsage does not assert the bit required by the cipher suite a fatal
handshake error (KEY_USAGE_BIT_INCORRECT) instead of the historical
non-fatal behaviour.
Many real upstream origins serve such certs; OpenSSL and the prior
BoringSSL pin accepted them. There is no Rust API to relax this per
connection. Restore the historical default (off) so RSA keyUsage
mismatches are non-fatal again; non-RSA keyUsage enforcement is
unaffected.
---
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 89702eaaf..4be64f8a5 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -575,7 +575,7 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg)
signed_cert_timestamps_enabled(false),
ocsp_stapling_enabled(false),
channel_id_enabled(false),
- enforce_rsa_key_usage(true),
+ enforce_rsa_key_usage(false),
retain_only_sha256_of_client_certs(false),
handoff(false),
shed_handshake_config(false),
--
2.39.5
4 changes: 4 additions & 0 deletions boring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ rpk = ["credential", "boring-sys/rpk"]
# `BORING_BSSL{,_FIPS}_ASSUME_PATCHED`.
underscore-wildcards = ["boring-sys/underscore-wildcards"]

# Restores the historical BoringSSL default of not enforcing RSA keyUsage
# during TLS handshakes.
relax-rsa-key-usage = ["boring-sys/relax-rsa-key-usage"]

# **DO NOT USE** This will be removed without warning in future releases.
# Alias for 'fips', only for backwards compatibility.
fips-precompiled = ["fips"]
Expand Down
67 changes: 66 additions & 1 deletion boring/src/ssl/test/verify.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::server::Server;
use crate::hash::MessageDigest;
use crate::ssl::SslVerifyMode;
use crate::ssl::{SslFiletype, SslOptions, SslVerifyMode, SslVersion};
use crate::x509::store::X509StoreBuilder;
use crate::x509::X509;
use hex;
Expand Down Expand Up @@ -148,3 +148,68 @@ fn ssl_callback() {
client.connect();
assert!(CALLED_BACK.load(Ordering::SeqCst));
}

/// Verifies that an RSA leaf certificate whose keyUsage extension lacks the
/// bit required by the negotiated cipher suite is rejected when BoringSSL
/// enforces RSA keyUsage and accepted when enforcement is relaxed.
///
/// The test certificates live in `boring/test/rsa-key-usage-relaxed*.pem` and
/// were generated by `boring/test/generate-rsa-key-usage-relaxed-certs.sh`.
/// That script creates a leaf cert with `keyUsage = keyEncipherment` only (no
/// `digitalSignature`). Pinning the handshake to TLS 1.2 +
/// `ECDHE-RSA-AES128-GCM-SHA256` makes the required bit `digitalSignature`, so
/// the connection fails with `KEY_USAGE_BIT_INCORRECT` unless the
/// `relax-rsa-key-usage` feature is enabled.
#[test]
fn rsa_key_usage_mismatch() {
const CIPHER: &str = "ECDHE-RSA-AES128-GCM-SHA256";

let mut server = Server::builder();
server
.ctx()
.set_certificate_chain_file("test/rsa-key-usage-relaxed.pem")
.unwrap();
server
.ctx()
.set_private_key_file("test/rsa-key-usage-relaxed-key.pem", SslFiletype::PEM)
.unwrap();
server.ctx().set_options(SslOptions::NO_TLSV1_3);
server.ctx().set_cipher_list(CIPHER).unwrap();
server
.ctx()
.set_min_proto_version(Some(SslVersion::TLS1_2))
.unwrap();
server
.ctx()
.set_max_proto_version(Some(SslVersion::TLS1_2))
.unwrap();

let configure_client = |server: &Server| {
let mut client = server.client();
client.ctx().set_verify(SslVerifyMode::PEER);
client
.ctx()
.set_ca_file("test/rsa-key-usage-relaxed-ca.pem")
.unwrap();
client.ctx().set_options(SslOptions::NO_TLSV1_3);
client.ctx().set_cipher_list(CIPHER).unwrap();
client
.ctx()
.set_min_proto_version(Some(SslVersion::TLS1_2))
.unwrap();
client
.ctx()
.set_max_proto_version(Some(SslVersion::TLS1_2))
.unwrap();
client
};

if cfg!(feature = "relax-rsa-key-usage") {
let server = server.build();
configure_client(&server).connect();
} else {
server.should_error();
let server = server.build();
configure_client(&server).connect_err();
}
}
46 changes: 46 additions & 0 deletions boring/test/generate-rsa-key-usage-relaxed-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Generates the certificates used by `boring/src/ssl/test/verify.rs` for the
# `rsa_key_usage_mismatch` test.
#
# The resulting leaf certificate has an RSA key and a keyUsage extension that
# only asserts keyEncipherment (no digitalSignature). When BoringSSL enforces
# RSA keyUsage, an ECDHE-RSA cipher suite therefore fails with
# KEY_USAGE_BIT_INCORRECT. When enforcement is relaxed, the handshake succeeds.
set -euo pipefail

cd "$(dirname "$0")"
NAME=rsa-key-usage-relaxed

# CA key and self-signed certificate. The CA key is deleted at the end; only
# the CA certificate is needed by the test.
openssl genrsa -out "${NAME}-ca-key.pem" 2048
openssl req -new -x509 \
-key "${NAME}-ca-key.pem" \
-out "${NAME}-ca.pem" \
-days 3650 \
-subj "/CN=Relax RSA Key Usage Test CA" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,keyCertSign,cRLSign"

# Leaf key and certificate request.
openssl genrsa -out "${NAME}-key.pem" 2048
openssl req -new \
-key "${NAME}-key.pem" \
-out "${NAME}.csr" \
-subj "/CN=localhost"

# Leaf certificate with keyUsage=keyEncipherment only. The missing
# digitalSignature bit is what triggers the RSA keyUsage check failure.
openssl x509 -req \
-in "${NAME}.csr" \
-CA "${NAME}-ca.pem" \
-CAkey "${NAME}-ca-key.pem" \
-CAcreateserial \
-out "${NAME}.pem" \
-days 365 \
-extfile <(printf '%s\n' \
'keyUsage=critical,keyEncipherment' \
'extendedKeyUsage=serverAuth' \
'subjectAltName=DNS:localhost')

rm -f "${NAME}.csr" "${NAME}.srl" "${NAME}-ca-key.pem"
20 changes: 20 additions & 0 deletions boring/test/rsa-key-usage-relaxed-ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDPTCCAiWgAwIBAgIUVyjdxXDX1AIoOdOTwFCvxMZtiikwDQYJKoZIhvcNAQEL
BQAwJjEkMCIGA1UEAwwbUmVsYXggUlNBIEtleSBVc2FnZSBUZXN0IENBMB4XDTI2
MDYyNjE4NDMxMloXDTM2MDYyMzE4NDMxMlowJjEkMCIGA1UEAwwbUmVsYXggUlNB
IEtleSBVc2FnZSBUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEA50Yu0DxDUJZ5G+nGy5QXajf7m6z/IlJgmz8lcmNiRmiIGMMdN9HMyLe4Mljk
qOl2aNfqLsSFeXg9KamhoScnQatQl5o4cf5kTePOYk9SkYuK86bcfHFJQLcPAjb4
XBvEHnpCr2LpPFGVGuOlG7d1I7zJ0Fz9a6hThjN2+1Nl7qnwLZM1f+45oD9bBmno
MObfLQDIC5Ds0pE0Iv+jPPoQqTzhkwRdsSWiSXojmuWsrS2kW7B/OUHxnB8zlEMZ
S2GoECKVEugRJUwXayyaJac9ygL895M9S49Ikvth18eyfmSu+A8usMG2PEklGCa2
Yz0ij3P5KmgEXnHHuIydsxITbQIDAQABo2MwYTAdBgNVHQ4EFgQUj8ngJAk3fVY/
KHlgDC2AFB1Kz5gwHwYDVR0jBBgwFoAUj8ngJAk3fVY/KHlgDC2AFB1Kz5gwDwYD
VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEB
AJStEky4C9/28O8MQz7+MaupQn7MORVEWnYm2+afET0O6S+sLmqU6dEuzPXAxZit
x72Hw+g3i3XHwPtr2+WOpppTSA4fWuQzntcTaJErs4nImP9oVDs7wACaR2ITMuQ9
jIwdBhaO3D1RBpKLsKYNyDbhvrprIscZBGxmmqOZJpcejsNCUwAAi3qcmGloZUJb
kX/+c3mYN5qGw62X2nQhTmm4sGfe4hRloAoaPFmezF+9HIKIYQ92gXRDEgDEImbj
39pqNdWfJ6zpWWrqqRH2il93BZ3qFk8904Z+3WBxKYhDJ0f8WBA4ECV4LCWaRL7t
RMbshIkpD5rfFuIjx1/ApuQ=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions boring/test/rsa-key-usage-relaxed-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtBcpDMwAouuCD
SdO4rtWQkT/5IImPGLIX0qofIZq54eur64RPnh7FqbI+G87iD8/xXaEBup84fhT9
yvsvxMDFYd06CUsrEcTEy3bfDHtfCo7dnELCj2A7tq5baxru2qASvqYCGEGeBiqM
qETjAn3BnsU1BHUCGaGA9bVnpwUEoKaBaFplXSonQnphdiXzad3ilIpGcWmJU/8i
z+NzgJrNmKSJL2F4OwIvvb+LNEJT2IW0U4RCXMIT+SMbgJ1MwRfH/XrU9fviRv9l
pjaXNlVonPjE1IRwAoZGagdPRso3naCiPWlHyJGpii3qoCd/dcCLk72xYV1tJVji
UFR3b7x3AgMBAAECggEACAyljX012cGGNkDYX/H2TyOKxQNgAKZUi07BUvGWo0B8
XPn37cSX7JzuO/0LD2iX6eims0bSAsOX//t/2xoiIXXPlwsdf+o8x1NPDYFJpzEP
6Son9BcXEhuKGghAXQSAWqpSXPVMpVZUh7bS6+UFtEqlSVo3Ow1IENnmpq4xku2I
x03zwXLdCPdleUBr8zPHRWaGNg2x1jpVxHR7N5KHTfhz0ylIMDBfThseHUuMkkY9
VlTQNW5jd/9Zr8kxbe6J5/o699QL6I3a/ACmlXbyO6g6PSUl39dYfOQPTCeIFKrc
FyZvEeVT9ZZwSnKbVr+kM+k/uzdURKOj7IE68yF+VQKBgQDf8TQw4Wn7PVVnZGgw
PvkAKiKp0OE+NqWu7p+NhRE0x6nUcqXOX1zm1EDu2GcFGSegGb+DcQYVcU7DhWlo
7PZEPaH3ddgRBXte/nhP0Meaxz5FRdMGoI4ywv/uB4jOeJbw/gIkfkyBCgpplYbv
H/BOBjN+4f6HiGlcSwl/bR8KvQKBgQDFyooQb8CrF7vxPAxagU/JWzCp1xVKjtzU
Z5oRWjNBNH/PzXfDTQWpDefHXJ30Z8cKwHy5TUqIL8g2jW85AXYk8rgbIBtRk/DI
izHJWqTydrOaeTvbUrao+xIvSOhxgcLt90aadOAk47E+bnbXBGFOEfvM8KF2QVeb
x8PQ+UTxQwKBgQC53N5dR2kHvYL5egtDJ7DQIyh72sJnOUHP63r/IRcDwEdC7RiS
LPHVHwr5cSAnyhXqOhSKSi8rcsxVWJABJtLKFoEr+mGm1u7rC7bdP8G6w2z6X5Zi
pLUAinmRnC0+eDWGtLsggLaMTsIPmavRIaf3igwJXhY7dMtFb33lhbLC3QKBgCY4
VSWH8rsdAvxClkCG7FwEewrWvQ6DPLjurB7eRzk6Y9hL4/ChWY6pWTh09TDdPOEf
APrtrJFUamPgQLXLSoEpRdo4Ag9pfwXBoAVAts8DkQEwnBhti05r9b+dXw1P/dLu
DX6bRxTZys49mklCV2s2nmmjtg+b4MoBeB1RjbjxAoGAEsxMZu1hZbynDf/j6Q9J
JvZWzBGbiGbEXJQPB0ZlBDSWXeGyMYv1pw35YRXBa+jk1+fP4IWRF3UABY8tchmt
M4X9veVRUyznd7GwqhrwgvvUK1EW6qURDVObeMe6/Bdm09lu3G2NhFWZP7DM3F/5
/okcZc7DZOZCUlcHgiIg0y0=
-----END PRIVATE KEY-----
20 changes: 20 additions & 0 deletions boring/test/rsa-key-usage-relaxed.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUCmRSuBn+jTOljHtas3Mut6KyiFAwDQYJKoZIhvcNAQEL
BQAwJjEkMCIGA1UEAwwbUmVsYXggUlNBIEtleSBVc2FnZSBUZXN0IENBMB4XDTI2
MDYyNjE4NDMxMloXDTI3MDYyNjE4NDMxMlowFDESMBAGA1UEAwwJbG9jYWxob3N0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArQXKQzMAKLrgg0nTuK7V
kJE/+SCJjxiyF9KqHyGaueHrq+uET54examyPhvO4g/P8V2hAbqfOH4U/cr7L8TA
xWHdOglLKxHExMt23wx7XwqO3ZxCwo9gO7auW2sa7tqgEr6mAhhBngYqjKhE4wJ9
wZ7FNQR1AhmhgPW1Z6cFBKCmgWhaZV0qJ0J6YXYl82nd4pSKRnFpiVP/Is/jc4Ca
zZikiS9heDsCL72/izRCU9iFtFOEQlzCE/kjG4CdTMEXx/161PX74kb/ZaY2lzZV
aJz4xNSEcAKGRmoHT0bKN52goj1pR8iRqYot6qAnf3XAi5O9sWFdbSVY4lBUd2+8
dwIDAQABo30wezAOBgNVHQ8BAf8EBAMCBSAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw
FAYDVR0RBA0wC4IJbG9jYWxob3N0MB0GA1UdDgQWBBR4WbrbwW1ZzEwF0fRUB+XA
LF4WGzAfBgNVHSMEGDAWgBSPyeAkCTd9Vj8oeWAMLYAUHUrPmDANBgkqhkiG9w0B
AQsFAAOCAQEAz336T8K625TdEkvqQ/B/bbkW5zv2y/mu1G+iW7aSfYNdOsH1fVFl
kFpFJsv2dUoV82fKzk33RcXDlc9o3y4KzTeTPaEZb4ZCe8TleWkjdZYa7/hRj6GR
bc7mniRawJVtdCKfAvg+SgiPwSt18s1BCMd4B/5XIQivgd+ksYvtIFRdn15OtNZi
Z91m1rSUHSgJLqHtxSNYwbxz3yw1/gm+Xfvj1+HZe4gTjfqjLIyhRJti1botWMaR
4XYy1W/WAbJ1avvKNfjkAoBZAYXguperASS/eZ3d7hH+0RVrBQSp1bde9/utChvE
5ls7xa9vwSLCKoXtAXGiaSePA5XDAkTGrg==
-----END CERTIFICATE-----
Loading