Repository navigation
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The verifier’s security-critical key import and rejection assumptions require validation on supported Apple runtimes, but this review environment could not run the new XCTest suite.
No open issues 🎉
What changed in this PR
Adds a standalone CodePushCore Swift package for verifying CodePush release JWT signatures with Apple’s Security framework, independently of React Native.
Changes:
- Adds RS256 signature verification, RSA public-key parsing, and descriptive verification errors.
- Adds tests for valid signatures, supported key formats, tampered tokens, and invalid inputs.
- Integrates core tests into the iOS unit-test command and ignores Swift Package Manager artifacts.
| File | Description |
|---|---|
package.json |
Runs existing iOS tests and the new core test suite. |
ios/CodePushCore/Tests/CodePushCoreTests/JWTVerifierTests.swift |
Tests signature verification and rejection of invalid tokens and keys. |
ios/CodePushCore/Sources/CodePushCore/SignatureVerification/RSAPublicKey.swift |
Imports PEM or bare-base64 RSA public keys. |
ios/CodePushCore/Sources/CodePushCore/SignatureVerification/JWTVerifier.swift |
Verifies RS256 signatures and returns decoded payloads through an Objective-C-compatible API. |
ios/CodePushCore/Sources/CodePushCore/SignatureVerification/JWTVerificationError.swift |
Defines verification errors and their descriptions. |
ios/CodePushCore/Package.swift |
Declares the standalone library and test target. |
.gitignore |
Excludes Swift Package Manager build and workspace artifacts. |
Review effort: Balanced
ofalvai
force-pushed
the
codepushcore-jwt-swift
branch
from
October 27, 2026 20:56
4ca42a2 to
b6628b2
Compare
This was referenced Oct 28, 2026
ofalvai
marked this pull request as ready for review
October 28, 2026 10:22
gsanta
approved these changes
Oct 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Part of the work enabling Swift Package Manager distribution (community RFC)
The iOS SDK verifies code-signed updates with the
JWT(~> 3.0.0-beta.12) andBase64(~> 1.1) pods. These two pods block SPM support (JWTis only packaged as a Pod, noPackage.swift), and a security library pinned to3.0.0-beta.12from 2019 is a scary situation (the library is abandoned anyway, last release is from 2021).Base64was only there becauseJWT.podspecdepends on it, no CodePush source used it.The stack
Package.swiftfor React Native SPM apps.What this PR adds
ios/CodePushCore/is a Swift package with the standard SPM layout. It imports onlyFoundationandSecurity, so it's unit testable directly, there is no dependency on React Native.Most of our
JWTpod usage can be replaced with calls into theSecurityframework'sSecKeyCreateWithData()andSecKeyVerifySignature()(check code comments for more details). We need to add a little "hand-rolled" code to parse the public key and the JWT token format, but these are ~100 lines total. Needless to say, I ran this PR through many rounds of LLM-assisted security reviews.Decisions
Why not a third-party JWT library
A candidate had to be on CocoaPods trunk and support SPM. State in October 2026:
SwiftASN1pod_CryptoExtras.JOSESwift does not remove the part that matters. Its verifier takes a
SecKey, so we would still callSecKeyCreateWithDataourselves. It would replace about 80 lines (split, base64url decode, pinalg, call verify) with a dependency plus an adapter. The crypto call is the same in both cases: oneSecKeyVerifySignaturecall into Apple's corecrypto.For comparison, Android uses
com.nimbusds:nimbus-jose-jwt. JVM has a good library with no modularity problem. CocoaPods has no equivalent.What input does an attacker control?
components(separatedBy:),Data(base64Encoded:),JSONSerialization). Our own logic on this path is about 20 lines: the RS256 pin, and the order (signature before payload). The tests cover the two attacks that matter,alg: noneand HS256 with the public key as the secret.CodePushPublicKeyin Info.plist.CodePushConfig.mhas no setter for it on purpose. A malformed key fails closed. An attacker who can edit Info.plist already controls the app.Is
SecKeyCreateWithDatasafe to rely on down to iOS 15.5?SecRSAPublicKeyInitis the same from Security-59306 (iOS 13) to Security-61901 (iOS 27). It hands the bytes to corecrypto'sccrsa_import_pub.Why
ios/CodePushCore/and not Swift files inios/CodePush/SwiftPM rejects a target that mixes Swift and C-family sources. #97 builds
ios/CodePush/as an Objective-C target, so Swift must live in its own target. The podspec globs both directories, so CocoaPods consumers get one pod as before. Future Swift that needs React or Objective-C types needs a new Swift-only target that depends onReactHeaders.🤖 Generated with Claude Code