Skip to content

Commit 74d86b3

Browse files
authored
Support s2n-tls on macOS (#990)
1 parent 17109e7 commit 74d86b3

7 files changed

Lines changed: 126 additions & 6 deletions

File tree

.github/workflows/ci.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,46 @@ jobs:
238238
./builder build -p ${{ env.PACKAGE_NAME }} --spec=downstream
239239
python3 codebuild/macos_compatibility_check.py
240240
241+
macos-s2n:
242+
runs-on: macos-15 #latest
243+
env:
244+
AWS_CRT_USE_NON_FIPS_TLS_13: 1
245+
steps:
246+
- uses: aws-actions/configure-aws-credentials@v4
247+
with:
248+
role-to-assume: ${{ env.CRT_CI_ROLE }}
249+
aws-region: ${{ env.AWS_DEFAULT_REGION }}
250+
- name: Checkout Sources
251+
uses: actions/checkout@v4
252+
with:
253+
submodules: true
254+
- name: Build ${{ env.PACKAGE_NAME }} + consumers
255+
run: |
256+
python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')"
257+
chmod a+x builder
258+
./builder build -p ${{ env.PACKAGE_NAME }} --spec=downstream
259+
python3 codebuild/macos_compatibility_check.py
260+
261+
macos-x64-s2n:
262+
runs-on: macos-15-large #latest
263+
env:
264+
AWS_CRT_USE_NON_FIPS_TLS_13: 1
265+
steps:
266+
- uses: aws-actions/configure-aws-credentials@v4
267+
with:
268+
role-to-assume: ${{ env.CRT_CI_ROLE }}
269+
aws-region: ${{ env.AWS_DEFAULT_REGION }}
270+
- name: Checkout Sources
271+
uses: actions/checkout@v4
272+
with:
273+
submodules: true
274+
- name: Build ${{ env.PACKAGE_NAME }} + consumers
275+
run: |
276+
python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')"
277+
chmod a+x builder
278+
./builder build -p ${{ env.PACKAGE_NAME }} --spec=downstream
279+
python3 codebuild/macos_compatibility_check.py
280+
241281
# check that docs can still build
242282
check-docs:
243283
runs-on: ubuntu-22.04 # use same version as docs.yml

CMakeLists.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ if (BUILD_DEPS)
2929
set(IN_SOURCE_BUILD ON)
3030
set(BUILD_TESTING OFF)
3131
add_subdirectory(crt/aws-c-common)
32-
if (UNIX AND NOT APPLE)
32+
# Build s2n-tls and aws-lc on all Unix platforms except non-macOS Apple (iOS, tvOS).
33+
# On macOS (Darwin), both Secure Transport and s2n are built; the TLS backend is selected at runtime.
34+
if (UNIX AND (NOT APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
3335
include(AwsPrebuildDependency)
3436

3537
set(AWSLC_CMAKE_ARGUMENTS
@@ -72,7 +74,18 @@ if (BUILD_DEPS)
7274
)
7375

7476
set(UNSAFE_TREAT_WARNINGS_AS_ERRORS OFF CACHE BOOL "Disable warnings-as-errors when building S2N")
77+
# On Intel Macs, Homebrew installs to /usr/local which is in the default header search path.
78+
# Without this, s2n's libcrypto detection picks up Homebrew's OpenSSL instead of bundled aws-lc.
79+
# ARM Macs use /opt/homebrew (not in default search paths) so they don't need this.
80+
if(APPLE AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
81+
set(_AWS_CRT_PREV_NO_SYSTEM_FROM_IMPORTED ${CMAKE_NO_SYSTEM_FROM_IMPORTED})
82+
set(CMAKE_NO_SYSTEM_FROM_IMPORTED ON)
83+
endif()
7584
add_subdirectory(crt/s2n)
85+
if(APPLE AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
86+
set(CMAKE_NO_SYSTEM_FROM_IMPORTED ${_AWS_CRT_PREV_NO_SYSTEM_FROM_IMPORTED})
87+
unset(_AWS_CRT_PREV_NO_SYSTEM_FROM_IMPORTED)
88+
endif()
7689
endif()
7790
add_subdirectory(crt/aws-c-sdkutils)
7891
add_subdirectory(crt/aws-c-io)

README.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,11 @@ In this way, it reduces the native image size around 30% (142 MB to 101 MB for a
188188

189189
The CRT uses native libraries for TLS, rather than Java's typical
190190
Secure Socket Extension (JSSE), KeyStore, and TrustStore.
191-
On [Windows](https://learn.microsoft.com/en-us/windows/win32/security) and
192-
[Apple](https://developer.apple.com/documentation/security) devices,
193-
the built-in OS libraries are used.
191+
On [Windows](https://learn.microsoft.com/en-us/windows/win32/security),
192+
the built-in OS library (Schannel) is used.
194193
On Linux/Unix/etc [s2n-tls](https://github.com/aws/s2n-tls) is used.
194+
On macOS, the default TLS backend is Apple Secure Transport, but an
195+
alternative backend (s2n-tls) can be selected at runtime (see below).
195196

196197
If you need to add certificates to the trust store, add them to your OS trust store.
197198
The CRT does not use the Java TrustStore. For more customization options, see
@@ -200,7 +201,25 @@ The CRT does not use the Java TrustStore. For more customization options, see
200201

201202
### Mac-Only TLS Behavior
202203

203-
Please note that on Mac, once a private key is used with a certificate, that certificate-key pair is imported into the Mac Keychain. All subsequent uses of that certificate will use the stored private key and ignore anything passed in programmatically. Beginning in v0.6.6, when a stored private key from the Keychain is used, the following will be logged at the "info" log level:
204+
#### `AWS_CRT_USE_NON_FIPS_TLS_13` environment variable
205+
206+
On macOS, both Apple Secure Transport and s2n-tls are compiled into the binary.
207+
The TLS backend is selected at runtime based on this environment variable:
208+
209+
* **Not set (default):** Apple Secure Transport is used.
210+
* **Set (e.g. `AWS_CRT_USE_NON_FIPS_TLS_13=1`):** s2n-tls with aws-lc is used.
211+
212+
This variable has no effect on Linux (always uses s2n-tls) or Windows (always uses Schannel).
213+
214+
| | Secure Transport (default) | s2n-tls (`AWS_CRT_USE_NON_FIPS_TLS_13=1`) |
215+
|---|---|---|
216+
| TLS versions | Up to TLS 1.2 | Up to TLS 1.3 |
217+
| FIPS compliance | Yes | No |
218+
| macOS Keychain integration | Yes (PKCS#12, system certs) | No |
219+
220+
#### Keychain behavior
221+
222+
Please note that on Mac, once a private key is used with a certificate, that certificate-key pair is imported into the Mac Keychain. All subsequent uses of that certificate will use the stored private key and ignore anything passed in programmatically. This applies when using the default Secure Transport backend. Beginning in v0.6.6, when a stored private key from the Keychain is used, the following will be logged at the "info" log level:
204223

205224
```
206225
static: certificate has an existing certificate-key pair that was previously imported into the Keychain. Using key from Keychain instead of the one provided.

crt/aws-c-io

Submodule aws-c-io updated 47 files

src/test/java/software/amazon/awssdk/crt/test/Mqtt5ClientTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,6 +3425,9 @@ public void ConnDC_Cred_UC2() throws Exception {
34253425
Assume.assumeNotNull(
34263426
AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_PKCS12_KEY,
34273427
AWS_TEST_MQTT5_IOT_CORE_PKCS12_KEY_PASSWORD);
3428+
// When set, TLS backend on macOS switches from Secure Transport to s2n-tls, which doesn't support PKCS#12.
3429+
Assume.assumeTrue("Skipped: AWS_CRT_USE_NON_FIPS_TLS_13 is set",
3430+
System.getenv("AWS_CRT_USE_NON_FIPS_TLS_13") == null);
34283431

34293432
TestUtils.doRetryableTest(this::doConnDC_Cred_UC2Test, TestUtils::isRetryableTimeout, MAX_TEST_RETRIES, TEST_RETRY_SLEEP_MILLIS);
34303433

@@ -3647,4 +3650,44 @@ public void ConnWS_Cred_UC4() throws Exception {
36473650

36483651
CrtResource.waitForNoResources();
36493652
}
3653+
3654+
/**
3655+
* ============================================================
3656+
* TLS 1.3 TEST CASES
3657+
* ============================================================
3658+
*/
3659+
3660+
private void doConnDC_TLS13Test() {
3661+
try (TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
3662+
AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
3663+
TlsContext tlsContext = new TlsContext(tlsOptions)) {
3664+
LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3665+
Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_TLS13_HOST, 8883l);
3666+
builder.withLifecycleEvents(events);
3667+
builder.withTlsContext(tlsContext);
3668+
3669+
try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3670+
client.start();
3671+
events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3672+
client.stop();
3673+
}
3674+
} catch (Exception ex) {
3675+
throw new RuntimeException(ex);
3676+
}
3677+
}
3678+
3679+
/* Direct connection to TLS 1.3-only host with mTLS */
3680+
@Test
3681+
public void ConnDC_TLS13() throws Exception {
3682+
skipIfNetworkUnavailable();
3683+
Assume.assumeNotNull(
3684+
AWS_TEST_MQTT5_IOT_CORE_TLS13_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
3685+
// macOS does not support TLS 1.3 unless AWS_CRT_USE_NON_FIPS_TLS_13 is set
3686+
Assume.assumeFalse("Skipped: macOS with Secure Transport does not support TLS 1.3",
3687+
CRT.getOSIdentifier().equals("osx") && System.getenv("AWS_CRT_USE_NON_FIPS_TLS_13") == null);
3688+
3689+
TestUtils.doRetryableTest(this::doConnDC_TLS13Test, TestUtils::isRetryableTimeout, MAX_TEST_RETRIES, TEST_RETRY_SLEEP_MILLIS);
3690+
3691+
CrtResource.waitForNoResources();
3692+
}
36503693
}

src/test/java/software/amazon/awssdk/crt/test/Mqtt5ClientTestFixture.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ public class Mqtt5ClientTestFixture extends CrtTestFixture {
8282
// MQTT5 Windows Cert Store
8383
static final String AWS_TEST_MQTT5_IOT_CORE_WINDOWS_PFX_CERT_NO_PASS = System.getProperty("AWS_TEST_MQTT5_IOT_CORE_WINDOWS_PFX_CERT_NO_PASS");
8484
static final String AWS_TEST_MQTT5_IOT_CORE_WINDOWS_CERT_STORE = System.getProperty("AWS_TEST_MQTT5_IOT_CORE_WINDOWS_CERT_STORE");
85+
// MQTT5 TLS 1.3
86+
static final String AWS_TEST_MQTT5_IOT_CORE_TLS13_HOST = System.getProperty("AWS_TEST_MQTT5_IOT_CORE_TLS13_HOST");
8587

8688
protected int OPERATION_TIMEOUT_TIME = 30;
8789

src/test/java/software/amazon/awssdk/crt/test/MqttClientConnectionMethodTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ public void ConnDC_Cred_UC2() throws Exception {
113113
Assume.assumeNotNull(
114114
AWS_TEST_MQTT311_IOT_CORE_HOST, AWS_TEST_MQTT311_IOT_CORE_PKCS12_KEY,
115115
AWS_TEST_MQTT311_IOT_CORE_PKCS12_KEY_PASSWORD);
116+
// When set, TLS backend on macOS switches from Secure Transport to s2n-tls, which doesn't support PKCS#12.
117+
Assume.assumeTrue("Skipped: AWS_CRT_USE_NON_FIPS_TLS_13 is set",
118+
System.getenv("AWS_CRT_USE_NON_FIPS_TLS_13") == null);
116119

117120
TestUtils.doRetryableTest(this::doConnDC_Cred_UC2Test, TestUtils::isRetryableTimeout, MAX_TEST_RETRIES, TEST_RETRY_SLEEP_MILLIS);
118121

0 commit comments

Comments
 (0)