Double-free when parsing RSA public key fails
Summary
When initializing an RSA public key from DER or PEM bytes throws an error, the EVP_PKEY* is double-freed: first in the catch block, then in the deinit. This can lead to a crash on future memory allocations. This double-free manifests when BoringSSL cannot decode the public key from the bytes provided.
PoC
The following tests will reliably trigger an error when run with address sanitizer enabled:
```swift
func test_invalidDERPublicKeyThrowsWithoutDoubleFree() throws {
// SEQUENCE { INTEGER 0, INTEGER 0 }
let badBase64 = "MAYCAQACAQ=="
let badDER = Array(Data(base64Encoded: badBase64)!)
XCTAssertThrowsError(try _RSA.Signing.PublicKey(derRepresentation: badDER))
}
func test_invalidPEMPublicKeyThrowsWithoutDoubleFree() throws {
// SEQUENCE { INTEGER 0, INTEGER 0 }
let badPEM = """
-----BEGIN PUBLIC KEY-----
MAYCAQACAQ==
-----END PUBLIC KEY-----
"""
XCTAssertThrowsError(try _RSA.Signing.PublicKey(pemRepresentation: badPEM))
}
`
Impact
Uses of _RSA.Encryption.PublicKey, _RSA.Signing.PublicKey, and _RSA.BlindSigning.PublicKey are affected. Calling these types initializers with a malformed key will trigger a double-free. Applications that parse untrusted RSA keys using these APIs are affected.
Credits
We would like to...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| swift-crypto Product | >= 3.2.0, < 4.5.1 | 4.5.1 |
Details and references
### Summary When initializing an RSA public key from DER or PEM bytes throws an error, the `EVP_PKEY*` is double-freed: first in the catch block, then in the `deinit`. This can lead to a crash on future memory allocations. This double-free manifests when BoringSSL cannot decode the public key from the bytes provided. ### PoC The following tests will reliably trigger an error when run with address sanitizer enabled: ```swift func test_invalidDERPublicKeyThrowsWithoutDoubleFree() throws { // SEQUENCE { INTEGER 0, INTEGER 0 } let badBase64 = "MAYCAQACAQ==" let badDER = Array(Data(base64Encoded: badBase64)!) XCTAssertThrowsError(try _RSA.Signing.PublicKey(derRepresentation: badDER)) } func test_invalidPEMPublicKeyThrowsWithoutDoubleFree() throws { // SEQUENCE { INTEGER 0, INTEGER 0 } let badPEM = """ -----BEGIN PUBLIC KEY----- MAYCAQACAQ== -----END PUBLIC KEY----- """ XCTAssertThrowsError(try _RSA.Signing.PublicKey(pemRepresentation: badPEM)) } ``` ### Impact Uses of `_RSA.Encryption.PublicKey`, `_RSA.Signing.PublicKey`, and `_RSA.BlindSigning.PublicKey` are affected. Calling these types initializers with a malformed key will trigger a double-free. Applications that parse untrusted RSA keys using these APIs are affected. ### Credits We would like to acknowledge Sujal Tuladhar for their assistance.
- Severity from
- GitHub (reviewed advisory)