Skip to content

Commit 71ae6ad

Browse files
authored
Add Linux support for PKCS#1 RSA public keys (#135)
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!
1 parent f652300 commit 71ae6ad

File tree

2 files changed

+75
-11
lines changed

2 files changed

+75
-11
lines changed

Sources/_CryptoExtras/RSA/RSA_boring.swift

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,26 @@ extension BoringSSLRSAPublicKey {
106106
fileprivate init(pemRepresentation: String) throws {
107107
var pemRepresentation = pemRepresentation
108108

109-
self.pointer = try pemRepresentation.withUTF8 { utf8Ptr in
110-
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: utf8Ptr) { bio in
111-
guard let key = CCryptoBoringSSL_PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) else {
112-
throw CryptoKitError.internalBoringSSLError()
109+
// There are two encodings for RSA public keys: PKCS#1 and the SPKI form.
110+
// The SPKI form is what we support for EC keys, so we try that first, then we
111+
// fall back to the PKCS#1 form if that parse fails.
112+
do {
113+
self.pointer = try pemRepresentation.withUTF8 { utf8Ptr in
114+
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: utf8Ptr) { bio in
115+
guard let key = CCryptoBoringSSL_PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) else {
116+
throw CryptoKitError.internalBoringSSLError()
117+
}
118+
return key
119+
}
120+
}
121+
} catch {
122+
self.pointer = try pemRepresentation.withUTF8 { utf8Ptr in
123+
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: utf8Ptr) { bio in
124+
guard let key = CCryptoBoringSSL_PEM_read_bio_RSAPublicKey(bio, nil, nil, nil) else {
125+
throw CryptoKitError.internalBoringSSLError()
126+
}
127+
return key
113128
}
114-
115-
return key
116129
}
117130
}
118131
}
@@ -127,12 +140,26 @@ extension BoringSSLRSAPublicKey {
127140
}
128141

129142
private init<Bytes: ContiguousBytes>(contiguousDerRepresentation: Bytes) throws {
130-
self.pointer = try contiguousDerRepresentation.withUnsafeBytes { derPtr in
131-
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: derPtr) { bio in
132-
guard let key = CCryptoBoringSSL_d2i_RSA_PUBKEY_bio(bio, nil) else {
133-
throw CryptoKitError.internalBoringSSLError()
143+
// There are two encodings for RSA public keys: PKCS#1 and the SPKI form.
144+
// The SPKI form is what we support for EC keys, so we try that first, then we
145+
// fall back to the PKCS#1 form if that parse fails.
146+
do {
147+
self.pointer = try contiguousDerRepresentation.withUnsafeBytes { derPtr in
148+
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: derPtr) { bio in
149+
guard let key = CCryptoBoringSSL_d2i_RSA_PUBKEY_bio(bio, nil) else {
150+
throw CryptoKitError.internalBoringSSLError()
151+
}
152+
return key
153+
}
154+
}
155+
} catch {
156+
self.pointer = try contiguousDerRepresentation.withUnsafeBytes { derPtr in
157+
return try BIOHelper.withReadOnlyMemoryBIO(wrapping: derPtr) { bio in
158+
guard let key = CCryptoBoringSSL_d2i_RSAPublicKey_bio(bio, nil) else {
159+
throw CryptoKitError.internalBoringSSLError()
160+
}
161+
return key
134162
}
135-
return key
136163
}
137164
}
138165
}

Tests/_CryptoExtrasTests/TestRSASigning.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,43 @@ final class TestRSASigning: XCTestCase {
569569
XCTAssertThrowsError(try _RSA.Signing.PrivateKey(keySize: .init(bitCount: 1016)))
570570
}
571571

572+
func testParsingPKCS1PublicKeyKeyDER() throws {
573+
let pkcs1Key = Data(base64Encoded:
574+
"MIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNwAHG8U9/E+ioSj0t" +
575+
"/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR62RRr55yzha" +
576+
"CCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onrayzT7" +
577+
"Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt" +
578+
"4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSEN" +
579+
"nTnIqm1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK" +
580+
"8sYxrfV8g/vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0C" +
581+
"zr56ENCHonYhMsT8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0i" +
582+
"TMARgexWO/bTouJbt7IEIlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31B" +
583+
"qVUa/oKMoYX9w0MOiqiwhqkfOKJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3x" +
584+
"aG4Nj/QN370EKIf6MzOi5cHkERgWPOGHFrK+ymircxXDpqR+DDeVnWIBqv8" +
585+
"mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/s1Hap0flhFMCAwEAAQ=="
586+
)!
587+
XCTAssertNoThrow(try _RSA.Signing.PublicKey(derRepresentation: pkcs1Key))
588+
}
589+
590+
func testParsingPKCS1PublicKeyKeyPEM() throws {
591+
let pemKey = """
592+
-----BEGIN RSA PUBLIC KEY-----
593+
MIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNwAHG8U9/E+ioSj0t/EFa9
594+
n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR62RRr55yzhaCCenavcZDX
595+
7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onrayzT7Y+YHBSrfuXjbvzY
596+
qOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt4Q08RWD8MpZRJ7xnw8ou
597+
tmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIqm1y9TBsoilwie7SrmNnu
598+
4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/vOldxJuvRZnio1oktLqp
599+
Vj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT8dm74YlguIwoVqwUHZwK
600+
53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IEIlKVgJNp6I5MZfGRAy1w
601+
dALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfOKJwGRXa/ghgntNWutMtQ
602+
5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPOGHFrK+ymircxXDpqR+DD
603+
eVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/s1Hap0flhFMCAwEAAQ==
604+
-----END RSA PUBLIC KEY-----
605+
"""
606+
XCTAssertNoThrow(try _RSA.Signing.PublicKey(pemRepresentation: pemKey))
607+
}
608+
572609
private func testPKCS1Group(_ group: RSAPKCS1TestGroup) throws {
573610
let derKey = try _RSA.Signing.PublicKey(derRepresentation: group.keyDerBytes)
574611
let pemKey = try _RSA.Signing.PublicKey(pemRepresentation: group.keyPem)

0 commit comments

Comments
 (0)