summaryrefslogtreecommitdiffstats
path: root/third_party/rust/neqo-crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/neqo-crypto/src')
-rw-r--r--third_party/rust/neqo-crypto/src/aead.rs1
-rw-r--r--third_party/rust/neqo-crypto/src/agent.rs12
-rw-r--r--third_party/rust/neqo-crypto/src/agentio.rs9
-rw-r--r--third_party/rust/neqo-crypto/src/cert.rs18
-rw-r--r--third_party/rust/neqo-crypto/src/ech.rs10
-rw-r--r--third_party/rust/neqo-crypto/src/ext.rs4
-rw-r--r--third_party/rust/neqo-crypto/src/hkdf.rs23
-rw-r--r--third_party/rust/neqo-crypto/src/hp.rs8
-rw-r--r--third_party/rust/neqo-crypto/src/lib.rs132
-rw-r--r--third_party/rust/neqo-crypto/src/once.rs44
-rw-r--r--third_party/rust/neqo-crypto/src/p11.rs114
-rw-r--r--third_party/rust/neqo-crypto/src/replay.rs1
-rw-r--r--third_party/rust/neqo-crypto/src/selfencrypt.rs2
-rw-r--r--third_party/rust/neqo-crypto/src/time.rs74
14 files changed, 244 insertions, 208 deletions
diff --git a/third_party/rust/neqo-crypto/src/aead.rs b/third_party/rust/neqo-crypto/src/aead.rs
index a2f009a403..bf7d7fe9d7 100644
--- a/third_party/rust/neqo-crypto/src/aead.rs
+++ b/third_party/rust/neqo-crypto/src/aead.rs
@@ -5,7 +5,6 @@
// except according to those terms.
use std::{
- convert::{TryFrom, TryInto},
fmt,
ops::{Deref, DerefMut},
os::raw::{c_char, c_uint},
diff --git a/third_party/rust/neqo-crypto/src/agent.rs b/third_party/rust/neqo-crypto/src/agent.rs
index cd0bb4cb12..82a6dacd48 100644
--- a/third_party/rust/neqo-crypto/src/agent.rs
+++ b/third_party/rust/neqo-crypto/src/agent.rs
@@ -6,7 +6,6 @@
use std::{
cell::RefCell,
- convert::TryFrom,
ffi::{CStr, CString},
mem::{self, MaybeUninit},
ops::{Deref, DerefMut},
@@ -33,6 +32,7 @@ use crate::{
ech,
err::{is_blocked, secstatus_to_res, Error, PRErrorCode, Res},
ext::{ExtensionHandler, ExtensionTracker},
+ null_safe_slice,
p11::{self, PrivateKey, PublicKey},
prio,
replay::AntiReplay,
@@ -897,7 +897,7 @@ impl Client {
let resumption = arg.cast::<Vec<ResumptionToken>>().as_mut().unwrap();
let len = usize::try_from(len).unwrap();
let mut v = Vec::with_capacity(len);
- v.extend_from_slice(std::slice::from_raw_parts(token, len));
+ v.extend_from_slice(null_safe_slice(token, len));
qinfo!(
[format!("{fd:p}")],
"Got resumption token {}",
@@ -1015,7 +1015,7 @@ pub enum ZeroRttCheckResult {
Accept,
/// Reject 0-RTT, but continue the handshake normally.
Reject,
- /// Send HelloRetryRequest (probably not needed for QUIC).
+ /// Send `HelloRetryRequest` (probably not needed for QUIC).
HelloRetryRequest(Vec<u8>),
/// Fail the handshake.
Fail,
@@ -1105,11 +1105,7 @@ impl Server {
}
let check_state = arg.cast::<ZeroRttCheckState>().as_mut().unwrap();
- let token = if client_token.is_null() {
- &[]
- } else {
- std::slice::from_raw_parts(client_token, usize::try_from(client_token_len).unwrap())
- };
+ let token = null_safe_slice(client_token, usize::try_from(client_token_len).unwrap());
match check_state.checker.check(token) {
ZeroRttCheckResult::Accept => ssl::SSLHelloRetryRequestAction::ssl_hello_retry_accept,
ZeroRttCheckResult::Fail => ssl::SSLHelloRetryRequestAction::ssl_hello_retry_fail,
diff --git a/third_party/rust/neqo-crypto/src/agentio.rs b/third_party/rust/neqo-crypto/src/agentio.rs
index 2bcc540530..7c57a0ef45 100644
--- a/third_party/rust/neqo-crypto/src/agentio.rs
+++ b/third_party/rust/neqo-crypto/src/agentio.rs
@@ -6,13 +6,11 @@
use std::{
cmp::min,
- convert::{TryFrom, TryInto},
fmt, mem,
ops::Deref,
os::raw::{c_uint, c_void},
pin::Pin,
ptr::{null, null_mut},
- vec::Vec,
};
use neqo_common::{hex, hex_with_len, qtrace};
@@ -20,7 +18,7 @@ use neqo_common::{hex, hex_with_len, qtrace};
use crate::{
constants::{ContentType, Epoch},
err::{nspr, Error, PR_SetError, Res},
- prio, ssl,
+ null_safe_slice, prio, ssl,
};
// Alias common types.
@@ -100,7 +98,7 @@ impl RecordList {
) -> ssl::SECStatus {
let records = arg.cast::<Self>().as_mut().unwrap();
- let slice = std::slice::from_raw_parts(data, len as usize);
+ let slice = null_safe_slice(data, len);
records.append(epoch, ContentType::try_from(ct).unwrap(), slice);
ssl::SECSuccess
}
@@ -178,6 +176,7 @@ impl AgentIoInput {
return Err(Error::NoDataAvailable);
}
+ #[allow(clippy::disallowed_methods)] // We just checked if this was empty.
let src = unsafe { std::slice::from_raw_parts(self.input, amount) };
qtrace!([self], "read {}", hex(src));
let dst = unsafe { std::slice::from_raw_parts_mut(buf, amount) };
@@ -232,7 +231,7 @@ impl AgentIo {
// Stage output from TLS into the output buffer.
fn save_output(&mut self, buf: *const u8, count: usize) {
- let slice = unsafe { std::slice::from_raw_parts(buf, count) };
+ let slice = unsafe { null_safe_slice(buf, count) };
qtrace!([self], "save output {}", hex(slice));
self.output.extend_from_slice(slice);
}
diff --git a/third_party/rust/neqo-crypto/src/cert.rs b/third_party/rust/neqo-crypto/src/cert.rs
index 64e63ec71a..2836b5237c 100644
--- a/third_party/rust/neqo-crypto/src/cert.rs
+++ b/third_party/rust/neqo-crypto/src/cert.rs
@@ -4,16 +4,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::{
- convert::TryFrom,
- ptr::{addr_of, NonNull},
- slice,
-};
+use std::ptr::{addr_of, NonNull};
use neqo_common::qerror;
use crate::{
err::secstatus_to_res,
+ null_safe_slice,
p11::{CERTCertListNode, CERT_GetCertificateDer, CertList, Item, SECItem, SECItemArray},
ssl::{
PRFileDesc, SSL_PeerCertificateChain, SSL_PeerSignedCertTimestamps,
@@ -24,7 +21,7 @@ use crate::{
pub struct CertificateInfo {
certs: CertList,
cursor: *const CERTCertListNode,
- /// stapled_ocsp_responses and signed_cert_timestamp are properties
+ /// `stapled_ocsp_responses` and `signed_cert_timestamp` are properties
/// associated with each of the certificates. Right now, NSS only
/// reports the value for the end-entity certificate (the first).
stapled_ocsp_responses: Option<Vec<Vec<u8>>>,
@@ -52,7 +49,7 @@ fn stapled_ocsp_responses(fd: *mut PRFileDesc) -> Option<Vec<Vec<u8>>> {
};
for idx in 0..len {
let itemp: *const SECItem = unsafe { ocsp_ptr.as_ref().items.offset(idx).cast() };
- let item = unsafe { slice::from_raw_parts((*itemp).data, (*itemp).len as usize) };
+ let item = unsafe { null_safe_slice((*itemp).data, (*itemp).len) };
ocsp_helper.push(item.to_owned());
}
Some(ocsp_helper)
@@ -68,9 +65,8 @@ fn signed_cert_timestamp(fd: *mut PRFileDesc) -> Option<Vec<u8>> {
if unsafe { sct_ptr.as_ref().len == 0 || sct_ptr.as_ref().data.is_null() } {
Some(Vec::new())
} else {
- let sct_slice = unsafe {
- slice::from_raw_parts(sct_ptr.as_ref().data, sct_ptr.as_ref().len as usize)
- };
+ let sct_slice =
+ unsafe { null_safe_slice(sct_ptr.as_ref().data, sct_ptr.as_ref().len) };
Some(sct_slice.to_owned())
}
}
@@ -105,7 +101,7 @@ impl<'a> Iterator for &'a mut CertificateInfo {
let cert = unsafe { *self.cursor }.cert;
secstatus_to_res(unsafe { CERT_GetCertificateDer(cert, &mut item) })
.expect("getting DER from certificate should work");
- Some(unsafe { std::slice::from_raw_parts(item.data, item.len as usize) })
+ Some(unsafe { null_safe_slice(item.data, item.len) })
}
}
diff --git a/third_party/rust/neqo-crypto/src/ech.rs b/third_party/rust/neqo-crypto/src/ech.rs
index 1f54c4592e..4ff2cda7e8 100644
--- a/third_party/rust/neqo-crypto/src/ech.rs
+++ b/third_party/rust/neqo-crypto/src/ech.rs
@@ -5,7 +5,6 @@
// except according to those terms.
use std::{
- convert::TryFrom,
ffi::CString,
os::raw::{c_char, c_uint},
ptr::{addr_of_mut, null_mut},
@@ -15,7 +14,7 @@ use neqo_common::qtrace;
use crate::{
err::{ssl::SSL_ERROR_ECH_RETRY_WITH_ECH, Error, Res},
- experimental_api,
+ experimental_api, null_safe_slice,
p11::{
self, Item, PrivateKey, PublicKey, SECITEM_FreeItem, SECItem, SECKEYPrivateKey,
SECKEYPublicKey, Slot,
@@ -76,7 +75,7 @@ pub fn convert_ech_error(fd: *mut PRFileDesc, err: Error) -> Error {
return Error::InternalError;
}
let buf = unsafe {
- let slc = std::slice::from_raw_parts(item.data, usize::try_from(item.len).unwrap());
+ let slc = null_safe_slice(item.data, item.len);
let buf = Vec::from(slc);
SECITEM_FreeItem(&mut item, PRBool::from(false));
buf
@@ -101,8 +100,7 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
let oid_data = unsafe { p11::SECOID_FindOIDByTag(p11::SECOidTag::SEC_OID_CURVE25519) };
let oid = unsafe { oid_data.as_ref() }.ok_or(Error::InternalError)?;
- let oid_slc =
- unsafe { std::slice::from_raw_parts(oid.oid.data, usize::try_from(oid.oid.len).unwrap()) };
+ let oid_slc = unsafe { null_safe_slice(oid.oid.data, oid.oid.len) };
let mut params: Vec<u8> = Vec::with_capacity(oid_slc.len() + 2);
params.push(u8::try_from(p11::SEC_ASN1_OBJECT_ID).unwrap());
params.push(u8::try_from(oid.oid.len).unwrap());
@@ -113,7 +111,6 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
// If we have tracing on, try to ensure that key data can be read.
let insensitive_secret_ptr = if log::log_enabled!(log::Level::Trace) {
- #[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
unsafe {
p11::PK11_GenerateKeyPairWithOpFlags(
*slot,
@@ -131,7 +128,6 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
};
assert_eq!(insensitive_secret_ptr.is_null(), public_ptr.is_null());
let secret_ptr = if insensitive_secret_ptr.is_null() {
- #[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
unsafe {
p11::PK11_GenerateKeyPairWithOpFlags(
*slot,
diff --git a/third_party/rust/neqo-crypto/src/ext.rs b/third_party/rust/neqo-crypto/src/ext.rs
index 310e87a1b7..02ee6340c1 100644
--- a/third_party/rust/neqo-crypto/src/ext.rs
+++ b/third_party/rust/neqo-crypto/src/ext.rs
@@ -6,7 +6,6 @@
use std::{
cell::RefCell,
- convert::TryFrom,
os::raw::{c_uint, c_void},
pin::Pin,
rc::Rc,
@@ -16,6 +15,7 @@ use crate::{
agentio::as_c_void,
constants::{Extension, HandshakeMessage, TLS_HS_CLIENT_HELLO, TLS_HS_ENCRYPTED_EXTENSIONS},
err::Res,
+ null_safe_slice,
ssl::{
PRBool, PRFileDesc, SECFailure, SECStatus, SECSuccess, SSLAlertDescription,
SSLExtensionHandler, SSLExtensionWriter, SSLHandshakeType,
@@ -105,7 +105,7 @@ impl ExtensionTracker {
alert: *mut SSLAlertDescription,
arg: *mut c_void,
) -> SECStatus {
- let d = std::slice::from_raw_parts(data, len as usize);
+ let d = null_safe_slice(data, len);
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
Self::wrap_handler_call(arg, |handler| {
// Cast is safe here because the message type is always part of the enum
diff --git a/third_party/rust/neqo-crypto/src/hkdf.rs b/third_party/rust/neqo-crypto/src/hkdf.rs
index e3cf77418c..3706be6c3b 100644
--- a/third_party/rust/neqo-crypto/src/hkdf.rs
+++ b/third_party/rust/neqo-crypto/src/hkdf.rs
@@ -5,7 +5,6 @@
// except according to those terms.
use std::{
- convert::TryFrom,
os::raw::{c_char, c_uint},
ptr::null_mut,
};
@@ -17,9 +16,10 @@ use crate::{
},
err::{Error, Res},
p11::{
- random, Item, PK11Origin, PK11SymKey, PK11_ImportDataKey, Slot, SymKey, CKA_DERIVE,
+ Item, PK11Origin, PK11SymKey, PK11_ImportDataKey, Slot, SymKey, CKA_DERIVE,
CKM_HKDF_DERIVE, CK_ATTRIBUTE_TYPE, CK_MECHANISM_TYPE,
},
+ random,
};
experimental_api!(SSL_HkdfExtract(
@@ -40,24 +40,32 @@ experimental_api!(SSL_HkdfExpandLabel(
secret: *mut *mut PK11SymKey,
));
-fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
+const MAX_KEY_SIZE: usize = 48;
+const fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
if version != TLS_VERSION_1_3 {
return Err(Error::UnsupportedVersion);
}
- Ok(match cipher {
+ let size = match cipher {
TLS_AES_128_GCM_SHA256 | TLS_CHACHA20_POLY1305_SHA256 => 32,
TLS_AES_256_GCM_SHA384 => 48,
_ => return Err(Error::UnsupportedCipher),
- })
+ };
+ debug_assert!(size <= MAX_KEY_SIZE);
+ Ok(size)
}
/// Generate a random key of the right size for the given suite.
///
/// # Errors
///
-/// Only if NSS fails.
+/// If the ciphersuite or protocol version is not supported.
pub fn generate_key(version: Version, cipher: Cipher) -> Res<SymKey> {
- import_key(version, &random(key_size(version, cipher)?))
+ // With generic_const_expr, this becomes:
+ // import_key(version, &random::<{ key_size(version, cipher) }>())
+ import_key(
+ version,
+ &random::<MAX_KEY_SIZE>()[0..key_size(version, cipher)?],
+ )
}
/// Import a symmetric key for use with HKDF.
@@ -70,7 +78,6 @@ pub fn import_key(version: Version, buf: &[u8]) -> Res<SymKey> {
return Err(Error::UnsupportedVersion);
}
let slot = Slot::internal()?;
- #[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
let key_ptr = unsafe {
PK11_ImportDataKey(
*slot,
diff --git a/third_party/rust/neqo-crypto/src/hp.rs b/third_party/rust/neqo-crypto/src/hp.rs
index 2479eff8f5..1eba6a9cb5 100644
--- a/third_party/rust/neqo-crypto/src/hp.rs
+++ b/third_party/rust/neqo-crypto/src/hp.rs
@@ -6,7 +6,6 @@
use std::{
cell::RefCell,
- convert::TryFrom,
fmt::{self, Debug},
os::raw::{c_char, c_int, c_uint},
ptr::{addr_of_mut, null, null_mut},
@@ -46,7 +45,7 @@ pub enum HpKey {
/// track references using `Rc`. `PK11Context` can't be used with `PK11_CloneContext`
/// as that is not supported for these contexts.
Aes(Rc<RefCell<Context>>),
- /// The ChaCha20 mask has to invoke a new PK11_Encrypt every time as it needs to
+ /// The `ChaCha20` mask has to invoke a new `PK11_Encrypt` every time as it needs to
/// change the counter and nonce on each invocation.
Chacha(SymKey),
}
@@ -76,7 +75,6 @@ impl HpKey {
let l = label.as_bytes();
let mut secret: *mut PK11SymKey = null_mut();
- #[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
let (mech, key_size) = match cipher {
TLS_AES_128_GCM_SHA256 => (CK_MECHANISM_TYPE::from(CKM_AES_ECB), 16),
TLS_AES_256_GCM_SHA384 => (CK_MECHANISM_TYPE::from(CKM_AES_ECB), 32),
@@ -104,8 +102,6 @@ impl HpKey {
let res = match cipher {
TLS_AES_128_GCM_SHA256 | TLS_AES_256_GCM_SHA384 => {
- // TODO: Remove when we bump the MSRV to 1.74.0.
- #[allow(clippy::useless_conversion)]
let context_ptr = unsafe {
PK11_CreateContextBySymKey(
mech,
@@ -181,8 +177,6 @@ impl HpKey {
};
let mut output_len: c_uint = 0;
let mut param_item = Item::wrap_struct(&params);
- // TODO: Remove when we bump the MSRV to 1.74.0.
- #[allow(clippy::useless_conversion)]
secstatus_to_res(unsafe {
PK11_Encrypt(
**key,
diff --git a/third_party/rust/neqo-crypto/src/lib.rs b/third_party/rust/neqo-crypto/src/lib.rs
index 05424ee1f3..2ec1b4a3ea 100644
--- a/third_party/rust/neqo-crypto/src/lib.rs
+++ b/third_party/rust/neqo-crypto/src/lib.rs
@@ -4,13 +4,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
-#![warn(clippy::pedantic)]
-// Bindgen auto generated code
-// won't adhere to the clippy rules below
-#![allow(clippy::module_name_repetitions)]
-#![allow(clippy::unseparated_literal_suffix)]
-#![allow(clippy::used_underscore_binding)]
+#![allow(clippy::module_name_repetitions)] // This lint doesn't work here.
+#![allow(clippy::unseparated_literal_suffix, clippy::used_underscore_binding)] // For bindgen code.
mod aead;
#[cfg(feature = "fuzzing")]
@@ -27,7 +22,6 @@ mod exp;
pub mod ext;
pub mod hkdf;
pub mod hp;
-mod once;
#[macro_use]
mod p11;
mod prio;
@@ -37,11 +31,7 @@ pub mod selfencrypt;
mod ssl;
mod time;
-use std::{
- ffi::CString,
- path::{Path, PathBuf},
- ptr::null,
-};
+use std::{ffi::CString, path::PathBuf, ptr::null, sync::OnceLock};
#[cfg(not(feature = "fuzzing"))]
pub use self::aead::RealAead as Aead;
@@ -49,7 +39,6 @@ pub use self::aead::RealAead as Aead;
pub use self::aead::RealAead;
#[cfg(feature = "fuzzing")]
pub use self::aead_fuzzing::FuzzingAead as Aead;
-use self::once::OnceResult;
pub use self::{
agent::{
Agent, AllowZeroRtt, Client, HandshakeState, Record, RecordList, ResumptionToken,
@@ -64,7 +53,7 @@ pub use self::{
},
err::{Error, PRErrorCode, Res},
ext::{ExtensionHandler, ExtensionHandlerResult, ExtensionWriterResult},
- p11::{random, PrivateKey, PublicKey, SymKey},
+ p11::{random, randomize, PrivateKey, PublicKey, SymKey},
replay::AntiReplay,
secrets::SecretDirection,
ssl::Opt,
@@ -87,7 +76,7 @@ fn secstatus_to_res(code: nss::SECStatus) -> Res<()> {
enum NssLoaded {
External,
NoDb,
- Db(Box<Path>),
+ Db,
}
impl Drop for NssLoaded {
@@ -100,7 +89,7 @@ impl Drop for NssLoaded {
}
}
-static mut INITIALIZED: OnceResult<NssLoaded> = OnceResult::new();
+static INITIALIZED: OnceLock<NssLoaded> = OnceLock::new();
fn already_initialized() -> bool {
unsafe { nss::NSS_IsInitialized() != 0 }
@@ -124,19 +113,18 @@ fn version_check() {
pub fn init() {
// Set time zero.
time::init();
- unsafe {
- INITIALIZED.call_once(|| {
- version_check();
- if already_initialized() {
- return NssLoaded::External;
- }
+ _ = INITIALIZED.get_or_init(|| {
+ version_check();
+ if already_initialized() {
+ return NssLoaded::External;
+ }
- secstatus_to_res(nss::NSS_NoDB_Init(null())).expect("NSS_NoDB_Init failed");
- secstatus_to_res(nss::NSS_SetDomesticPolicy()).expect("NSS_SetDomesticPolicy failed");
+ secstatus_to_res(unsafe { nss::NSS_NoDB_Init(null()) }).expect("NSS_NoDB_Init failed");
+ secstatus_to_res(unsafe { nss::NSS_SetDomesticPolicy() })
+ .expect("NSS_SetDomesticPolicy failed");
- NssLoaded::NoDb
- });
- }
+ NssLoaded::NoDb
+ });
}
/// This enables SSLTRACE by calling a simple, harmless function to trigger its
@@ -158,51 +146,71 @@ fn enable_ssl_trace() {
/// If NSS cannot be initialized.
pub fn init_db<P: Into<PathBuf>>(dir: P) {
time::init();
- unsafe {
- INITIALIZED.call_once(|| {
- version_check();
- if already_initialized() {
- return NssLoaded::External;
- }
+ _ = INITIALIZED.get_or_init(|| {
+ version_check();
+ if already_initialized() {
+ return NssLoaded::External;
+ }
- let path = dir.into();
- assert!(path.is_dir());
- let pathstr = path.to_str().expect("path converts to string").to_string();
- let dircstr = CString::new(pathstr).unwrap();
- let empty = CString::new("").unwrap();
- secstatus_to_res(nss::NSS_Initialize(
+ let path = dir.into();
+ assert!(path.is_dir());
+ let pathstr = path.to_str().expect("path converts to string").to_string();
+ let dircstr = CString::new(pathstr).unwrap();
+ let empty = CString::new("").unwrap();
+ secstatus_to_res(unsafe {
+ nss::NSS_Initialize(
dircstr.as_ptr(),
empty.as_ptr(),
empty.as_ptr(),
nss::SECMOD_DB.as_ptr().cast(),
nss::NSS_INIT_READONLY,
- ))
- .expect("NSS_Initialize failed");
-
- secstatus_to_res(nss::NSS_SetDomesticPolicy()).expect("NSS_SetDomesticPolicy failed");
- secstatus_to_res(ssl::SSL_ConfigServerSessionIDCache(
- 1024,
- 0,
- 0,
- dircstr.as_ptr(),
- ))
- .expect("SSL_ConfigServerSessionIDCache failed");
-
- #[cfg(debug_assertions)]
- enable_ssl_trace();
-
- NssLoaded::Db(path.into_boxed_path())
- });
- }
+ )
+ })
+ .expect("NSS_Initialize failed");
+
+ secstatus_to_res(unsafe { nss::NSS_SetDomesticPolicy() })
+ .expect("NSS_SetDomesticPolicy failed");
+ secstatus_to_res(unsafe {
+ ssl::SSL_ConfigServerSessionIDCache(1024, 0, 0, dircstr.as_ptr())
+ })
+ .expect("SSL_ConfigServerSessionIDCache failed");
+
+ #[cfg(debug_assertions)]
+ enable_ssl_trace();
+
+ NssLoaded::Db
+ });
}
/// # Panics
///
/// If NSS isn't initialized.
pub fn assert_initialized() {
- unsafe {
- INITIALIZED.call_once(|| {
- panic!("NSS not initialized with init or init_db");
- });
+ INITIALIZED
+ .get()
+ .expect("NSS not initialized with init or init_db");
+}
+
+/// NSS tends to return empty "slices" with a null pointer, which will cause
+/// `std::slice::from_raw_parts` to panic if passed directly. This wrapper avoids
+/// that issue. It also performs conversion for lengths, as a convenience.
+///
+/// # Panics
+/// If the provided length doesn't fit into a `usize`.
+///
+/// # Safety
+/// The caller must adhere to the safety constraints of `std::slice::from_raw_parts`,
+/// except that this will accept a null value for `data`.
+unsafe fn null_safe_slice<'a, T>(data: *const u8, len: T) -> &'a [u8]
+where
+ usize: TryFrom<T>,
+{
+ if data.is_null() {
+ &[]
+ } else if let Ok(len) = usize::try_from(len) {
+ #[allow(clippy::disallowed_methods)]
+ std::slice::from_raw_parts(data, len)
+ } else {
+ panic!("null_safe_slice: size overflow");
}
}
diff --git a/third_party/rust/neqo-crypto/src/once.rs b/third_party/rust/neqo-crypto/src/once.rs
deleted file mode 100644
index 80657cfe26..0000000000
--- a/third_party/rust/neqo-crypto/src/once.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::sync::Once;
-
-#[allow(clippy::module_name_repetitions)]
-pub struct OnceResult<T> {
- once: Once,
- v: Option<T>,
-}
-
-impl<T> OnceResult<T> {
- #[must_use]
- pub const fn new() -> Self {
- Self {
- once: Once::new(),
- v: None,
- }
- }
-
- pub fn call_once<F: FnOnce() -> T>(&mut self, f: F) -> &T {
- let v = &mut self.v;
- self.once.call_once(|| {
- *v = Some(f());
- });
- self.v.as_ref().unwrap()
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::OnceResult;
-
- static mut STATIC_ONCE_RESULT: OnceResult<u64> = OnceResult::new();
-
- #[test]
- fn static_update() {
- assert_eq!(*unsafe { STATIC_ONCE_RESULT.call_once(|| 23) }, 23);
- assert_eq!(*unsafe { STATIC_ONCE_RESULT.call_once(|| 24) }, 23);
- }
-}
diff --git a/third_party/rust/neqo-crypto/src/p11.rs b/third_party/rust/neqo-crypto/src/p11.rs
index 508d240062..5552882e2e 100644
--- a/third_party/rust/neqo-crypto/src/p11.rs
+++ b/third_party/rust/neqo-crypto/src/p11.rs
@@ -10,7 +10,7 @@
#![allow(non_snake_case)]
use std::{
- convert::TryFrom,
+ cell::RefCell,
mem,
ops::{Deref, DerefMut},
os::raw::{c_int, c_uint},
@@ -19,7 +19,10 @@ use std::{
use neqo_common::hex_with_len;
-use crate::err::{secstatus_to_res, Error, Res};
+use crate::{
+ err::{secstatus_to_res, Error, Res},
+ null_safe_slice,
+};
#[allow(clippy::upper_case_acronyms)]
#[allow(clippy::unreadable_literal)]
@@ -139,7 +142,6 @@ impl PrivateKey {
/// When the values are too large to fit. So never.
pub fn key_data(&self) -> Res<Vec<u8>> {
let mut key_item = Item::make_empty();
- #[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
secstatus_to_res(unsafe {
PK11_ReadRawAttribute(
PK11ObjectType::PK11_TypePrivKey,
@@ -148,9 +150,7 @@ impl PrivateKey {
&mut key_item,
)
})?;
- let slc = unsafe {
- std::slice::from_raw_parts(key_item.data, usize::try_from(key_item.len).unwrap())
- };
+ let slc = unsafe { null_safe_slice(key_item.data, key_item.len) };
let key = Vec::from(slc);
// The data that `key_item` refers to needs to be freed, but we can't
// use the scoped `Item` implementation. This is OK as long as nothing
@@ -206,7 +206,7 @@ impl SymKey {
// This is accessing a value attached to the key, so we can treat this as a borrow.
match unsafe { key_item.as_mut() } {
None => Err(Error::InternalError),
- Some(key) => Ok(unsafe { std::slice::from_raw_parts(key.data, key.len as usize) }),
+ Some(key) => Ok(unsafe { null_safe_slice(key.data, key.len) }),
}
}
}
@@ -285,36 +285,112 @@ impl Item {
let b = self.ptr.as_ref().unwrap();
// Sanity check the type, as some types don't count bytes in `Item::len`.
assert_eq!(b.type_, SECItemType::siBuffer);
- let slc = std::slice::from_raw_parts(b.data, usize::try_from(b.len).unwrap());
+ let slc = null_safe_slice(b.data, b.len);
Vec::from(slc)
}
}
-/// Generate a randomized buffer.
+/// Fill a buffer with randomness.
///
/// # Panics
///
/// When `size` is too large or NSS fails.
-#[must_use]
-pub fn random(size: usize) -> Vec<u8> {
- let mut buf = vec![0; size];
- secstatus_to_res(unsafe {
- PK11_GenerateRandom(buf.as_mut_ptr(), c_int::try_from(buf.len()).unwrap())
- })
- .unwrap();
+pub fn randomize<B: AsMut<[u8]>>(mut buf: B) -> B {
+ let m_buf = buf.as_mut();
+ let len = c_int::try_from(m_buf.len()).unwrap();
+ secstatus_to_res(unsafe { PK11_GenerateRandom(m_buf.as_mut_ptr(), len) }).unwrap();
buf
}
+struct RandomCache {
+ cache: [u8; Self::SIZE],
+ used: usize,
+}
+
+impl RandomCache {
+ const SIZE: usize = 256;
+ const CUTOFF: usize = 32;
+
+ fn new() -> Self {
+ RandomCache {
+ cache: [0; Self::SIZE],
+ used: Self::SIZE,
+ }
+ }
+
+ fn randomize<B: AsMut<[u8]>>(&mut self, mut buf: B) -> B {
+ let m_buf = buf.as_mut();
+ debug_assert!(m_buf.len() <= Self::CUTOFF);
+ let avail = Self::SIZE - self.used;
+ if m_buf.len() <= avail {
+ m_buf.copy_from_slice(&self.cache[self.used..self.used + m_buf.len()]);
+ self.used += m_buf.len();
+ } else {
+ if avail > 0 {
+ m_buf[..avail].copy_from_slice(&self.cache[self.used..]);
+ }
+ randomize(&mut self.cache[..]);
+ self.used = m_buf.len() - avail;
+ m_buf[avail..].copy_from_slice(&self.cache[..self.used]);
+ }
+ buf
+ }
+}
+
+/// Generate a randomized array.
+///
+/// # Panics
+///
+/// When `size` is too large or NSS fails.
+#[must_use]
+pub fn random<const N: usize>() -> [u8; N] {
+ thread_local!(static CACHE: RefCell<RandomCache> = RefCell::new(RandomCache::new()));
+
+ let buf = [0; N];
+ if N <= RandomCache::CUTOFF {
+ CACHE.with_borrow_mut(|c| c.randomize(buf))
+ } else {
+ randomize(buf)
+ }
+}
+
#[cfg(test)]
mod test {
use test_fixture::fixture_init;
- use super::random;
+ use super::RandomCache;
+ use crate::{random, randomize};
#[test]
fn randomness() {
fixture_init();
- // If this ever fails, there is either a bug, or it's time to buy a lottery ticket.
- assert_ne!(random(16), random(16));
+ // If any of these ever fail, there is either a bug, or it's time to buy a lottery ticket.
+ assert_ne!(random::<16>(), randomize([0; 16]));
+ assert_ne!([0; 16], random::<16>());
+ assert_ne!([0; 64], random::<64>());
+ }
+
+ #[test]
+ fn cache_random_lengths() {
+ const ZERO: [u8; 256] = [0; 256];
+
+ fixture_init();
+ let mut cache = RandomCache::new();
+ let mut buf = [0; 256];
+ let bits = usize::BITS - (RandomCache::CUTOFF - 1).leading_zeros();
+ let mask = 0xff >> (u8::BITS - bits);
+
+ for _ in 0..100 {
+ let len = loop {
+ let len = usize::from(random::<1>()[0] & mask) + 1;
+ if len <= RandomCache::CUTOFF {
+ break len;
+ }
+ };
+ buf.fill(0);
+ if len >= 16 {
+ assert_ne!(&cache.randomize(&mut buf[..len])[..len], &ZERO[..len]);
+ }
+ }
}
}
diff --git a/third_party/rust/neqo-crypto/src/replay.rs b/third_party/rust/neqo-crypto/src/replay.rs
index d4d3677f5c..5fd6fd1250 100644
--- a/third_party/rust/neqo-crypto/src/replay.rs
+++ b/third_party/rust/neqo-crypto/src/replay.rs
@@ -5,7 +5,6 @@
// except according to those terms.
use std::{
- convert::{TryFrom, TryInto},
ops::{Deref, DerefMut},
os::raw::c_uint,
ptr::null_mut,
diff --git a/third_party/rust/neqo-crypto/src/selfencrypt.rs b/third_party/rust/neqo-crypto/src/selfencrypt.rs
index b8a63153fd..1130c35250 100644
--- a/third_party/rust/neqo-crypto/src/selfencrypt.rs
+++ b/third_party/rust/neqo-crypto/src/selfencrypt.rs
@@ -82,7 +82,7 @@ impl SelfEncrypt {
// opaque aead_encrypted(plaintext)[length as expanded];
// };
// AAD covers the entire header, plus the value of the AAD parameter that is provided.
- let salt = random(Self::SALT_LENGTH);
+ let salt = random::<{ Self::SALT_LENGTH }>();
let cipher = self.make_aead(&self.key, &salt)?;
let encoded_len = 2 + salt.len() + plaintext.len() + cipher.expansion();
diff --git a/third_party/rust/neqo-crypto/src/time.rs b/third_party/rust/neqo-crypto/src/time.rs
index 84dbfdb4a5..0e59c4f5e2 100644
--- a/third_party/rust/neqo-crypto/src/time.rs
+++ b/third_party/rust/neqo-crypto/src/time.rs
@@ -7,18 +7,16 @@
#![allow(clippy::upper_case_acronyms)]
use std::{
- boxed::Box,
- convert::{TryFrom, TryInto},
ops::Deref,
os::raw::c_void,
pin::Pin,
+ sync::OnceLock,
time::{Duration, Instant},
};
use crate::{
agentio::as_c_void,
err::{Error, Res},
- once::OnceResult,
ssl::{PRFileDesc, SSLTimeFunc},
};
@@ -67,14 +65,13 @@ impl TimeZero {
}
}
-static mut BASE_TIME: OnceResult<TimeZero> = OnceResult::new();
+static BASE_TIME: OnceLock<TimeZero> = OnceLock::new();
fn get_base() -> &'static TimeZero {
- let f = || TimeZero {
+ BASE_TIME.get_or_init(|| TimeZero {
instant: Instant::now(),
prtime: unsafe { PR_Now() },
- };
- unsafe { BASE_TIME.call_once(f) }
+ })
}
pub(crate) fn init() {
@@ -97,9 +94,8 @@ impl Deref for Time {
impl From<Instant> for Time {
/// Convert from an Instant into a Time.
fn from(t: Instant) -> Self {
- // Call `TimeZero::baseline(t)` so that time zero can be set.
- let f = || TimeZero::baseline(t);
- _ = unsafe { BASE_TIME.call_once(f) };
+ // Initialize `BASE_TIME` using `TimeZero::baseline(t)`.
+ BASE_TIME.get_or_init(|| TimeZero::baseline(t));
Self { t }
}
}
@@ -108,14 +104,17 @@ impl TryFrom<PRTime> for Time {
type Error = Error;
fn try_from(prtime: PRTime) -> Res<Self> {
let base = get_base();
- if let Some(delta) = prtime.checked_sub(base.prtime) {
- let d = Duration::from_micros(delta.try_into()?);
- base.instant
- .checked_add(d)
- .map_or(Err(Error::TimeTravelError), |t| Ok(Self { t }))
+ let delta = prtime
+ .checked_sub(base.prtime)
+ .ok_or(Error::TimeTravelError)?;
+ let d = Duration::from_micros(u64::try_from(delta.abs())?);
+ let t = if delta >= 0 {
+ base.instant.checked_add(d)
} else {
- Err(Error::TimeTravelError)
- }
+ base.instant.checked_sub(d)
+ };
+ let t = t.ok_or(Error::TimeTravelError)?;
+ Ok(Self { t })
}
}
@@ -123,14 +122,21 @@ impl TryInto<PRTime> for Time {
type Error = Error;
fn try_into(self) -> Res<PRTime> {
let base = get_base();
- let delta = self
- .t
- .checked_duration_since(base.instant)
- .ok_or(Error::TimeTravelError)?;
- if let Ok(d) = PRTime::try_from(delta.as_micros()) {
- d.checked_add(base.prtime).ok_or(Error::TimeTravelError)
+
+ if let Some(delta) = self.t.checked_duration_since(base.instant) {
+ if let Ok(d) = PRTime::try_from(delta.as_micros()) {
+ d.checked_add(base.prtime).ok_or(Error::TimeTravelError)
+ } else {
+ Err(Error::TimeTravelError)
+ }
} else {
- Err(Error::TimeTravelError)
+ // Try to go backwards from the base time.
+ let backwards = base.instant - self.t; // infallible
+ if let Ok(d) = PRTime::try_from(backwards.as_micros()) {
+ base.prtime.checked_sub(d).ok_or(Error::TimeTravelError)
+ } else {
+ Err(Error::TimeTravelError)
+ }
}
}
}
@@ -207,10 +213,7 @@ impl Default for TimeHolder {
#[cfg(test)]
mod test {
- use std::{
- convert::{TryFrom, TryInto},
- time::{Duration, Instant},
- };
+ use std::time::{Duration, Instant};
use super::{get_base, init, Interval, PRTime, Time};
use crate::err::Res;
@@ -228,16 +231,23 @@ mod test {
}
#[test]
- fn past_time() {
+ fn past_prtime() {
+ const DELTA: Duration = Duration::from_secs(1);
init();
let base = get_base();
- assert!(Time::try_from(base.prtime - 1).is_err());
+ let delta_micros = PRTime::try_from(DELTA.as_micros()).unwrap();
+ println!("{} - {}", base.prtime, delta_micros);
+ let t = Time::try_from(base.prtime - delta_micros).unwrap();
+ assert_eq!(Instant::from(t) + DELTA, base.instant);
}
#[test]
- fn negative_time() {
+ fn past_instant() {
+ const DELTA: Duration = Duration::from_secs(1);
init();
- assert!(Time::try_from(-1).is_err());
+ let base = get_base();
+ let t = Time::from(base.instant.checked_sub(DELTA).unwrap());
+ assert_eq!(Instant::from(t) + DELTA, base.instant);
}
#[test]