Bug 1892528 - part 2: enable Xyber768 in Http/3 under a pref. r=valentin,necko-reviewers,kershaw

Differential Revision: https://phabricator.services.mozilla.com/D208048
This commit is contained in:
John Schanck 2024-06-05 16:51:37 +00:00
parent 5194094269
commit 29e702a9ad
9 changed files with 143 additions and 15 deletions

View File

@ -13287,6 +13287,18 @@
mirror: always
rust: true
# Whether to send a Xyber768 key share in HTTP/3 TLS handshakes.
# Has no effect unless security.tls.enable_kyber is true.
- name: network.http.http3.enable_kyber
type: RelaxedAtomicBool
#ifdef ANDROID
value: false
#else
value: @IS_NIGHTLY_BUILD@
#endif
mirror: always
rust: true
# When true, a http request will be upgraded to https when HTTPS RR is
# available.
- name: network.dns.upgrade_with_https_rr
@ -15052,6 +15064,7 @@
value: @IS_NIGHTLY_BUILD@
#endif
mirror: always
rust: true
- name: security.ssl.treat_unsafe_negotiation_as_broken
type: RelaxedAtomicBool

View File

@ -91,7 +91,7 @@ static nsresult RawBytesToNetAddr(uint16_t aFamily, const uint8_t* aRemoteAddr,
nsresult Http3Session::Init(const nsHttpConnectionInfo* aConnInfo,
nsINetAddr* aSelfAddr, nsINetAddr* aPeerAddr,
HttpConnectionUDP* udpConn, uint32_t controlFlags,
HttpConnectionUDP* udpConn, uint32_t aProviderFlags,
nsIInterfaceRequestor* callbacks) {
LOG3(("Http3Session::Init %p", this));
@ -108,7 +108,7 @@ nsresult Http3Session::Init(const nsHttpConnectionInfo* aConnInfo,
mSocketControl = new QuicSocketControl(
httpsProxy ? aConnInfo->ProxyInfo()->Host() : aConnInfo->GetOrigin(),
httpsProxy ? aConnInfo->ProxyInfo()->Port() : aConnInfo->OriginPort(),
controlFlags, this);
aProviderFlags, this);
NetAddr selfAddr;
MOZ_ALWAYS_SUCCEEDS(aSelfAddr->GetNetAddr(&selfAddr));
@ -142,7 +142,7 @@ nsresult Http3Session::Init(const nsHttpConnectionInfo* aConnInfo,
StaticPrefs::network_http_http3_max_stream_data(),
StaticPrefs::network_http_http3_version_negotiation_enabled(),
mConnInfo->GetWebTransport(), gHttpHandler->Http3QlogDir(), datagramSize,
StaticPrefs::network_http_http3_max_accumlated_time_ms(),
StaticPrefs::network_http_http3_max_accumlated_time_ms(), aProviderFlags,
getter_AddRefs(mHttp3Connection));
if (NS_FAILED(rv)) {
return rv;

View File

@ -130,7 +130,7 @@ class Http3Session final : public nsAHttpTransaction, public nsAHttpConnection {
Http3Session();
nsresult Init(const nsHttpConnectionInfo* aConnInfo, nsINetAddr* selfAddr,
nsINetAddr* peerAddr, HttpConnectionUDP* udpConn,
uint32_t controlFlags, nsIInterfaceRequestor* callbacks);
uint32_t aProviderFlags, nsIInterfaceRequestor* callbacks);
bool IsConnected() const { return mState == CONNECTED; }
bool CanSendData() const {

View File

@ -24,6 +24,7 @@
#include "nsHttpHandler.h"
#include "Http3Session.h"
#include "nsComponentManagerUtils.h"
#include "nsIHttpChannelInternal.h"
#include "nsISocketProvider.h"
#include "nsNetAddr.h"
#include "nsINetAddr.h"
@ -129,26 +130,31 @@ nsresult HttpConnectionUDP::Init(nsHttpConnectionInfo* info,
return rv;
}
uint32_t controlFlags = 0;
uint32_t providerFlags = 0;
if (caps & NS_HTTP_LOAD_ANONYMOUS) {
controlFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
providerFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
}
if (mConnInfo->GetPrivate()) {
controlFlags |= nsISocketProvider::NO_PERMANENT_STORAGE;
providerFlags |= nsISocketProvider::NO_PERMANENT_STORAGE;
}
if (((caps & NS_HTTP_BE_CONSERVATIVE) || mConnInfo->GetBeConservative()) &&
gHttpHandler->ConnMgr()->BeConservativeIfProxied(
mConnInfo->ProxyInfo())) {
controlFlags |= nsISocketProvider::BE_CONSERVATIVE;
providerFlags |= nsISocketProvider::BE_CONSERVATIVE;
}
if ((caps & NS_HTTP_IS_RETRY) ||
(mConnInfo->GetTlsFlags() &
nsIHttpChannelInternal::TLS_FLAG_CONFIGURE_AS_RETRY)) {
providerFlags |= nsISocketProvider::IS_RETRY;
}
if (mResolvedByTRR) {
controlFlags |= nsISocketProvider::USED_PRIVATE_DNS;
providerFlags |= nsISocketProvider::USED_PRIVATE_DNS;
}
mPeerAddr = new nsNetAddr(&peerAddr);
mHttp3Session = new Http3Session();
rv = mHttp3Session->Init(mConnInfo, mSelfAddr, mPeerAddr, this, controlFlags,
rv = mHttp3Session->Init(mConnInfo, mSelfAddr, mPeerAddr, this, providerFlags,
callbacks);
if (NS_FAILED(rv)) {
LOG(

View File

@ -315,9 +315,10 @@ interface nsIHttpChannelInternal : nsISupports
/**
* An opaque flags for non-standard behavior of the TLS system.
* It is unlikely this will need to be set outside of telemetry studies
* relating to the TLS implementation.
* It is unlikely this will need to be set outside of tests or telemetry
* studies relating to the TLS implementation.
*/
const unsigned long TLS_FLAG_CONFIGURE_AS_RETRY = (1 << 16);
[must_use] attribute unsigned long tlsFlags;
[must_use] readonly attribute PRTime lastModifiedTime;

View File

@ -19,12 +19,13 @@ class NeqoHttp3Conn final {
uint64_t aMaxData, uint64_t aMaxStreamData,
bool aVersionNegotiation, bool aWebTransport,
const nsACString& aQlogDir, uint32_t aDatagramSize,
uint32_t aMaxAccumulatedTime, NeqoHttp3Conn** aConn) {
uint32_t aMaxAccumulatedTime, uint32_t aProviderFlags,
NeqoHttp3Conn** aConn) {
return neqo_http3conn_new(
&aOrigin, &aAlpn, &aLocalAddr, &aRemoteAddr, aMaxTableSize,
aMaxBlockedStreams, aMaxData, aMaxStreamData, aVersionNegotiation,
aWebTransport, &aQlogDir, aDatagramSize, aMaxAccumulatedTime,
(const mozilla::net::NeqoHttp3Conn**)aConn);
aProviderFlags, (const mozilla::net::NeqoHttp3Conn**)aConn);
}
void Close(uint64_t aError) { neqo_http3conn_close(this, aError); }

View File

@ -39,7 +39,7 @@ use thin_vec::ThinVec;
use uuid::Uuid;
#[cfg(windows)]
use winapi::shared::ws2def::{AF_INET, AF_INET6};
use xpcom::{AtomicRefcnt, RefCounted, RefPtr};
use xpcom::{interfaces::nsISocketProvider, AtomicRefcnt, RefCounted, RefPtr};
#[repr(C)]
pub struct NeqoHttp3Conn {
@ -119,6 +119,7 @@ impl NeqoHttp3Conn {
qlog_dir: &nsACString,
webtransport_datagram_size: u32,
max_accumlated_time_ms: u32,
provider_flags: u32,
) -> Result<RefPtr<NeqoHttp3Conn>, nsresult> {
// Nss init.
init().map_err(|_| NS_ERROR_UNEXPECTED)?;
@ -194,6 +195,24 @@ impl NeqoHttp3Conn {
return Err(NS_ERROR_INVALID_ARG);
};
if static_prefs::pref!("security.tls.enable_kyber")
&& static_prefs::pref!("network.http.http3.enable_kyber")
&& (provider_flags & nsISocketProvider::IS_RETRY) == 0
&& (provider_flags & nsISocketProvider::BE_CONSERVATIVE) == 0
{
// These operations are infallible when conn.state == State::Init.
let _ = conn.set_groups(&[
neqo_crypto::TLS_GRP_KEM_XYBER768D00,
neqo_crypto::TLS_GRP_EC_X25519,
neqo_crypto::TLS_GRP_EC_SECP256R1,
neqo_crypto::TLS_GRP_EC_SECP384R1,
neqo_crypto::TLS_GRP_EC_SECP521R1,
]);
// This ensures that we send key shares for Xyber768D00, X25519, and P-256,
// so that servers are less likely to use HelloRetryRequest.
let _ = conn.send_additional_key_shares(2);
}
let mut conn = Http3Client::new_with_conn(conn, http3_settings);
if !qlog_dir.is_empty() {
@ -280,6 +299,7 @@ pub extern "C" fn neqo_http3conn_new(
qlog_dir: &nsACString,
webtransport_datagram_size: u32,
max_accumlated_time_ms: u32,
provider_flags: u32,
result: &mut *const NeqoHttp3Conn,
) -> nsresult {
*result = ptr::null_mut();
@ -298,6 +318,7 @@ pub extern "C" fn neqo_http3conn_new(
qlog_dir,
webtransport_datagram_size,
max_accumlated_time_ms,
provider_flags,
) {
Ok(http3_conn) => {
http3_conn.forget(result);

View File

@ -0,0 +1,79 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("security.tls.enable_kyber");
Services.prefs.clearUserPref("network.http.http3.enable_kyber");
http3_clear_prefs();
});
add_task(async function setup() {
Services.prefs.setBoolPref("security.tls.enable_kyber", true);
Services.prefs.setBoolPref("network.http.http3.enable_kyber", true);
await http3_setup_tests("h3");
});
let Http3Listener = function () {};
Http3Listener.prototype = {
expectedKeaGroup: undefined,
onStartRequest: function testOnStartRequest(request) {
Assert.equal(request.status, Cr.NS_OK);
Assert.equal(request.responseStatus, 200);
Assert.equal(request.securityInfo.keaGroupName, this.expectedKeaGroup);
},
onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
read_stream(stream, cnt);
},
onStopRequest: function testOnStopRequest(request) {
let httpVersion = "";
try {
httpVersion = request.protocolVersion;
} catch (e) {}
Assert.equal(httpVersion, "h3");
this.finish();
},
};
function chanPromise(chan, listener) {
return new Promise(resolve => {
function finish(result) {
resolve(result);
}
listener.finish = finish;
chan.asyncOpen(listener);
});
}
function makeChan(uri) {
let chan = NetUtil.newChannel({
uri,
loadUsingSystemPrincipal: true,
}).QueryInterface(Ci.nsIHttpChannel);
chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
return chan;
}
add_task(async function test_kyber_success() {
let listener = new Http3Listener();
listener.expectedKeaGroup = "xyber768d00";
let chan = makeChan("https://foo.example.com");
await chanPromise(chan, listener);
});
add_task(async function test_no_kyber_on_retry() {
Services.obs.notifyObservers(null, "net:cancel-all-connections");
let listener = new Http3Listener();
listener.expectedKeaGroup = "x25519";
let chan = makeChan("https://foo.example.com");
chan.QueryInterface(Ci.nsIHttpChannelInternal).tlsFlags =
Ci.nsIHttpChannelInternal.TLS_FLAG_CONFIGURE_AS_RETRY;
await chanPromise(chan, listener);
});

View File

@ -703,6 +703,12 @@ skip-if = [
]
run-sequentially = "node server exceptions dont replay well"
["test_http3_kyber.js"]
skip-if = [
"os == 'win'",
"os == 'android'",
]
["test_http3_large_post.js"]
skip-if = [
"os == 'win'",
@ -718,6 +724,7 @@ disabled = "bug 1771744 - telemetry probe expired"
# os == 'android'
# socketprocess_networking
["test_http3_perf.js"]
skip-if = [
"os == 'android'",