Search code examples
iosswiftjwtkitura

SwiftJWT crashes iOS App on JWT.init() call


The following code crashes on iPad mini 2 / 3 only when executed from the AppStore distributed executable.

let jwtVerifier = JWTVerifier.es512(publicKey: publicKey.data(using: .utf8)!)
do {
  let parsedJwt = try JWT<LicenseJWTClaims>(jwtString: jwt, verifier: jwtVerifier) // <== crashes here
  return License(jwt: parsedJwt, raw_jwt_string: jwt)
} catch {
}

// LicenseJWTClaims for reference
internal struct LicenseJWTClaims: Claims {
    let exp: Date?
    let nbf: Date?
    let iat: Date?
    let licenseKey: String?
}

The code works just fine on every device when installed via XCode. The App also works on 'normal' (not mini) iPads when installed from the App Store.

How would you go on analysing this issue? Do you maybe even have a fix available?

Find the relevant part of the crash log below:

Thread 0 name:  Dispatch queue: com.apple.avfoundation.metadataoutput.objectqueue
Thread 0 Crashed:
0   libswiftCore.dylib              0x00000001b1b33b00 specialized _fatalErrorMessage+ 2112256 (_:_:file:line:flags:) + 296
1   libswiftCore.dylib              0x00000001b1b33b00 specialized _fatalErrorMessage+ 2112256 (_:_:file:line:flags:) + 296
2   libswiftCore.dylib              0x00000001b1b65300 specialized _NativeDictionary.bridged+ 2315008 () + 288
3   libswiftCore.dylib              0x00000001b19b1f70 _NativeDictionary.bridged+ 532336 () + 20
4   CryptorECC                      0x0000000100564958 specialized ECPublicKey.init(der:) + 51544 (ECPublicKey.swift:144)
5   CryptorECC                      0x0000000100564240 ECPublicKey.__allocating_init(key:) + 49728 (ECPublicKey.swift:93)
6   SwiftJWT                        0x00000001008a36d0 BlueECVerifier.verify(signature:for:) + 30416 (BlueECDSA.swift:99)
7   SwiftJWT                        0x00000001008a34a8 BlueECVerifier.verify(jwt:) + 29864 (BlueECDSA.swift:84)
8   SwiftJWT                        0x00000001008a3884 protocol witness for VerifierAlgorithm.verify(jwt:) in conformance BlueECVerifier + 30852 (<compiler-generated>:0)
9   SwiftJWT                        0x00000001008b3200 JWT.init(jwtString:verifier:) + 94720 (JWT.swift:73)
10  Eliah                           0x00000001004d25e4 LicenseValidator.constructLicense(with:) + 255460 (License.swift:64)
11  Eliah                           0x00000001004d3eb4 LicenseViewController.licenseScanned(_:) + 261812 (LicenseViewController.swift:35)
12  Eliah                           0x00000001004d518c partial apply for implicit closure #2 in implicit closure #1 in LicenseViewController.loadView() + 266636 (<compiler-generated>:0)
13  Eliah                           0x00000001004d6c9c specialized LicenseScanView.metadataOutput(_:didOutput:from:) + 273564 (LicenseScanView.swift:0)
14  Eliah                           0x00000001004d616c @objc LicenseScanView.metadataOutput(_:didOutput:from:) + 270700 (<compiler-generated>:0)
15  AVFoundation                    0x000000018a40ac2c -[AVCaptureMetadataOutput _processSampleBuffer:] + 1284
16  AVFoundation                    0x000000018a40a520 __46-[AVCaptureMetadataOutput _updateRemoteQueue:]_block_invoke + 100
17  CoreMedia                       0x00000001878c9118 __FigRemoteOperationReceiverCreateMessageReceiver_block_invoke + 280
18  CoreMedia                       0x00000001878e6718 __FigRemoteQueueReceiverSetHandler_block_invoke.2 + 224
19  libdispatch.dylib               0x0000000183d9c7d4 _dispatch_client_callout + 16
20  libdispatch.dylib               0x0000000183d4101c _dispatch_continuation_pop$VARIANT$mp + 412
21  libdispatch.dylib               0x0000000183d50fa8 _dispatch_source_invoke$VARIANT$mp + 1308
22  libdispatch.dylib               0x0000000183d451f0 _dispatch_lane_serial_drain$VARIANT$mp + 284
23  libdispatch.dylib               0x0000000183d45e74 _dispatch_lane_invoke$VARIANT$mp + 480
24  libdispatch.dylib               0x0000000183d49eec _dispatch_main_queue_callback_4CF$VARIANT$mp + 784
25  CoreFoundation                  0x00000001842efb20 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
26  CoreFoundation                  0x00000001842eaa58 __CFRunLoopRun + 1924
27  CoreFoundation                  0x00000001842e9fb4 CFRunLoopRunSpecific + 436
28  GraphicsServices                0x00000001864eb79c GSEventRunModal + 104
29  UIKitCore                       0x00000001b07efc38 UIApplicationMain + 212
30  Eliah                           0x0000000100499b88 main + 23432 (AppDelegate.swift:5)
31  libdyld.dylib                   0x0000000183dad8e0 start + 4

Solution

  • CryptorEEC is open source. The last call to the stack that isn't a system framework is ECPublicKey.swift:144.

    As you can see from that link, it's creating a dictionary with this value kSecAttrKeyTypeECSECPrimeRandom. According to the next call in the stack, this is causing the crash.

    I searched for kSecAttrKeyTypeECSECPrimeRandom on Google and I found this question on SO.

    This answer suggests that a key larger than 256 is too big for ECSEC.

    This is an old question with old answers, which leads me to believe it's crashing on older devices with older iOS versions because support for larger keys was introduced in iOS 13 or later, or in devices with Secure Enclave (I'm not sure).

    Since I don't know how you're using this encrypted token, I can't make a suggestion on how to fix this, but I hope it's at least enough information for you to make a decision.