Repository: rustls/rustls (language: rust)

Issue:
`no-std` support for targets w/o atomics?
Since `0.23.0` there is support for `no-std/alloc` which works fine on targets supporting atomics. Some targets however don't have support for atomics and usually the `portable-atomic` crate is used for that. It seems all the dependencies of Rustls support that but Rustls itself needs `alloc::sync::Arc` which is not available without atomics.

Is supporting those targets desired? Would a PR adding that something you might consider?


Discussion / hints:
Could you say which targets these are?
Microcontrollers like ESP32-C2, ESP32-C3 and ESP32-S2 (other members of the ESP32-family come with support for atomics)

Thanks! I could see two routes for this:

1. Globally, replace all uses of Arc with a crate-local Arc type alias. For these targets, that alias would be Rc. Remove all the Send+Sync bounds on everything for those targets. The result would be rustls types cannot be moved between threads, so multiple threads using rustls would each need their own *Config values, etc.
2. For these targets, depend on `portable-atomic-util` and use its `Arc` as a polyfill.

Sounds like you were proposing (2)?
Yes, my initial idea was (2)
If we take the 2nd approach, is there a way to prevent regression in our CI matrix? How do other no-std projects handle that? Presently our no-std testing is done w/ `x86_64-unknown-none` and since that platform supports atomics it seems like it would be tricky to catch mistakes in the polyfill. 
> If we take the 2nd approach, is there a way to prevent regression in our CI matrix? How do other no-std projects handle that? Presently our no-std testing is done w/ `x86_64-unknown-none` and since that platform supports atomics it seems like it would be tricky to catch mistakes in the polyfill.

I see how optionally depending on the polyfill will make things tricky. Thinking about it makes option (1) more appealing
I worry that making trait bounds optional depending on targets will be a pretty big pain in the ass?
> I worry that making trait bounds optional depending on targets will be a pretty big pain in the ass?

Yes - I didn't even dare to think about that initially
I am preparing a proposal for idea 1, with optional alias to `Rc`, turned out to be a bit heavier change than I expected. I would love to break some things out to smaller pieces, may do this to a very limited extent for now.

I do really like idea 2 as well, and would love to see both ideas as options. My initial attempt for idea 2 was unfortunately blocked by this: https://github.com/taiki-e/portable-atomic/issues/143
> I do really like idea 2 as well, and would love to see both ideas as options. My initial attempt for idea 2 was unfortunately blocked by this: [taiki-e/portable-atomic#143](https://github.com/taiki-e/portable-atomic/issues/143)

I played around with that approach and tried to work around that via `Box` like here: https://github.com/rustls/rustls/compare/main...bjoernQ:rustls:portable-atomic

There is still an issue around https://github.com/rustls/rustls/blob/f17866cd4040d7e38e3f1d84b16c671ef78b5ba7/rustls/src/server/builder.rs#L135-L138 which I wasn't able to fully solve (i.e. building with `portable-atomic` only succeeds for `no-std` on my branch)

> There is still an issue around
> 
> https://github.com/rustls/rustls/blob/f17866cd4040d7e38e3f1d84b16c671ef78b5ba7/rustls/src/server/builder.rs#L135-L138
> 
> which I wasn't able to fully solve (i.e. building with `portable-atomic` only succeeds for `no-std` on my branch)

I think that issue is due to this code: https://github.com/rustls/rustls/blob/v/0.23.12/rustls/src/server/handy.rs#L48-L50

`handy::ServerSessionMemoryCache::new` is already returning an `Arc` object ... we may need to modify this to work around https://github.com/taiki-e/portable-atomic/issues/143

I tried building from your branch. I was able to build with `no-std`. It also looks like there is an issue with OtherError due to the way it is containing `Arc<dyn StdError ...`
Quick update: I have proposal almost ready for review in PR #2200 ...

This proposal requires an unstable cfg option that I have successfully contributed to `portable-atomic-util` & requires Rust nightly version. It seems to me like work on this kind of embedded hardware is often done with Rust nightly.

One issue is that I had some trouble building the built-in `aws-lc-rs` & `ring` providers with the no atomic ptr targets. I have started working on getting external `rustls-rustcrypto` provider to build for ESP32 with `riscv32imc-unknown-none-elf` target, PR on my personal fork for now: https://github.com/brodycj/rustls-rustcrypto/pull/1

@bjoernQ & @rustls team any feedback you may have on PR #2200 would be much appreciated.

@bjoernQ I hope this will be ready as an early holiday present for you :)
>  I hope this will be ready as an early holiday present for you :)

Awesome! Looks good to me! Thanks for all your effort
> requires Rust nightly version

Perhaps this isn't a feature ready for mainline Rustls in this case?

> One issue is that I had some trouble building the built-in aws-lc-rs & ring providers with the no atomic ptr targets.

I have similar feelings here. If this only works with rustls-rustcrypto, and not the two mainline crypto providers, is it ready to ship?

> Perhaps this isn't a feature ready for mainline Rustls in this case?

I was hoping to contribute this feature as an unstable feature, and I think there is plenty of precedence for supporting unstable feature options. Here are a couple prime examples that I found from a very quick search, which happen to be within the Rust ecosystem:

- https://doc.rust-lang.org/cargo/reference/unstable.html - unstable features in Rust itself
- https://docs.deno.com/runtime/reference/cli/unstable_flags/

Yes there would be some special requirements for those who wish to start using this proposed feature, which I don't think should affect anyone else not using this feature.

The one minor caveat I can think of is that someone building rustls with `--all-features` flag would be affected by this feature. But considering that rustls is a library, I think this could only be an issue with someone building rustls as a stand-alone library build, NOT someone including rustls as a dependency for a higher-level application or library.

I really hope we can find a way to start moving forward so that people would not need to maintain a fork of rustls to support targets with no atomic ptr.

---

P.S. Possible alternative could be to use an unstable cfg feature, like I did in this released contribution: [taiki-e/portable-atomic#195](https://github.com/taiki-e/portable-atomic/pull/195)

I know this would be against how rustls has been supporting options & features ... wish we had a better way to distinguish between stable vs unstable features.

---

P.S. 2: According to <https://github.com/esp-rs/esp-hal/issues/1836#issuecomment-2541965061> it looks like this discussion should continue in PR #2200.
Left a response in #2200.

Fix patch:
diff --git a/.clippy.toml b/.clippy.toml
index cc94ec53e13..1d849dc657e 100644
--- a/.clippy.toml
+++ b/.clippy.toml
@@ -1,1 +1,6 @@
 upper-case-acronyms-aggressive = true
+
+# only intended to affect main rustls crate - need to allow disallowed-types in all other crates in Clippy CI job
+disallowed-types = [
+  { path = "std::sync::Arc", reason = "must use Arc from sync module to support downstream forks targetting architectures without atomic ptrs" },
+]
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8cc8fab36a4..39ba757762a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -464,7 +464,11 @@ jobs:
         with:
           components: clippy
       # We want to be free of any warnings, so deny them.
-      - run: ./admin/clippy -- --deny warnings
+      # - Allow `clippy::disallowed_types` as a workaround since `disallowed_types` configured in `.clippy.toml`
+      #   is only intended for the main `rustls` crate.
+      - run: ./admin/clippy -- --deny warnings --allow clippy::disallowed_types
+      # - Keep the main crate free of all warnings.
+      - run: cargo clippy -p rustls -- --deny warnings
 
   clippy-nightly:
     name: Clippy (Nightly)
@@ -483,8 +487,12 @@ jobs:
         uses: dtolnay/rust-toolchain@nightly
         with:
           components: clippy
-      # do not deny warnings, as nightly clippy sometimes has false negatives
-      - run: ./admin/clippy
+      # Do not deny warnings, as nightly clippy sometimes has false negatives.
+      # - Ignore `clippy::disallowed_types` as a workaround since `disallowed_types` configured in `.clippy.toml`
+      #   is only intended for main `rustls` crate.
+      - run: ./admin/clippy -- --allow clippy::disallowed_types
+      # Check the main crate for any Clippy nightly warnings, but do not deny them.
+      - run: cargo clippy -p rustls
 
   check-external-types:
     name: Validate external types appearing in public API
diff --git a/rustls/src/builder.rs b/rustls/src/builder.rs
index 85f95bdf436..342e3633600 100644
--- a/rustls/src/builder.rs
+++ b/rustls/src/builder.rs
@@ -1,5 +1,4 @@
 use alloc::format;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt;
 use core::marker::PhantomData;
@@ -8,6 +7,7 @@ use crate::client::EchMode;
 use crate::crypto::CryptoProvider;
 use crate::error::Error;
 use crate::msgs::handshake::ALL_KEY_EXCHANGE_ALGORITHMS;
+use crate::sync::Arc;
 use crate::time_provider::TimeProvider;
 use crate::versions;
 #[cfg(doc)]
diff --git a/rustls/src/client/builder.rs b/rustls/src/client/builder.rs
index bb2a7d66ecc..9c0316f3013 100644
--- a/rustls/src/client/builder.rs
+++ b/rustls/src/client/builder.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::marker::PhantomData;
 
@@ -10,6 +9,7 @@ use crate::client::{handy, ClientConfig, EchMode, ResolvesClientCert};
 use crate::error::Error;
 use crate::key_log::NoKeyLog;
 use crate::msgs::handshake::CertificateChain;
+use crate::sync::Arc;
 use crate::versions::TLS13;
 use crate::webpki::{self, WebPkiServerVerifier};
 use crate::{compress, verify, versions, WantsVersions};
@@ -89,10 +89,10 @@ impl ConfigBuilder<ClientConfig, WantsVerifier> {
 
 /// Container for unsafe APIs
 pub(super) mod danger {
-    use alloc::sync::Arc;
     use core::marker::PhantomData;
 
     use crate::client::WantsClientCert;
+    use crate::sync::Arc;
     use crate::{verify, ClientConfig, ConfigBuilder, WantsVerifier};
 
     /// Accessor for dangerous configuration options.
diff --git a/rustls/src/client/client_conn.rs b/rustls/src/client/client_conn.rs
index 854c6b65b67..c2540be6308 100644
--- a/rustls/src/client/client_conn.rs
+++ b/rustls/src/client/client_conn.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::marker::PhantomData;
 use core::ops::{Deref, DerefMut};
@@ -20,6 +19,7 @@ use crate::msgs::enums::NamedGroup;
 use crate::msgs::handshake::ClientExtension;
 use crate::msgs::persist;
 use crate::suites::SupportedCipherSuite;
+use crate::sync::Arc;
 #[cfg(feature = "std")]
 use crate::time_provider::DefaultTimeProvider;
 use crate::time_provider::TimeProvider;
@@ -511,10 +511,9 @@ pub enum Tls12Resumption {
 
 /// Container for unsafe APIs
 pub(super) mod danger {
-    use alloc::sync::Arc;
-
     use super::verify::ServerCertVerifier;
     use super::ClientConfig;
+    use crate::sync::Arc;
 
     /// Accessor for dangerous configuration options.
     #[derive(Debug)]
@@ -611,7 +610,6 @@ impl EarlyData {
 
 #[cfg(feature = "std")]
 mod connection {
-    use alloc::sync::Arc;
     use alloc::vec::Vec;
     use core::fmt;
     use core::ops::{Deref, DerefMut};
@@ -625,6 +623,7 @@ mod connection {
     use crate::conn::{ConnectionCommon, ConnectionCore};
     use crate::error::Error;
     use crate::suites::ExtractedSecrets;
+    use crate::sync::Arc;
     use crate::ClientConfig;
 
     /// Stub that implements io::Write and dispatches to `write_early_data`.
diff --git a/rustls/src/client/common.rs b/rustls/src/client/common.rs
index ad5e82b0f70..a468af93839 100644
--- a/rustls/src/client/common.rs
+++ b/rustls/src/client/common.rs
@@ -1,11 +1,11 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 
 use super::ResolvesClientCert;
 use crate::log::{debug, trace};
 use crate::msgs::enums::ExtensionType;
 use crate::msgs::handshake::{CertificateChain, DistinguishedName, ServerExtension};
+use crate::sync::Arc;
 use crate::{compress, sign, SignatureScheme};
 
 #[derive(Debug)]
diff --git a/rustls/src/client/handy.rs b/rustls/src/client/handy.rs
index 78d9326d355..911894f2bbe 100644
--- a/rustls/src/client/handy.rs
+++ b/rustls/src/client/handy.rs
@@ -1,11 +1,10 @@
-use alloc::sync::Arc;
-
 use pki_types::ServerName;
 
 use crate::enums::SignatureScheme;
 use crate::error::Error;
 use crate::msgs::handshake::CertificateChain;
 use crate::msgs::persist;
+use crate::sync::Arc;
 use crate::{client, sign, NamedGroup};
 
 /// An implementer of `ClientSessionStore` which does nothing.
@@ -279,7 +278,6 @@ impl client::ResolvesClientCert for AlwaysResolvesClientRawPublicKeys {
 #[cfg(test)]
 #[macro_rules_attribute::apply(test_for_each_provider)]
 mod tests {
-    use alloc::sync::Arc;
     use std::prelude::v1::*;
 
     use pki_types::{ServerName, UnixTime};
@@ -294,6 +292,7 @@ mod tests {
     use crate::msgs::handshake::SessionId;
     use crate::msgs::persist::Tls13ClientSessionValue;
     use crate::suites::SupportedCipherSuite;
+    use crate::sync::Arc;
 
     #[test]
     fn test_noclientsessionstorage_does_nothing() {
diff --git a/rustls/src/client/hs.rs b/rustls/src/client/hs.rs
index 3a2aee48055..44c7dee361d 100644
--- a/rustls/src/client/hs.rs
+++ b/rustls/src/client/hs.rs
@@ -1,6 +1,5 @@
 use alloc::borrow::ToOwned;
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec;
 use alloc::vec::Vec;
 use core::ops::Deref;
@@ -37,6 +36,7 @@ use crate::msgs::handshake::{
 };
 use crate::msgs::message::{Message, MessagePayload};
 use crate::msgs::persist;
+use crate::sync::Arc;
 use crate::tls13::key_schedule::KeyScheduleEarly;
 use crate::SupportedCipherSuite;
 
diff --git a/rustls/src/client/tls12.rs b/rustls/src/client/tls12.rs
index 0f098d3d5e2..c0af6f2e59d 100644
--- a/rustls/src/client/tls12.rs
+++ b/rustls/src/client/tls12.rs
@@ -1,6 +1,5 @@
 use alloc::borrow::ToOwned;
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec;
 use alloc::vec::Vec;
 
@@ -31,6 +30,7 @@ use crate::msgs::message::{Message, MessagePayload};
 use crate::msgs::persist;
 use crate::sign::Signer;
 use crate::suites::{PartiallyExtractedSecrets, SupportedCipherSuite};
+use crate::sync::Arc;
 use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite};
 use crate::verify::{self, DigitallySignedStruct};
 
diff --git a/rustls/src/client/tls13.rs b/rustls/src/client/tls13.rs
index 6794579ab8e..94d904f0ee0 100644
--- a/rustls/src/client/tls13.rs
+++ b/rustls/src/client/tls13.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec;
 use alloc::vec::Vec;
 
@@ -37,6 +36,7 @@ use crate::msgs::message::{Message, MessagePayload};
 use crate::msgs::persist;
 use crate::sign::{CertifiedKey, Signer};
 use crate::suites::PartiallyExtractedSecrets;
+use crate::sync::Arc;
 use crate::tls13::key_schedule::{
     KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, KeyScheduleTraffic,
     ResumptionSecret,
diff --git a/rustls/src/compress.rs b/rustls/src/compress.rs
index e6a2f028d96..e7b07d1db09 100644
--- a/rustls/src/compress.rs
+++ b/rustls/src/compress.rs
@@ -34,7 +34,6 @@
 
 #[cfg(feature = "std")]
 use alloc::collections::VecDeque;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt::Debug;
 #[cfg(feature = "std")]
@@ -44,6 +43,7 @@ use crate::enums::CertificateCompressionAlgorithm;
 use crate::msgs::base::{Payload, PayloadU24};
 use crate::msgs::codec::Codec;
 use crate::msgs::handshake::{CertificatePayloadTls13, CompressedCertificatePayload};
+use crate::sync::Arc;
 
 /// Returns the supported `CertDecompressor` implementations enabled
 /// by crate features.
diff --git a/rustls/src/crypto/aws_lc_rs/hpke.rs b/rustls/src/crypto/aws_lc_rs/hpke.rs
index 80514de19c3..e7b1a949d4d 100644
--- a/rustls/src/crypto/aws_lc_rs/hpke.rs
+++ b/rustls/src/crypto/aws_lc_rs/hpke.rs
@@ -1,6 +1,4 @@
 use alloc::boxed::Box;
-#[cfg(feature = "std")]
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt::{self, Debug, Formatter};
 
@@ -21,6 +19,8 @@ use crate::crypto::hpke::{
 use crate::crypto::tls13::{expand, HkdfExpander, HkdfPrkExtract, HkdfUsingHmac};
 use crate::msgs::enums::{HpkeAead, HpkeKdf, HpkeKem};
 use crate::msgs::handshake::HpkeSymmetricCipherSuite;
+#[cfg(feature = "std")]
+use crate::sync::Arc;
 use crate::{Error, OtherError};
 
 /// Default [RFC 9180] Hybrid Public Key Encryption (HPKE) suites supported by aws-lc-rs cryptography.
diff --git a/rustls/src/crypto/aws_lc_rs/mod.rs b/rustls/src/crypto/aws_lc_rs/mod.rs
index 73749a28f09..8b2390c6583 100644
--- a/rustls/src/crypto/aws_lc_rs/mod.rs
+++ b/rustls/src/crypto/aws_lc_rs/mod.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 
 // aws-lc-rs has a -- roughly -- ring-compatible API, so we just reuse all that
@@ -14,6 +13,7 @@ use crate::enums::SignatureScheme;
 use crate::rand::GetRandomFailed;
 use crate::sign::SigningKey;
 use crate::suites::SupportedCipherSuite;
+use crate::sync::Arc;
 use crate::webpki::WebPkiSupportedAlgorithms;
 use crate::{Error, OtherError};
 
diff --git a/rustls/src/crypto/aws_lc_rs/sign.rs b/rustls/src/crypto/aws_lc_rs/sign.rs
index 91d9110e982..e251c4a7c64 100644
--- a/rustls/src/crypto/aws_lc_rs/sign.rs
+++ b/rustls/src/crypto/aws_lc_rs/sign.rs
@@ -2,7 +2,6 @@
 
 use alloc::boxed::Box;
 use alloc::string::ToString;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use alloc::{format, vec};
 use core::fmt::{self, Debug, Formatter};
@@ -15,6 +14,7 @@ use super::ring_like::signature::{self, EcdsaKeyPair, Ed25519KeyPair, KeyPair, R
 use crate::crypto::signer::{public_key_to_spki, Signer, SigningKey};
 use crate::enums::{SignatureAlgorithm, SignatureScheme};
 use crate::error::Error;
+use crate::sync::Arc;
 
 /// Parse `der` as any supported key encoding/type, returning
 /// the first which works.
diff --git a/rustls/src/crypto/aws_lc_rs/ticketer.rs b/rustls/src/crypto/aws_lc_rs/ticketer.rs
index dfed6b743be..3157a65f673 100644
--- a/rustls/src/crypto/aws_lc_rs/ticketer.rs
+++ b/rustls/src/crypto/aws_lc_rs/ticketer.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt;
 use core::fmt::{Debug, Formatter};
@@ -19,6 +18,7 @@ use crate::log::debug;
 use crate::polyfill::try_split_at;
 use crate::rand::GetRandomFailed;
 use crate::server::ProducesTickets;
+use crate::sync::Arc;
 
 /// A concrete, safe ticket creation mechanism.
 pub struct Ticketer {}
diff --git a/rustls/src/crypto/mod.rs b/rustls/src/crypto/mod.rs
index c0b83995bda..6a7db7a4009 100644
--- a/rustls/src/crypto/mod.rs
+++ b/rustls/src/crypto/mod.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt::Debug;
 
@@ -8,6 +7,7 @@ use zeroize::Zeroize;
 
 use crate::msgs::ffdhe_groups::FfdheGroup;
 use crate::sign::SigningKey;
+use crate::sync::Arc;
 pub use crate::webpki::{
     verify_tls12_signature, verify_tls13_signature, verify_tls13_signature_with_raw_key,
     WebPkiSupportedAlgorithms,
@@ -695,7 +695,6 @@ pub fn default_fips_provider() -> CryptoProvider {
 mod static_default {
     #[cfg(not(feature = "std"))]
     use alloc::boxed::Box;
-    use alloc::sync::Arc;
     #[cfg(feature = "std")]
     use std::sync::OnceLock;
 
@@ -703,6 +702,7 @@ mod static_default {
     use once_cell::race::OnceBox;
 
     use super::CryptoProvider;
+    use crate::sync::Arc;
 
     #[cfg(feature = "std")]
     pub(crate) fn install_default(
diff --git a/rustls/src/crypto/ring/mod.rs b/rustls/src/crypto/ring/mod.rs
index 84b7c945b86..5ddc87e20ac 100644
--- a/rustls/src/crypto/ring/mod.rs
+++ b/rustls/src/crypto/ring/mod.rs
@@ -1,5 +1,3 @@
-use alloc::sync::Arc;
-
 use pki_types::PrivateKeyDer;
 pub(crate) use ring as ring_like;
 use webpki::ring as webpki_algs;
@@ -9,6 +7,7 @@ use crate::enums::SignatureScheme;
 use crate::rand::GetRandomFailed;
 use crate::sign::SigningKey;
 use crate::suites::SupportedCipherSuite;
+use crate::sync::Arc;
 use crate::webpki::WebPkiSupportedAlgorithms;
 use crate::Error;
 
diff --git a/rustls/src/crypto/ring/sign.rs b/rustls/src/crypto/ring/sign.rs
index 0ddfe2d41c2..63496766a48 100644
--- a/rustls/src/crypto/ring/sign.rs
+++ b/rustls/src/crypto/ring/sign.rs
@@ -2,7 +2,6 @@
 
 use alloc::boxed::Box;
 use alloc::string::ToString;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use alloc::{format, vec};
 use core::fmt::{self, Debug, Formatter};
@@ -15,6 +14,7 @@ use super::ring_like::signature::{self, EcdsaKeyPair, Ed25519KeyPair, KeyPair, R
 use crate::crypto::signer::{public_key_to_spki, Signer, SigningKey};
 use crate::enums::{SignatureAlgorithm, SignatureScheme};
 use crate::error::Error;
+use crate::sync::Arc;
 use crate::x509::{wrap_concat_in_sequence, wrap_in_octet_string};
 
 /// Parse `der` as any supported key encoding/type, returning
diff --git a/rustls/src/crypto/ring/ticketer.rs b/rustls/src/crypto/ring/ticketer.rs
index 556293cad34..95793f6223d 100644
--- a/rustls/src/crypto/ring/ticketer.rs
+++ b/rustls/src/crypto/ring/ticketer.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt;
 use core::fmt::{Debug, Formatter};
@@ -15,6 +14,7 @@ use crate::log::debug;
 use crate::polyfill::try_split_at;
 use crate::rand::GetRandomFailed;
 use crate::server::ProducesTickets;
+use crate::sync::Arc;
 
 /// A concrete, safe ticket creation mechanism.
 pub struct Ticketer {}
diff --git a/rustls/src/crypto/signer.rs b/rustls/src/crypto/signer.rs
index 1ee932d8c40..9f4edbb2546 100644
--- a/rustls/src/crypto/signer.rs
+++ b/rustls/src/crypto/signer.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt::Debug;
 
@@ -8,6 +7,7 @@ use pki_types::{AlgorithmIdentifier, CertificateDer, SubjectPublicKeyInfoDer};
 use crate::enums::{SignatureAlgorithm, SignatureScheme};
 use crate::error::{Error, InconsistentKeys};
 use crate::server::ParsedCertificate;
+use crate::sync::Arc;
 use crate::x509;
 
 /// An abstract signing key.
diff --git a/rustls/src/error.rs b/rustls/src/error.rs
index d7dc6549f43..7453880daae 100644
--- a/rustls/src/error.rs
+++ b/rustls/src/error.rs
@@ -621,13 +621,13 @@ impl From<rand::GetRandomFailed> for Error {
 }
 
 mod other_error {
-    #[cfg(feature = "std")]
-    use alloc::sync::Arc;
     use core::fmt;
     #[cfg(feature = "std")]
     use std::error::Error as StdError;
 
     use super::Error;
+    #[cfg(feature = "std")]
+    use crate::sync::Arc;
 
     /// Any other error that cannot be expressed by a more specific [`Error`] variant.
     ///
@@ -679,6 +679,8 @@ mod tests {
     use std::{println, vec};
 
     use super::{CertRevocationListError, Error, InconsistentKeys, InvalidMessage, OtherError};
+    #[cfg(feature = "std")]
+    use crate::sync::Arc;
 
     #[test]
     fn certificate_error_equality() {
@@ -698,7 +700,7 @@ mod tests {
         );
         let other = Other(OtherError(
             #[cfg(feature = "std")]
-            alloc::sync::Arc::from(Box::from("")),
+            Arc::from(Box::from("")),
         ));
         assert_ne!(other, other);
         assert_ne!(BadEncoding, Expired);
@@ -722,7 +724,7 @@ mod tests {
         assert_eq!(UnsupportedRevocationReason, UnsupportedRevocationReason);
         let other = Other(OtherError(
             #[cfg(feature = "std")]
-            alloc::sync::Arc::from(Box::from("")),
+            Arc::from(Box::from("")),
         ));
         assert_ne!(other, other);
         assert_ne!(BadSignature, InvalidCrlNumber);
@@ -731,7 +733,7 @@ mod tests {
     #[test]
     #[cfg(feature = "std")]
     fn other_error_equality() {
-        let other_error = OtherError(alloc::sync::Arc::from(Box::from("")));
+        let other_error = OtherError(Arc::from(Box::from("")));
         assert_ne!(other_error, other_error);
         let other: Error = other_error.into();
         assert_ne!(other, other);
@@ -769,7 +771,7 @@ mod tests {
             Error::InvalidCertRevocationList(CertRevocationListError::BadSignature),
             Error::Other(OtherError(
                 #[cfg(feature = "std")]
-                alloc::sync::Arc::from(Box::from("")),
+                Arc::from(Box::from("")),
             )),
         ];
 
diff --git a/rustls/src/lib.rs b/rustls/src/lib.rs
index d8562932ba3..a3b77623bab 100644
--- a/rustls/src/lib.rs
+++ b/rustls/src/lib.rs
@@ -401,6 +401,14 @@ mod log {
 #[macro_use]
 mod test_macros;
 
+/// This internal `sync` module aliases the `Arc` implementation to allow downstream forks
+/// of rustls targetting architectures without atomic pointers to replace the implementation
+/// with another implementation such as `portable_atomic_util::Arc` in one central location.
+mod sync {
+    #[allow(clippy::disallowed_types)]
+    pub(crate) type Arc<T> = alloc::sync::Arc<T>;
+}
+
 #[macro_use]
 mod msgs;
 mod common_state;
diff --git a/rustls/src/lock.rs b/rustls/src/lock.rs
index 4a261b2eb75..b632b2c54b5 100644
--- a/rustls/src/lock.rs
+++ b/rustls/src/lock.rs
@@ -35,10 +35,11 @@ mod std_lock {
 #[cfg(not(feature = "std"))]
 mod no_std_lock {
     use alloc::boxed::Box;
-    use alloc::sync::Arc;
     use core::fmt::Debug;
     use core::ops::DerefMut;
 
+    use crate::sync::Arc;
+
     /// A no-std compatible wrapper around [`Lock`].
     #[derive(Debug)]
     pub struct Mutex<T> {
diff --git a/rustls/src/msgs/handshake.rs b/rustls/src/msgs/handshake.rs
index 38e211016ec..101f73d1c61 100644
--- a/rustls/src/msgs/handshake.rs
+++ b/rustls/src/msgs/handshake.rs
@@ -1,7 +1,6 @@
 use alloc::collections::BTreeSet;
 #[cfg(feature = "logging")]
 use alloc::string::String;
-use alloc::sync::Arc;
 use alloc::vec;
 use alloc::vec::Vec;
 use core::ops::Deref;
@@ -28,6 +27,7 @@ use crate::msgs::enums::{
     NamedGroup, PSKKeyExchangeMode, ServerNameType,
 };
 use crate::rand;
+use crate::sync::Arc;
 use crate::verify::DigitallySignedStruct;
 use crate::x509::wrap_in_sequence;
 
diff --git a/rustls/src/msgs/persist.rs b/rustls/src/msgs/persist.rs
index 33e7b66f9cc..1867e021eab 100644
--- a/rustls/src/msgs/persist.rs
+++ b/rustls/src/msgs/persist.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::cmp;
 
@@ -12,6 +11,7 @@ use crate::msgs::codec::{Codec, Reader};
 use crate::msgs::handshake::CertificateChain;
 #[cfg(feature = "tls12")]
 use crate::msgs::handshake::SessionId;
+use crate::sync::Arc;
 #[cfg(feature = "tls12")]
 use crate::tls12::Tls12CipherSuite;
 use crate::tls13::Tls13CipherSuite;
diff --git a/rustls/src/quic.rs b/rustls/src/quic.rs
index adfe168669f..ab2c28bd410 100644
--- a/rustls/src/quic.rs
+++ b/rustls/src/quic.rs
@@ -17,7 +17,6 @@ use crate::tls13::Tls13CipherSuite;
 
 #[cfg(feature = "std")]
 mod connection {
-    use alloc::sync::Arc;
     use alloc::vec;
     use alloc::vec::Vec;
     use core::fmt::{self, Debug};
@@ -35,6 +34,7 @@ mod connection {
     use crate::msgs::handshake::{ClientExtension, ServerExtension};
     use crate::msgs::message::InboundPlainMessage;
     use crate::server::{ServerConfig, ServerConnectionData};
+    use crate::sync::Arc;
     use crate::vecbuf::ChunkVecBuffer;
 
     /// A QUIC client or server connection.
diff --git a/rustls/src/server/builder.rs b/rustls/src/server/builder.rs
index 196dd3fcd06..fb15e807e7b 100644
--- a/rustls/src/server/builder.rs
+++ b/rustls/src/server/builder.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::marker::PhantomData;
 
@@ -8,6 +7,7 @@ use crate::builder::{ConfigBuilder, WantsVerifier};
 use crate::error::Error;
 use crate::server::{handy, ResolvesServerCert, ServerConfig};
 use crate::sign::CertifiedKey;
+use crate::sync::Arc;
 use crate::verify::{ClientCertVerifier, NoClientAuth};
 use crate::{compress, versions, InconsistentKeys, NoKeyLog};
 
diff --git a/rustls/src/server/handy.rs b/rustls/src/server/handy.rs
index ba2570abfdd..be26b06537a 100644
--- a/rustls/src/server/handy.rs
+++ b/rustls/src/server/handy.rs
@@ -1,8 +1,8 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt::Debug;
 
 use crate::server::ClientHello;
+use crate::sync::Arc;
 use crate::{server, sign};
 
 /// Something which never stores sessions.
@@ -26,11 +26,11 @@ impl server::StoresServerSessions for NoServerSessionStorage {
 
 #[cfg(any(feature = "std", feature = "hashbrown"))]
 mod cache {
-    use alloc::sync::Arc;
     use alloc::vec::Vec;
     use core::fmt::{Debug, Formatter};
 
     use crate::lock::Mutex;
+    use crate::sync::Arc;
     use crate::{limited_cache, server};
 
     /// An implementer of `StoresServerSessions` that stores everything
@@ -226,7 +226,6 @@ impl server::ResolvesServerCert for AlwaysResolvesServerRawPublicKeys {
 #[cfg(any(feature = "std", feature = "hashbrown"))]
 mod sni_resolver {
     use alloc::string::{String, ToString};
-    use alloc::sync::Arc;
     use core::fmt::Debug;
 
     use pki_types::{DnsName, ServerName};
@@ -234,6 +233,7 @@ mod sni_resolver {
     use crate::error::Error;
     use crate::hash_map::HashMap;
     use crate::server::ClientHello;
+    use crate::sync::Arc;
     use crate::webpki::{verify_server_name, ParsedCertificate};
     use crate::{server, sign};
 
diff --git a/rustls/src/server/hs.rs b/rustls/src/server/hs.rs
index 2d2a45cc575..b50f00f3e44 100644
--- a/rustls/src/server/hs.rs
+++ b/rustls/src/server/hs.rs
@@ -1,6 +1,5 @@
 use alloc::borrow::ToOwned;
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 
 use pki_types::DnsName;
@@ -31,6 +30,7 @@ use crate::msgs::message::{Message, MessagePayload};
 use crate::msgs::persist;
 use crate::server::common::ActiveCertifiedKey;
 use crate::server::{tls13, ClientHello, ServerConfig};
+use crate::sync::Arc;
 use crate::{suites, SupportedCipherSuite};
 
 pub(super) type NextState<'a> = Box<dyn State<ServerConnectionData> + 'a>;
diff --git a/rustls/src/server/server_conn.rs b/rustls/src/server/server_conn.rs
index ad46cdf28f2..bb790da83fc 100644
--- a/rustls/src/server/server_conn.rs
+++ b/rustls/src/server/server_conn.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt;
 use core::fmt::{Debug, Formatter};
@@ -26,6 +25,7 @@ use crate::msgs::base::Payload;
 use crate::msgs::enums::CertificateType;
 use crate::msgs::handshake::{ClientHelloPayload, ProtocolName, ServerExtension};
 use crate::msgs::message::Message;
+use crate::sync::Arc;
 #[cfg(feature = "std")]
 use crate::time_provider::DefaultTimeProvider;
 use crate::time_provider::TimeProvider;
@@ -528,7 +528,6 @@ impl ServerConfig {
 #[cfg(feature = "std")]
 mod connection {
     use alloc::boxed::Box;
-    use alloc::sync::Arc;
     use alloc::vec::Vec;
     use core::fmt;
     use core::fmt::{Debug, Formatter};
@@ -541,6 +540,7 @@ mod connection {
     use crate::error::Error;
     use crate::server::hs;
     use crate::suites::ExtractedSecrets;
+    use crate::sync::Arc;
     use crate::vecbuf::ChunkVecBuffer;
 
     /// Allows reading of early data in resumed TLS1.3 connections.
diff --git a/rustls/src/server/tls12.rs b/rustls/src/server/tls12.rs
index 3313216998c..12b8d4da780 100644
--- a/rustls/src/server/tls12.rs
+++ b/rustls/src/server/tls12.rs
@@ -1,6 +1,5 @@
 use alloc::boxed::Box;
 use alloc::string::ToString;
-use alloc::sync::Arc;
 use alloc::vec;
 use alloc::vec::Vec;
 
@@ -29,6 +28,7 @@ use crate::msgs::handshake::{
 use crate::msgs::message::{Message, MessagePayload};
 use crate::msgs::persist;
 use crate::suites::PartiallyExtractedSecrets;
+use crate::sync::Arc;
 use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite};
 use crate::verify;
 
diff --git a/rustls/src/server/tls13.rs b/rustls/src/server/tls13.rs
index e90de2fba3a..8dde9260e76 100644
--- a/rustls/src/server/tls13.rs
+++ b/rustls/src/server/tls13.rs
@@ -1,5 +1,4 @@
 use alloc::boxed::Box;
-use alloc::sync::Arc;
 use alloc::vec;
 use alloc::vec::Vec;
 
@@ -28,6 +27,7 @@ use crate::msgs::message::{Message, MessagePayload};
 use crate::msgs::persist;
 use crate::server::ServerConfig;
 use crate::suites::PartiallyExtractedSecrets;
+use crate::sync::Arc;
 use crate::tls13::key_schedule::{
     KeyScheduleTraffic, KeyScheduleTrafficWithClientFinishedPending, ResumptionSecret,
 };
diff --git a/rustls/src/webpki/client_verifier.rs b/rustls/src/webpki/client_verifier.rs
index bbe9db36be0..90b6f325f2e 100644
--- a/rustls/src/webpki/client_verifier.rs
+++ b/rustls/src/webpki/client_verifier.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 
 use pki_types::{CertificateDer, CertificateRevocationListDer, UnixTime};
@@ -10,6 +9,7 @@ use crate::crypto;
 use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms};
 #[cfg(doc)]
 use crate::server::ServerConfig;
+use crate::sync::Arc;
 use crate::verify::{
     ClientCertVerified, ClientCertVerifier, DigitallySignedStruct, HandshakeSignatureValid,
     NoClientAuth,
@@ -432,7 +432,6 @@ pub(crate) enum AnonymousClientPolicy {
 #[macro_rules_attribute::apply(test_for_each_provider)]
 mod tests {
     use std::prelude::v1::*;
-    use std::sync::Arc;
     use std::{format, println, vec};
 
     use pki_types::pem::PemObject;
@@ -440,6 +439,7 @@ mod tests {
 
     use super::{provider, WebPkiClientVerifier};
     use crate::server::VerifierBuilderError;
+    use crate::sync::Arc;
     use crate::RootCertStore;
 
     fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> {
diff --git a/rustls/src/webpki/mod.rs b/rustls/src/webpki/mod.rs
index 3b890fa8a3a..77c83751858 100644
--- a/rustls/src/webpki/mod.rs
+++ b/rustls/src/webpki/mod.rs
@@ -1,5 +1,3 @@
-#[cfg(feature = "std")]
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::fmt;
 
@@ -7,6 +5,8 @@ use pki_types::CertificateRevocationListDer;
 use webpki::{CertRevocationList, OwnedCertRevocationList};
 
 use crate::error::{CertRevocationListError, CertificateError, Error, OtherError};
+#[cfg(feature = "std")]
+use crate::sync::Arc;
 
 mod anchors;
 mod client_verifier;
diff --git a/rustls/src/webpki/server_verifier.rs b/rustls/src/webpki/server_verifier.rs
index 40ccfcd371f..50a56fd4081 100644
--- a/rustls/src/webpki/server_verifier.rs
+++ b/rustls/src/webpki/server_verifier.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use alloc::vec::Vec;
 
 use pki_types::{CertificateDer, CertificateRevocationListDer, ServerName, UnixTime};
@@ -6,6 +5,7 @@ use webpki::{CertRevocationList, ExpirationPolicy, RevocationCheckDepth, Unknown
 
 use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms};
 use crate::log::trace;
+use crate::sync::Arc;
 use crate::verify::{
     DigitallySignedStruct, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
 };
@@ -304,13 +304,13 @@ impl ServerCertVerifier for WebPkiServerVerifier {
 #[macro_rules_attribute::apply(test_for_each_provider)]
 mod tests {
     use std::prelude::v1::*;
-    use std::sync::Arc;
     use std::{println, vec};
 
     use pki_types::pem::PemObject;
     use pki_types::{CertificateDer, CertificateRevocationListDer};
 
     use super::{provider, VerifierBuilderError, WebPkiServerVerifier};
+    use crate::sync::Arc;
     use crate::RootCertStore;
 
     fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> {


Test patch:
diff --git a/rustls/src/msgs/handshake_test.rs b/rustls/src/msgs/handshake_test.rs
index c6b2861eb5f..dc77e7f6020 100644
--- a/rustls/src/msgs/handshake_test.rs
+++ b/rustls/src/msgs/handshake_test.rs
@@ -1,4 +1,3 @@
-use alloc::sync::Arc;
 use std::prelude::v1::*;
 use std::{format, println, vec};
 
@@ -26,6 +25,7 @@ use crate::enums::{
     CertificateCompressionAlgorithm, CipherSuite, HandshakeType, ProtocolVersion, SignatureScheme,
 };
 use crate::error::InvalidMessage;
+use crate::sync::Arc;
 use crate::verify::DigitallySignedStruct;
 
 #[test]
diff --git a/rustls/tests/api.rs b/rustls/tests/api.rs
index 48d7da9106a..e9adaae5794 100644
--- a/rustls/tests/api.rs
+++ b/rustls/tests/api.rs
@@ -6,10 +6,11 @@ use std::fmt::Debug;
 use std::io::{self, IoSlice, Read, Write};
 use std::ops::{Deref, DerefMut};
 use std::sync::atomic::{AtomicUsize, Ordering};
-use std::sync::{Arc, Mutex};
+use std::sync::Mutex;
 use std::{fmt, mem};
 
 use pki_types::{CertificateDer, IpAddr, ServerName, UnixTime};
+
 use rustls::client::{verify_server_cert_signed_by_trust_anchor, ResolvesClientCert, Resumption};
 use rustls::crypto::{ActiveKeyExchange, CryptoProvider, SharedSecret, SupportedKxGroup};
 use rustls::internal::msgs::base::Payload;
diff --git a/rustls/tests/client_cert_verifier.rs b/rustls/tests/client_cert_verifier.rs
index 5f001a64331..9069680f667 100644
--- a/rustls/tests/client_cert_verifier.rs
+++ b/rustls/tests/client_cert_verifier.rs
@@ -5,13 +5,13 @@
 use super::*;
 
 mod common;
-use std::sync::Arc;
 
 use common::{
     do_handshake_until_both_error, do_handshake_until_error, make_client_config_with_versions,
     make_client_config_with_versions_with_auth, make_pair_for_arc_configs, server_config_builder,
-    server_name, ErrorFromPeer, KeyType, MockClientVerifier, ALL_KEY_TYPES,
+    server_name, Arc, ErrorFromPeer, KeyType, MockClientVerifier, ALL_KEY_TYPES,
 };
+
 use rustls::server::danger::ClientCertVerified;
 use rustls::{
     AlertDescription, ClientConnection, Error, InvalidMessage, ServerConfig, ServerConnection,
diff --git a/rustls/tests/common/mod.rs b/rustls/tests/common/mod.rs
index 21cf4e53524..a66812d19d7 100644
--- a/rustls/tests/common/mod.rs
+++ b/rustls/tests/common/mod.rs
@@ -3,13 +3,14 @@
 
 use std::io;
 use std::ops::DerefMut;
-use std::sync::{Arc, OnceLock};
+use std::sync::OnceLock;
 
 use pki_types::pem::PemObject;
 use pki_types::{
     CertificateDer, CertificateRevocationListDer, PrivateKeyDer, PrivatePkcs8KeyDer, ServerName,
     SubjectPublicKeyInfoDer, UnixTime,
 };
+
 use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
 use rustls::client::{
     AlwaysResolvesClientRawPublicKeys, ServerCertVerifierBuilder, WebPkiServerVerifier,
@@ -28,10 +29,14 @@ use rustls::{
     DigitallySignedStruct, DistinguishedName, Error, InconsistentKeys, NamedGroup, ProtocolVersion,
     RootCertStore, ServerConfig, ServerConnection, SideData, SignatureScheme, SupportedCipherSuite,
 };
+
 use webpki::anchor_from_trusted_cert;
 
 use super::provider;
 
+// Import `Arc` here for tests - can be overwritten to test with another `Arc` such as `portable_atomic_util::Arc`
+pub use std::sync::Arc;
+
 macro_rules! embed_files {
     (
         $(
diff --git a/rustls/tests/key_log_file_env.rs b/rustls/tests/key_log_file_env.rs
index 1d00f0b2aa4..81f517c5143 100644
--- a/rustls/tests/key_log_file_env.rs
+++ b/rustls/tests/key_log_file_env.rs
@@ -25,14 +25,13 @@
 
 use std::env;
 use std::io::Write;
-use std::sync::Arc;
 
 use super::*;
 
 mod common;
 use common::{
     do_handshake, make_client_config_with_versions, make_pair_for_arc_configs, make_server_config,
-    transfer, KeyType,
+    transfer, Arc, KeyType,
 };
 
 #[test]
diff --git a/rustls/tests/server_cert_verifier.rs b/rustls/tests/server_cert_verifier.rs
index 8b5b03a9783..6a3ecad7042 100644
--- a/rustls/tests/server_cert_verifier.rs
+++ b/rustls/tests/server_cert_verifier.rs
@@ -5,15 +5,16 @@
 use super::*;
 
 mod common;
-use std::sync::Arc;
 
 use common::{
     client_config_builder, client_config_builder_with_versions, do_handshake,
     do_handshake_until_both_error, do_handshake_until_error, make_client_config_with_versions,
     make_pair_for_arc_configs, make_server_config, server_config_builder, transfer_altered,
-    Altered, ErrorFromPeer, KeyType, MockServerVerifier, ALL_KEY_TYPES,
+    Altered, Arc, ErrorFromPeer, KeyType, MockServerVerifier, ALL_KEY_TYPES,
 };
+
 use pki_types::{CertificateDer, ServerName};
+
 use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
 use rustls::client::WebPkiServerVerifier;
 use rustls::internal::msgs::handshake::{ClientExtension, HandshakePayload};
@@ -25,6 +26,7 @@ use rustls::{
     AlertDescription, CertificateError, DigitallySignedStruct, DistinguishedName, Error,
     InvalidMessage, RootCertStore,
 };
+
 use x509_parser::prelude::FromDer;
 use x509_parser::x509::X509Name;
 
diff --git a/rustls/tests/unbuffered.rs b/rustls/tests/unbuffered.rs
index 318dc97bb08..e979940ee98 100644
--- a/rustls/tests/unbuffered.rs
+++ b/rustls/tests/unbuffered.rs
@@ -1,7 +1,6 @@
 #![allow(clippy::duplicate_mod)]
 
 use std::num::NonZeroUsize;
-use std::sync::Arc;
 
 use rustls::client::{ClientConnectionData, EarlyDataError, UnbufferedClientConnection};
 use rustls::server::{ServerConnectionData, UnbufferedServerConnection};