github datatheorem/TrustKit 4.0.0-beta.1

pre-release6 hours ago

TrustKit 4.0 is a major release. It raises the minimum OS versions, drops CocoaPods, adds visionOS, logs through os_log, and accepts any domain name or IP address in the pinning configuration. Some of these changes affect which connections get pinned, so test this beta before you ship it. Please report problems in Issues.

Breaking changes

Requirements

  • Minimum OS versions are now iOS 15, macOS 12, Mac Catalyst 15, tvOS 15, watchOS 9 and visionOS 1. They were iOS 12, macOS 10.13, tvOS 12 and watchOS 4.
  • Swift Package Manager needs Xcode 16 or later (swift-tools-version:6.0). So does building from the Xcode project, which now uses the Xcode 16 project format. TrustKit itself is built and tested with Xcode 27.
  • CocoaPods is no longer supported. TrustKit 4.0 and later aren't published to CocoaPods, but 3.x is still available there. Use Swift Package Manager, or the static XCFramework (TrustKit-static.zip) attached to each release.
  • The TrustKit_Static Xcode target is removed. Use TrustKit-static.zip instead.

Removed APIs

  • +[TrustKit setLoggerBlock:] is removed. TrustKit now logs through os_log (see Logging). To act on validation results in code, set pinningValidatorCallback.
  • kTSKPublicKeyAlgorithms, TSKSupportedAlgorithm, kTSKAlgorithmRsa2048, kTSKAlgorithmRsa4096, kTSKAlgorithmEcDsaSecp256r1 and kTSKAlgorithmEcDsaSecp384r1 are removed. They have been deprecated since 1.6.0, so remove them from your code. A configuration or Info.plist that still sets TSKPublicKeyAlgorithms keeps working, because the key is ignored.

macOS-only symbols no longer compile on other platforms

kTSKIgnorePinningForUserDefinedTrustAnchors and TSKTrustEvaluationFailedUserDefinedTrustAnchor are now marked unavailable on iOS, Mac Catalyst, tvOS, watchOS and visionOS. Using them there is a compile error. In code shared across platforms, wrap them in #if TARGET_OS_OSX (Objective-C) or #if os(macOS) (Swift).

Header location

The public headers moved to TrustKit/public/TrustKit/. #import <TrustKit/TrustKit.h> and @import TrustKit; now work the same way with Swift Package Manager and with the framework. If you have header search paths pointing into a TrustKit checkout, update them.

Static XCFramework in apps without Swift

Part of TrustKit is now written in Swift. This is internal only, and the public API hasn't changed. If your app has no Swift code of its own and targets an OS earlier than iOS 16, tvOS 16, Mac Catalyst 16 or macOS 13, linking the XCFramework fails with Undefined symbols … __swift_FORCE_LOAD_$_swiftCompatibility56. To fix it, add an empty Swift file to your app target.

Swift contributions

Starting with 4.0, TrustKit accepts contributions in Swift. This release ships TrustKit's first Swift code. Over time we plan to move the Objective-C classes to Swift that Objective-C can still call, so existing apps keep working unchanged.

  • Put new Swift files in TrustKit/Swift/ and add them to each framework target in TrustKit.xcodeproj.
  • Swift code builds in Swift 6 language mode, with strict concurrency checking. scripts/lint.sh runs swift-format and SwiftLint, and CI fails if lint fails.
  • For now, Swift code is internal only. Swift Package Manager builds it as a separate target, which doesn't support public Swift API yet. Open an issue before you add a public Swift type.

Pinning configuration (#333, #341)

These changes affect which connections are pinned, so review your configuration when you upgrade.

  • Any domain name or IP address can be pinned. This includes internal names such as api.internal or localhost, and IPv4 or IPv6 addresses. 3.x rejected names that didn't end in an entry of its bundled public suffix list. That list is now removed.
  • Keys that can never match now throw an exception at startup. Examples are *.example.com, or any key containing :, /, @ or a space. 3.x loaded these keys, and the domain silently stayed unpinned. Like any other configuration error, this raises an NSException from initSharedInstanceWithConfiguration:. If your app downloads its configuration at runtime, validate it before you pass it to TrustKit.
  • Matching now ignores case and a trailing dot. IPv6 addresses match with or without brackets, and in any notation. In 3.x, a key such as API.example.com never matched, and the host stayed unpinned without any warning. In 4.0 that key matches and the host is pinned.
  • kTSKIncludeSubdomains now uses plain suffix matching. It throws for an IP address or a single-label domain such as com. Otherwise it is allowed on any domain, including public suffixes such as co.uk or appspot.com, which 3.x rejected.

Any key type can be pinned

TrustKit now hashes each certificate's Subject Public Key Info exactly as it is encoded in the certificate. Before, it rebuilt the Subject Public Key Info, and that only worked for a fixed list of key types.

  • Key types that 3.x couldn't handle now work, ECDSA P-521 for example. In 3.x, those certificates failed with TSKTrustEvaluationErrorCouldNotGenerateSpkiHash, and the connection was blocked.
  • Pins for standard RSA 2048, 3072 and 4096 keys and for ECDSA P-256 and P-384 keys are unchanged. If a certificate encodes its key in a non-standard way, its 4.0 pin can differ from its 3.x pin. Regenerate the pin to check.
  • get_pin_from_certificate.sh replaces the Python script. It computes pins the same way TrustKit does, and takes a PEM or DER file: ./get_pin_from_certificate.sh ca.pem. Don't re-encode the key first, for example with openssl pkey. For some certificates that changes the bytes, and the pin won't match.

Logging

TrustKit logs through the unified logging system (#128), under the subsystem com.datatheorem.trustkit and the category TrustKit.

  • Validation failures and other errors are logged at the error level. Successful validations are logged at the info level, and the detail of each step at the debug level.
  • Release builds now log too. 3.x didn't log anything in Release builds. Pinned hostnames are logged as public data, so they appear in device logs.
  • To watch the logs, run log stream --level debug --predicate 'subsystem == "com.datatheorem.trustkit"'. For the simulator, put xcrun simctl spawn booted in front of it.

Pin failure reports

The app-platform field now reports VISIONOS for visionOS apps, MAC_CATALYST for Mac Catalyst apps, and IOS_ON_MAC for iPhone or iPad apps running on a Mac. 3.x reported the last two as IOS. If your report server filters on this field, update it. The other report fields haven't changed.

New platforms

  • visionOS is supported through Swift Package Manager, the Xcode project and the static XCFramework.
  • Mac Catalyst is now officially supported. It is declared in Package.swift, tested in CI and has its own slice in the XCFramework.
  • The static XCFramework now also includes arm64e slices.

Docs and demos

  • In the getting started guide, the UIWebView section is replaced by a WKWebView example in Objective-C and Swift. The example validates off the main thread, and both demo apps include it.
  • The demo apps now use TrustKit as a local Swift package and use the UIScene lifecycle.

For contributors

  • CI runs the unit tests on macOS, Mac Catalyst, and the iOS, tvOS and visionOS simulators. It also runs UI tests for both demo apps. watchOS is turned off for now, until a runner image issue is fixed.
  • scripts/lint.sh runs swift-format, SwiftLint and clang-format, and CI fails when lint fails.
  • OCMock now comes from Swift Package Manager instead of bundled binaries.

What's Changed

Full Changelog: 3.0.8...4.0.0-beta.1

Don't miss a new TrustKit release

NewReleases is sending notifications on new releases.