Skip to content

Commit

Permalink
Add Linux support for PKCS#1 RSA public keys (#135)
Browse files Browse the repository at this point in the history
Motivation

The init(derRepresentation:) and init(pemRepresentation:) constructors
for RSA public keys support both PKCS#8 and PKCS#1 key formats on
Darwin. This support was missing from Linux, with only PKCS#8 support.
This patch brings the two platforms into parity.

Modifications

Add code to try both versions on Linux.
Add tests.

Results

PKCS#1 keys are supported on Linux too!
  • Loading branch information
Lukasa authored Nov 21, 2022
1 parent f652300 commit 71ae6ad
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 11 deletions.
49 changes: 38 additions & 11 deletions Sources/_CryptoExtras/RSA/RSA_boring.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,26 @@ extension BoringSSLRSAPublicKey {
fileprivate init(pemRepresentation: String) throws {
var pemRepresentation = pemRepresentation

self.pointer = try pemRepresentation.withUTF8 { utf8Ptr in
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: utf8Ptr) { bio in
guard let key = CCryptoBoringSSL_PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) else {
throw CryptoKitError.internalBoringSSLError()
// There are two encodings for RSA public keys: PKCS#1 and the SPKI form.
// The SPKI form is what we support for EC keys, so we try that first, then we
// fall back to the PKCS#1 form if that parse fails.
do {
self.pointer = try pemRepresentation.withUTF8 { utf8Ptr in
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: utf8Ptr) { bio in
guard let key = CCryptoBoringSSL_PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) else {
throw CryptoKitError.internalBoringSSLError()
}
return key
}
}
} catch {
self.pointer = try pemRepresentation.withUTF8 { utf8Ptr in
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: utf8Ptr) { bio in
guard let key = CCryptoBoringSSL_PEM_read_bio_RSAPublicKey(bio, nil, nil, nil) else {
throw CryptoKitError.internalBoringSSLError()
}
return key
}

return key
}
}
}
Expand All @@ -127,12 +140,26 @@ extension BoringSSLRSAPublicKey {
}

private init<Bytes: ContiguousBytes>(contiguousDerRepresentation: Bytes) throws {
self.pointer = try contiguousDerRepresentation.withUnsafeBytes { derPtr in
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: derPtr) { bio in
guard let key = CCryptoBoringSSL_d2i_RSA_PUBKEY_bio(bio, nil) else {
throw CryptoKitError.internalBoringSSLError()
// There are two encodings for RSA public keys: PKCS#1 and the SPKI form.
// The SPKI form is what we support for EC keys, so we try that first, then we
// fall back to the PKCS#1 form if that parse fails.
do {
self.pointer = try contiguousDerRepresentation.withUnsafeBytes { derPtr in
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: derPtr) { bio in
guard let key = CCryptoBoringSSL_d2i_RSA_PUBKEY_bio(bio, nil) else {
throw CryptoKitError.internalBoringSSLError()
}
return key
}
}
} catch {
self.pointer = try contiguousDerRepresentation.withUnsafeBytes { derPtr in
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: derPtr) { bio in
guard let key = CCryptoBoringSSL_d2i_RSAPublicKey_bio(bio, nil) else {
throw CryptoKitError.internalBoringSSLError()
}
return key
}
return key
}
}
}
Expand Down
37 changes: 37 additions & 0 deletions Tests/_CryptoExtrasTests/TestRSASigning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,43 @@ final class TestRSASigning: XCTestCase {
XCTAssertThrowsError(try _RSA.Signing.PrivateKey(keySize: .init(bitCount: 1016)))
}

func testParsingPKCS1PublicKeyKeyDER() throws {
let pkcs1Key = Data(base64Encoded:
"MIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNwAHG8U9/E+ioSj0t" +
"/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR62RRr55yzha" +
"CCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onrayzT7" +
"Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt" +
"4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSEN" +
"nTnIqm1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK" +
"8sYxrfV8g/vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0C" +
"zr56ENCHonYhMsT8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0i" +
"TMARgexWO/bTouJbt7IEIlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31B" +
"qVUa/oKMoYX9w0MOiqiwhqkfOKJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3x" +
"aG4Nj/QN370EKIf6MzOi5cHkERgWPOGHFrK+ymircxXDpqR+DDeVnWIBqv8" +
"mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/s1Hap0flhFMCAwEAAQ=="
)!
XCTAssertNoThrow(try _RSA.Signing.PublicKey(derRepresentation: pkcs1Key))
}

func testParsingPKCS1PublicKeyKeyPEM() throws {
let pemKey = """
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNwAHG8U9/E+ioSj0t/EFa9
n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR62RRr55yzhaCCenavcZDX
7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onrayzT7Y+YHBSrfuXjbvzY
qOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt4Q08RWD8MpZRJ7xnw8ou
tmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIqm1y9TBsoilwie7SrmNnu
4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/vOldxJuvRZnio1oktLqp
Vj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT8dm74YlguIwoVqwUHZwK
53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IEIlKVgJNp6I5MZfGRAy1w
dALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfOKJwGRXa/ghgntNWutMtQ
5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPOGHFrK+ymircxXDpqR+DD
eVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/s1Hap0flhFMCAwEAAQ==
-----END RSA PUBLIC KEY-----
"""
XCTAssertNoThrow(try _RSA.Signing.PublicKey(pemRepresentation: pemKey))
}

private func testPKCS1Group(_ group: RSAPKCS1TestGroup) throws {
let derKey = try _RSA.Signing.PublicKey(derRepresentation: group.keyDerBytes)
let pemKey = try _RSA.Signing.PublicKey(pemRepresentation: group.keyPem)
Expand Down

0 comments on commit 71ae6ad

Please sign in to comment.