From dfc4d06c5170e37b84c65f9ef2b34f9ffba9cbfd Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Fri, 14 Nov 2025 11:02:39 +0000 Subject: [PATCH 01/11] Validate non-certificate signatures Motivation: Keys can be used to sign arbitrary data. Validating those signatures is currently not straight forward. Modifications: Introduce an isValidSignature overload that works with any input bytes. Add tests to verify that it works. Results: A new API to validate signatures represented as bytes. --- Sources/X509/CertificatePublicKey.swift | 31 ++++++ Sources/X509/Signature.swift | 114 +++++++++++++++++++++++ Tests/X509Tests/SignatureTests.swift | 119 ++++++++++++++++++++++++ 3 files changed, 264 insertions(+) diff --git a/Sources/X509/CertificatePublicKey.swift b/Sources/X509/CertificatePublicKey.swift index e3b3f408..1b7014d4 100644 --- a/Sources/X509/CertificatePublicKey.swift +++ b/Sources/X509/CertificatePublicKey.swift @@ -156,6 +156,37 @@ extension Certificate.PublicKey { return ed25519.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm) } } + + /// Confirms that `signature` is a valid signature for `bytes`, created by the + /// private key associated with this public key. + /// + /// This function accepts raw signature bytes (such as those from a TLS handshake) + /// and validates them directly against the data. + /// + /// - Parameters: + /// - signature: The raw signature bytes to validate. + /// - bytes: The data that was signed. + /// - signatureAlgorithm: The algorithm used to create the signature. + /// - Returns: Whether the signature was produced by signing `bytes` with the private key corresponding to this public key. + @inlinable + public func isValidSignature( + _ signature: SignatureBytes, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { + switch self.backing { + case .p256(let p256): + return p256.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm) + case .p384(let p384): + return p384.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm) + case .p521(let p521): + return p521.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm) + case .rsa(let rsa): + return rsa.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm) + case .ed25519(let ed25519): + return ed25519.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm) + } + } } @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index 1787597c..f0867279 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -199,6 +199,31 @@ extension P256.Signing.PublicKey { return false } } + + @inlinable + internal func isValidSignature( + _ signature: SignatureBytes, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { + + // Parse the raw signature bytes as DER-encoded ECDSA signature + guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), + let innerSignature = P256.Signing.ECDSASignature(ecdsaSignature) else { + return false + } + + switch signatureAlgorithm { + case .ecdsaWithSHA256: + return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) + case .ecdsaWithSHA384: + return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) + case .ecdsaWithSHA512: + return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) + default: + return false + } + } } @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *) @@ -227,6 +252,30 @@ extension P384.Signing.PublicKey { return false } } + + @inlinable + internal func isValidSignature( + _ signature: SignatureBytes, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { + // Parse the raw signature bytes as DER-encoded ECDSA signature + guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), + let innerSignature = P384.Signing.ECDSASignature(ecdsaSignature) else { + return false + } + + switch signatureAlgorithm { + case .ecdsaWithSHA256: + return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) + case .ecdsaWithSHA384: + return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) + case .ecdsaWithSHA512: + return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) + default: + return false + } + } } @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *) @@ -255,6 +304,30 @@ extension P521.Signing.PublicKey { return false } } + + @inlinable + internal func isValidSignature( + _ signature: SignatureBytes, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { + // Parse the raw signature bytes as DER-encoded ECDSA signature + guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), + let innerSignature = P521.Signing.ECDSASignature(ecdsaSignature) else { + return false + } + + switch signatureAlgorithm { + case .ecdsaWithSHA256: + return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) + case .ecdsaWithSHA384: + return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) + case .ecdsaWithSHA512: + return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) + default: + return false + } + } } @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *) @@ -285,6 +358,32 @@ extension _RSA.Signing.PublicKey { return false } } + + @inlinable + internal func isValidSignature( + _ signature: SignatureBytes, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { + // RSA signatures are already in raw format + let rsaSignature = _RSA.Signing.RSASignature(rawRepresentation: signature) + + // For now we don't support RSA PSS, as it's not deployed in the WebPKI. + let padding = _RSA.Signing.Padding.insecurePKCS1v1_5 + + switch signatureAlgorithm { + case .sha1WithRSAEncryption: + return self.isValidSignature(rsaSignature, for: Insecure.SHA1.hash(data: bytes), padding: padding) + case .sha256WithRSAEncryption: + return self.isValidSignature(rsaSignature, for: SHA256.hash(data: bytes), padding: padding) + case .sha384WithRSAEncryption: + return self.isValidSignature(rsaSignature, for: SHA384.hash(data: bytes), padding: padding) + case .sha512WithRSAEncryption: + return self.isValidSignature(rsaSignature, for: SHA512.hash(data: bytes), padding: padding) + default: + return false + } + } } @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *) @@ -307,6 +406,21 @@ extension Curve25519.Signing.PublicKey { return false } } + + @inlinable + internal func isValidSignature( + _ signature: SignatureBytes, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { + switch signatureAlgorithm { + case .ed25519: + // Ed25519 signatures are already in raw format (64 bytes) + return self.isValidSignature(signature, for: bytes) + default: + return false + } + } } // MARK: Private key operations diff --git a/Tests/X509Tests/SignatureTests.swift b/Tests/X509Tests/SignatureTests.swift index 3660dc91..7346a6e5 100644 --- a/Tests/X509Tests/SignatureTests.swift +++ b/Tests/X509Tests/SignatureTests.swift @@ -31,6 +31,7 @@ final class SignatureTests: XCTestCase { static let p521Key = P521.Signing.PrivateKey() static let rsaKey = try! _RSA.Signing.PrivateKey(keySize: .bits2048) static let ed25519Key = Curve25519.Signing.PrivateKey() + static let dummyData: Data = "the quick brown fox jumps over the lazy dog".data(using: .utf8)! #if canImport(Darwin) static let secureEnclaveP256 = try? SecureEnclave.P256.Signing.PrivateKey() static let secKeyRSA = try? generateSecKey(keyType: kSecAttrKeyTypeRSA, keySize: 2048, useSEP: false) @@ -941,4 +942,122 @@ final class SignatureTests: XCTestCase { 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, ]) } + + func testSignatureValidationRSA() async throws { + let algo = Certificate.SignatureAlgorithm.sha384WithRSAEncryption + let key = Certificate.PrivateKey(Self.rsaKey) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + XCTAssert(pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo)) + } + + func testSignatureValidationECDSA() async throws { + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA384 + + func test(_ key: Certificate.PrivateKey) throws { + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + try test(Certificate.PrivateKey(Self.p256Key)) + try test(Certificate.PrivateKey(Self.p384Key)) + try test(Certificate.PrivateKey(Self.p521Key)) + } + + func testSignatureValidationEdDSA() async throws { + let algo = Certificate.SignatureAlgorithm.ed25519 + let key = Certificate.PrivateKey(Self.ed25519Key) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + #if canImport(Darwin) + func testSignatureValidationSecureEncalve() throws { + guard let secureEnclaveP256 = Self.secureEnclaveP256 else { + throw XCTSkip("No SEP") + } + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA256 + let key = Certificate.PrivateKey(secureEnclaveP256) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + func testSignatureValidationSecKeyRSA() async throws { + guard let secKeyRSA = Self.secKeyRSA else { + throw XCTSkip("Key Error") + } + let algo = Certificate.SignatureAlgorithm.sha384WithRSAEncryption + let key = try Certificate.PrivateKey(secKeyRSA) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + func testSignatureValidationSecKeyEC256() async throws { + guard let secKeyEC256 = Self.secKeyEC256 else { + throw XCTSkip("Key Error") + } + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA256 + let key = try Certificate.PrivateKey(secKeyEC256) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + func testSignatureValidationSecKeyEC2384() async throws { + guard let secKeyEC384 = Self.secKeyEC384 else { + throw XCTSkip("Key Error") + } + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA512 + let key = try Certificate.PrivateKey(secKeyEC384) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + func testSignatureValidationSecKeyEC521() async throws { + guard let secKeyEC521 = Self.secKeyEC521 else { + throw XCTSkip("Key Error") + } + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA256 + let key = try Certificate.PrivateKey(secKeyEC521) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + func testSignatureValidationSecKeyEnclaveEC256() async throws { + guard let secKeyEnclaveEC256 = Self.secKeyEnclaveEC256 else { + throw XCTSkip("Key Error") + } + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA256 + let key = try Certificate.PrivateKey(secKeyEnclaveEC256) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + + func testSignatureValidationSecKeyEnclaveEC384() async throws { + guard let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384 else { + throw XCTSkip("Key Error") + } + let algo = Certificate.SignatureAlgorithm.ecdsaWithSHA384 + let key = try Certificate.PrivateKey(secKeyEnclaveEC384) + let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = key.publicKey + let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + XCTAssert(isValidSignature) + } + #endif } From 22be2be103596ef8e0192fcc3d3bededf8435476 Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Mon, 17 Nov 2025 11:31:03 +0000 Subject: [PATCH 02/11] Deduplication --- Sources/X509/Signature.swift | 134 +++++++++++++++++------------------ 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index f0867279..5486902f 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -181,6 +181,7 @@ extension P256.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { + guard case .ecdsa(let rawInnerSignature) = signature.backing, let innerSignature = P256.Signing.ECDSASignature(rawInnerSignature) else { @@ -188,16 +189,7 @@ extension P256.Signing.PublicKey { return false } - switch signatureAlgorithm { - case .ecdsaWithSHA256: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) - case .ecdsaWithSHA384: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) - case .ecdsaWithSHA512: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) - default: - return false - } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -207,19 +199,29 @@ extension P256.Signing.PublicKey { signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - // Parse the raw signature bytes as DER-encoded ECDSA signature + // Parse the bytes as DER-encoded ECDSA signature. guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), - let innerSignature = P256.Signing.ECDSASignature(ecdsaSignature) else { + let innerSignature = P256.Signing.ECDSASignature(ecdsaSignature) + else { return false } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + } + + @inlinable + internal func isValidSignature( + _ signature: P256.Signing.ECDSASignature, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { switch signatureAlgorithm { case .ecdsaWithSHA256: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA256.hash(data: bytes)) case .ecdsaWithSHA384: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA384.hash(data: bytes)) case .ecdsaWithSHA512: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA512.hash(data: bytes)) default: return false } @@ -241,16 +243,7 @@ extension P384.Signing.PublicKey { return false } - switch signatureAlgorithm { - case .ecdsaWithSHA256: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) - case .ecdsaWithSHA384: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) - case .ecdsaWithSHA512: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) - default: - return false - } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -259,19 +252,30 @@ extension P384.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - // Parse the raw signature bytes as DER-encoded ECDSA signature + + // Parse the bytes as DER-encoded ECDSA signature guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), - let innerSignature = P384.Signing.ECDSASignature(ecdsaSignature) else { + let innerSignature = P384.Signing.ECDSASignature(ecdsaSignature) + else { return false } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + } + + @inlinable + internal func isValidSignature( + _ signature: P384.Signing.ECDSASignature, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { switch signatureAlgorithm { case .ecdsaWithSHA256: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA256.hash(data: bytes)) case .ecdsaWithSHA384: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA384.hash(data: bytes)) case .ecdsaWithSHA512: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA512.hash(data: bytes)) default: return false } @@ -293,16 +297,7 @@ extension P521.Signing.PublicKey { return false } - switch signatureAlgorithm { - case .ecdsaWithSHA256: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) - case .ecdsaWithSHA384: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) - case .ecdsaWithSHA512: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) - default: - return false - } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -313,17 +308,27 @@ extension P521.Signing.PublicKey { ) -> Bool { // Parse the raw signature bytes as DER-encoded ECDSA signature guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), - let innerSignature = P521.Signing.ECDSASignature(ecdsaSignature) else { + let innerSignature = P521.Signing.ECDSASignature(ecdsaSignature) + else { return false } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + } + + @inlinable + internal func isValidSignature( + _ signature: P521.Signing.ECDSASignature, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { switch signatureAlgorithm { case .ecdsaWithSHA256: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA256.hash(data: bytes)) case .ecdsaWithSHA384: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA384.hash(data: bytes)) case .ecdsaWithSHA512: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes)) + return self.isValidSignature(signature, for: SHA512.hash(data: bytes)) default: return false } @@ -342,21 +347,8 @@ extension _RSA.Signing.PublicKey { // Signature mismatch return false } - // For now we don't support RSA PSS, as it's not deployed in the WebPKI. - let padding = _RSA.Signing.Padding.insecurePKCS1v1_5 - switch signatureAlgorithm { - case .sha1WithRSAEncryption: - return self.isValidSignature(innerSignature, for: Insecure.SHA1.hash(data: bytes), padding: padding) - case .sha256WithRSAEncryption: - return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes), padding: padding) - case .sha384WithRSAEncryption: - return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes), padding: padding) - case .sha512WithRSAEncryption: - return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes), padding: padding) - default: - return false - } + return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -367,19 +359,28 @@ extension _RSA.Signing.PublicKey { ) -> Bool { // RSA signatures are already in raw format let rsaSignature = _RSA.Signing.RSASignature(rawRepresentation: signature) - + + return isValidSignature(rsaSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + } + + @inlinable + internal func isValidSignature( + _ signature: _RSA.Signing.RSASignature, + for bytes: Bytes, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) -> Bool { // For now we don't support RSA PSS, as it's not deployed in the WebPKI. let padding = _RSA.Signing.Padding.insecurePKCS1v1_5 switch signatureAlgorithm { case .sha1WithRSAEncryption: - return self.isValidSignature(rsaSignature, for: Insecure.SHA1.hash(data: bytes), padding: padding) + return self.isValidSignature(signature, for: Insecure.SHA1.hash(data: bytes), padding: padding) case .sha256WithRSAEncryption: - return self.isValidSignature(rsaSignature, for: SHA256.hash(data: bytes), padding: padding) + return self.isValidSignature(signature, for: SHA256.hash(data: bytes), padding: padding) case .sha384WithRSAEncryption: - return self.isValidSignature(rsaSignature, for: SHA384.hash(data: bytes), padding: padding) + return self.isValidSignature(signature, for: SHA384.hash(data: bytes), padding: padding) case .sha512WithRSAEncryption: - return self.isValidSignature(rsaSignature, for: SHA512.hash(data: bytes), padding: padding) + return self.isValidSignature(signature, for: SHA512.hash(data: bytes), padding: padding) default: return false } @@ -399,12 +400,7 @@ extension Curve25519.Signing.PublicKey { return false } - switch signatureAlgorithm { - case .ed25519: - return self.isValidSignature(rawInnerSignature, for: bytes) - default: - return false - } + return isValidSignature(rawInnerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable From ffe15cf39bd815cb38e0626f0f8cc2c9d910ba27 Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Mon, 17 Nov 2025 11:31:50 +0000 Subject: [PATCH 03/11] Formatting --- Tests/X509Tests/SignatureTests.swift | 54 +++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/Tests/X509Tests/SignatureTests.swift b/Tests/X509Tests/SignatureTests.swift index 7346a6e5..d92393f5 100644 --- a/Tests/X509Tests/SignatureTests.swift +++ b/Tests/X509Tests/SignatureTests.swift @@ -957,7 +957,11 @@ final class SignatureTests: XCTestCase { func test(_ key: Certificate.PrivateKey) throws { let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -971,7 +975,11 @@ final class SignatureTests: XCTestCase { let key = Certificate.PrivateKey(Self.ed25519Key) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -984,7 +992,11 @@ final class SignatureTests: XCTestCase { let key = Certificate.PrivateKey(secureEnclaveP256) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -996,7 +1008,11 @@ final class SignatureTests: XCTestCase { let key = try Certificate.PrivateKey(secKeyRSA) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -1008,7 +1024,11 @@ final class SignatureTests: XCTestCase { let key = try Certificate.PrivateKey(secKeyEC256) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -1020,7 +1040,11 @@ final class SignatureTests: XCTestCase { let key = try Certificate.PrivateKey(secKeyEC384) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -1032,7 +1056,11 @@ final class SignatureTests: XCTestCase { let key = try Certificate.PrivateKey(secKeyEC521) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -1044,7 +1072,11 @@ final class SignatureTests: XCTestCase { let key = try Certificate.PrivateKey(secKeyEnclaveEC256) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } @@ -1056,7 +1088,11 @@ final class SignatureTests: XCTestCase { let key = try Certificate.PrivateKey(secKeyEnclaveEC384) let signature = try key.sign(bytes: Self.dummyData, signatureAlgorithm: algo) let pub = key.publicKey - let isValidSignature = pub.isValidSignature(signature.rawRepresentation, for: Self.dummyData, signatureAlgorithm: algo) + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) XCTAssert(isValidSignature) } #endif From b53c4b1a0b4843055506ba3e32d8ed2505aca9dd Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 09:59:36 +0000 Subject: [PATCH 04/11] Cleanup --- Sources/X509/Signature.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index 5486902f..42963d37 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -252,7 +252,6 @@ extension P384.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - // Parse the bytes as DER-encoded ECDSA signature guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), let innerSignature = P384.Signing.ECDSASignature(ecdsaSignature) @@ -306,7 +305,6 @@ extension P521.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - // Parse the raw signature bytes as DER-encoded ECDSA signature guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), let innerSignature = P521.Signing.ECDSASignature(ecdsaSignature) else { @@ -357,7 +355,6 @@ extension _RSA.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - // RSA signatures are already in raw format let rsaSignature = _RSA.Signing.RSASignature(rawRepresentation: signature) return isValidSignature(rsaSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) From 0caf4c75960411ff3f49294090511d442e4966d9 Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 10:00:11 +0000 Subject: [PATCH 05/11] Add cross-verification tests --- Tests/X509Tests/SignatureTests.swift | 227 +++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) diff --git a/Tests/X509Tests/SignatureTests.swift b/Tests/X509Tests/SignatureTests.swift index d92393f5..76f60030 100644 --- a/Tests/X509Tests/SignatureTests.swift +++ b/Tests/X509Tests/SignatureTests.swift @@ -1096,4 +1096,231 @@ final class SignatureTests: XCTestCase { XCTAssert(isValidSignature) } #endif + + func testRawSignatureValidationAcrossKeysShouldFail() async throws { + var keys = [ + Certificate.PrivateKey(Self.rsaKey), + Certificate.PrivateKey(Self.p256Key), + Certificate.PrivateKey(Self.p384Key), + Certificate.PrivateKey(Self.p521Key), + Certificate.PrivateKey(Self.ed25519Key), + ] + + #if canImport(Darwin) + if let secureEnclaveP256 = Self.secureEnclaveP256 { + keys.append(Certificate.PrivateKey(secureEnclaveP256)) + } + if let secKeyRSA = Self.secKeyRSA, let key = try? Certificate.PrivateKey(secKeyRSA) { + keys.append(key) + } + if let secKeyEC256 = Self.secKeyEC256, let key = try? Certificate.PrivateKey(secKeyEC256) { + keys.append(key) + } + if let secKeyEC384 = Self.secKeyEC384, let key = try? Certificate.PrivateKey(secKeyEC384) { + keys.append(key) + } + if let secKeyEC521 = Self.secKeyEC521, let key = try? Certificate.PrivateKey(secKeyEC521) { + keys.append(key) + } + if let secKeyEnclaveEC256 = Self.secKeyEnclaveEC256, let key = try? Certificate.PrivateKey(secKeyEnclaveEC256) { + keys.append(key) + } + if let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384, let key = try? Certificate.PrivateKey(secKeyEnclaveEC384) { + keys.append(key) + } + #endif + + for signatureKey in keys { + for verificationKey in keys { + let algo = signatureKey.defaultSignatureAlgorithm + let signature = try signatureKey.sign(bytes: Self.dummyData, signatureAlgorithm: algo) + let pub = verificationKey.publicKey + let isValidSignature = pub.isValidSignature( + signature.rawRepresentation, + for: Self.dummyData, + signatureAlgorithm: algo + ) + // Signatures should only be validated by the same key pair. + XCTAssertEqual(isValidSignature, signatureKey == verificationKey) + + // Bit flips in the signature always fail. + var signatureBytes = signature.rawRepresentation + signatureBytes[0] ^= 0xff + let isValidCorruptedSignature = pub.isValidSignature( + signatureBytes, + for: Self.dummyData, + signatureAlgorithm: algo + ) + XCTAssertFalse(isValidCorruptedSignature) + } + } + } + + func signatureCrossVerificationCheck( + publicKeyPEM: String, + signatureBase64: String, + signatureAlgorithm: Certificate.SignatureAlgorithm + ) throws -> Bool { + let singatureData = try XCTUnwrap(Data(base64Encoded: signatureBase64)) + let publicKey = try Certificate.PublicKey(pemEncoded: publicKeyPEM) + let isValidSignature = publicKey.isValidSignature( + singatureData, + for: Self.dummyData, + signatureAlgorithm: signatureAlgorithm + ) + return isValidSignature + } + + /// The key and signature were created with openssl for cross verification. + /// + /// ```bash + /// openssl ecparam -genkey -name prime256v1 -noout -out private_key.pem + /// openssl ec -in private_key.pem -pubout -out public_key.pem + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha256 -sign private_key.pem -out signature.bin + /// cat signature.bin | base64 > signature.b64 + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha256 -verify public_key.pem -signature signature.bin + /// ``` + func testVerifyExternalSignatureP256() throws { + let publicKeyString = """ + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECE0sHvBI7sII2F/BU0MQZmYTopKC + kPvWhk6CZfJwUpWnwD/frW40nvA20YzQur/PWqUBh7q2Y9wiTiLuBcxO/g== + -----END PUBLIC KEY----- + """ + let b64Signature = + "MEUCICk5wNvxRSoHGa8YmbCnpfpmmnsrjLIUBHRdQVGFwRgPAiEA+IvpJeu0ky5cLex4j6hcAhlPNu3V2cIIIMdgYa9pnko=" + let signatureAlgorithm = Certificate.SignatureAlgorithm.ecdsaWithSHA256 + + XCTAssert( + try signatureCrossVerificationCheck( + publicKeyPEM: publicKeyString, + signatureBase64: b64Signature, + signatureAlgorithm: signatureAlgorithm + ) + ) + } + + /// The key and signature were created with openssl for cross verification. + /// + /// ```bash + /// openssl ecparam -genkey -name secp384r1 -noout -out private_key.pem + /// openssl ec -in private_key.pem -pubout -out public_key.pem + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha384 -sign private_key.pem -out signature.bin + /// cat signature.bin | base64 > signature.b64 + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha384 -verify public_key.pem -signature signature.bin + /// ``` + func testVerifyExternalSignatureP384() throws { + let publicKeyString = """ + -----BEGIN PUBLIC KEY----- + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENxXh5R2x/yemNlT3HdrTl5s18R1vc9Wb + 07LajGD+Lpf71UOPHDOgvvvqXvSpjOmNlAjo1QZ9RYdTIBEdkld6i6G9eS/8HUYH + K0ShVbw8J9FoEqeEudPkDYnSsP4rGbi+ + -----END PUBLIC KEY----- + """ + let b64Signature = + "MGUCMBG76L2Jy/aS0AGDGOfMAXtYS0KJSXagd1HgcJjSMCDu39A45OAzrwuB79Q7WxHo7AIxALmi8wBQyD3tuKZXqyWX6WKMT5S5OP6GTR0yOskxxTgOtSAAJjfdPlwSHh/dX6SHlA==" + let signatureAlgorithm = Certificate.SignatureAlgorithm.ecdsaWithSHA384 + + XCTAssert( + try signatureCrossVerificationCheck( + publicKeyPEM: publicKeyString, + signatureBase64: b64Signature, + signatureAlgorithm: signatureAlgorithm + ) + ) + } + + /// The key and signature were created with openssl for cross verification. + /// + /// ```bash + /// openssl ecparam -genkey -name secp521r1 -noout -out private_key.pem + /// openssl ec -in private_key.pem -pubout -out public_key.pem + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha512 -sign private_key.pem -out signature.bin + /// cat signature.bin | base64 > signature.b64 + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha512 -verify public_key.pem -signature signature.bin + /// ``` + func testVerifyExternalSignatureP521() throws { + let publicKeyString = """ + -----BEGIN PUBLIC KEY----- + MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBs/PH1A47bzcgI5B9AO9WHSucivS6 + DY8zAxCAxKgaiY2TZNx6+X5tfj3dULWmJihC2KhIIV8xwy4jMu+cnXE6KWQBgrQ5 + LHJwzSmkmwHOUNfZFBZWcgciRS73A6ObamCODHpq0MX3EQQf+flTcgK9gPE/mG0Z + vFG9Vp8EOSoyGiMUYyg= + -----END PUBLIC KEY----- + """ + let b64Signature = + "MIGIAkIA3UlG4owLd8os1NtGyssTph1dpRxYmfRXZ8XclKmaHXcVcqztZiFEs2aubmM4PbEBxMhs5B99Y6wEaV93wpF8+TACQgEikZjniBCSSwycVOKs63gLbz+cxHZesEsZ5YUoiotWL0qP1QHxZSkiMhdEjbi3iVV4cICMp79L8nl+Y45cCE5l2A==" + let signatureAlgorithm = Certificate.SignatureAlgorithm.ecdsaWithSHA512 + + XCTAssert( + try signatureCrossVerificationCheck( + publicKeyPEM: publicKeyString, + signatureBase64: b64Signature, + signatureAlgorithm: signatureAlgorithm + ) + ) + } + + /// The key and signature were created with openssl for cross verification. + /// + /// ```bash + /// openssl genrsa -out private_key.pem 2048 + /// openssl rsa -in private_key.pem -pubout -out public_key.pem + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha256 -sign private_key.pem -out signature.bin + /// base64 -i signature.bin -o signature.b64 + /// echo -n "the quick brown fox jumps over the lazy dog" | openssl dgst -sha256 -verify public_key.pem -signature signature.bin + /// ``` + func testVerifyExternalSignatureRSA() throws { + let publicKeyString = """ + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA69n2XSWqEfUXePz2LE/o + rJPn8WEWMUIbAXmVOkTkEtxu1hcPkFP+L8zpoXjcxXTieFPLPXNST2Y2DgOVW36R + bqcgK9L5UV/x1ZaHlT2aLjowSNapjMRMETWahiNLyoXjzj/bVefpreQx++BDx1BL + rYHd77OzjN5rOs16ASOxceinV34OddHMdNVZpA+nhL3vTjz+1wCplxhmF2x6wXty + jKv4UfUfxXSTzwgew0SmhjcBkpljkI+tUcS/XICIXCyrqGCzVupm/OnCET/2e6Kb + Q2OlSkJBsvXbaALZ+R5pBEz19OJ6gNXJKzQ1R+onkiER4vUE2KIV/nz8nClkiLEt + hwIDAQAB + -----END PUBLIC KEY----- + """ + let b64Signature = + "Y8shChzT1weQ/aI9KtQaYAjQO3nB7TdJXBvCqtRjxF4hF3zM/RS5vd9HD5+pq9A2r4Zi9w8ehqOEJVMQ1iOoJ4kaJuKo6AXq4lGzeITiEF2P/BlFpBijawfuSlfGUxu8mtbj8bPOdCSH3QtRRSKl2xrmXz8pXyFBPnVdsVDL6nJ1qfv36eYPT4ZckyW4ob3LxB8DUWbC1yM2uoiv8qkGwI23xBae9G5Wk6rd6Op/jLxSB7OBbzReIE9OC9KKoqkwSM2f39L9tb/OCLBGt+EiDrj9dBeplbftqklHRtiz09+YMo62q0VuNDy/ZFidMouBI0m2RqqbZfguc7AJknj4ig==" + let signatureAlgorithm = Certificate.SignatureAlgorithm.sha256WithRSAEncryption + + XCTAssert( + try signatureCrossVerificationCheck( + publicKeyPEM: publicKeyString, + signatureBase64: b64Signature, + signatureAlgorithm: signatureAlgorithm + ) + ) + } + + /// The key and signature were created with openssl for cross verification. The openssl that comes with macOS has + /// some problems here, but the hombrew version does the job. + /// + /// ```bash + /// openssl_brew="/opt/homebrew/opt/openssl@3/bin/openssl" # adjust path as needed + /// $openssl_brew genpkey -algorithm Ed25519 -out private_key_ed25519.pem + /// $openssl_brew pkey -in private_key_ed25519.pem -pubout -out public_key_ed25519.pem + /// echo -n "the quick brown fox jumps over the lazy dog" | $openssl_brew dgst -sign private_key_ed25519.pem -out signature_ed25519.bin + /// base64 -i signature_ed25519.bin -o signature_ed25519.b64 + /// echo -n "the quick brown fox jumps over the lazy dog" | $openssl_brew dgst -verify public_key_ed25519.pem -signature signature_ed25519.bin + /// ``` + func testVerifyExternalSignatureEd25519() throws { + let publicKeyString = """ + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VwAyEAigqjYOkQRGJZnXK5tlYGL64wqRImNW4xJ9ddCmCaNa8= + -----END PUBLIC KEY----- + """ + let b64Signature = "kxEmGeHhUT+dG4Kpq/+ZCMpHzbIfXb/Oss+mvAGJMoieCu+4dhsQaO/fKNBNUQmBj2wu0ZyHpkXX8p2Eijd/Aw==" + let signatureAlgorithm = Certificate.SignatureAlgorithm.ed25519 + + XCTAssert( + try signatureCrossVerificationCheck( + publicKeyPEM: publicKeyString, + signatureBase64: b64Signature, + signatureAlgorithm: signatureAlgorithm + ) + ) + } } From 3a601c1cd2df52cbec3a4f72787fa795c155f48e Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 10:07:40 +0000 Subject: [PATCH 06/11] Cleanup --- Sources/X509/Signature.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index 42963d37..d469b309 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -181,7 +181,6 @@ extension P256.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - guard case .ecdsa(let rawInnerSignature) = signature.backing, let innerSignature = P256.Signing.ECDSASignature(rawInnerSignature) else { @@ -408,7 +407,6 @@ extension Curve25519.Signing.PublicKey { ) -> Bool { switch signatureAlgorithm { case .ed25519: - // Ed25519 signatures are already in raw format (64 bytes) return self.isValidSignature(signature, for: bytes) default: return false From f53e3189a5a7182672221ad45991eb02c7130cd6 Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 10:09:02 +0000 Subject: [PATCH 07/11] Remove redundant test --- Tests/X509Tests/SignatureTests.swift | 59 ---------------------------- 1 file changed, 59 deletions(-) diff --git a/Tests/X509Tests/SignatureTests.swift b/Tests/X509Tests/SignatureTests.swift index 76f60030..084fb2bb 100644 --- a/Tests/X509Tests/SignatureTests.swift +++ b/Tests/X509Tests/SignatureTests.swift @@ -1097,65 +1097,6 @@ final class SignatureTests: XCTestCase { } #endif - func testRawSignatureValidationAcrossKeysShouldFail() async throws { - var keys = [ - Certificate.PrivateKey(Self.rsaKey), - Certificate.PrivateKey(Self.p256Key), - Certificate.PrivateKey(Self.p384Key), - Certificate.PrivateKey(Self.p521Key), - Certificate.PrivateKey(Self.ed25519Key), - ] - - #if canImport(Darwin) - if let secureEnclaveP256 = Self.secureEnclaveP256 { - keys.append(Certificate.PrivateKey(secureEnclaveP256)) - } - if let secKeyRSA = Self.secKeyRSA, let key = try? Certificate.PrivateKey(secKeyRSA) { - keys.append(key) - } - if let secKeyEC256 = Self.secKeyEC256, let key = try? Certificate.PrivateKey(secKeyEC256) { - keys.append(key) - } - if let secKeyEC384 = Self.secKeyEC384, let key = try? Certificate.PrivateKey(secKeyEC384) { - keys.append(key) - } - if let secKeyEC521 = Self.secKeyEC521, let key = try? Certificate.PrivateKey(secKeyEC521) { - keys.append(key) - } - if let secKeyEnclaveEC256 = Self.secKeyEnclaveEC256, let key = try? Certificate.PrivateKey(secKeyEnclaveEC256) { - keys.append(key) - } - if let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384, let key = try? Certificate.PrivateKey(secKeyEnclaveEC384) { - keys.append(key) - } - #endif - - for signatureKey in keys { - for verificationKey in keys { - let algo = signatureKey.defaultSignatureAlgorithm - let signature = try signatureKey.sign(bytes: Self.dummyData, signatureAlgorithm: algo) - let pub = verificationKey.publicKey - let isValidSignature = pub.isValidSignature( - signature.rawRepresentation, - for: Self.dummyData, - signatureAlgorithm: algo - ) - // Signatures should only be validated by the same key pair. - XCTAssertEqual(isValidSignature, signatureKey == verificationKey) - - // Bit flips in the signature always fail. - var signatureBytes = signature.rawRepresentation - signatureBytes[0] ^= 0xff - let isValidCorruptedSignature = pub.isValidSignature( - signatureBytes, - for: Self.dummyData, - signatureAlgorithm: algo - ) - XCTAssertFalse(isValidCorruptedSignature) - } - } - } - func signatureCrossVerificationCheck( publicKeyPEM: String, signatureBase64: String, From 7d550ce5ae99f1d074e3d65cf2dfdf32d4ae3667 Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 10:13:21 +0000 Subject: [PATCH 08/11] More cleanup --- Sources/X509/Signature.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index d469b309..4f8589de 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -197,8 +197,6 @@ extension P256.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - - // Parse the bytes as DER-encoded ECDSA signature. guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), let innerSignature = P256.Signing.ECDSASignature(ecdsaSignature) else { @@ -251,7 +249,6 @@ extension P384.Signing.PublicKey { for bytes: Bytes, signatureAlgorithm: Certificate.SignatureAlgorithm ) -> Bool { - // Parse the bytes as DER-encoded ECDSA signature guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)), let innerSignature = P384.Signing.ECDSASignature(ecdsaSignature) else { From 31e30696c1b7d06266cb38940974126c96e18dfc Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 18 Nov 2025 14:17:58 +0000 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: Cory Benfield --- Sources/X509/Signature.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index 4f8589de..d9831b4c 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -188,7 +188,7 @@ extension P256.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -203,7 +203,7 @@ extension P256.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -240,7 +240,7 @@ extension P384.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -255,7 +255,7 @@ extension P384.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -292,7 +292,7 @@ extension P521.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -307,7 +307,7 @@ extension P521.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -353,7 +353,7 @@ extension _RSA.Signing.PublicKey { ) -> Bool { let rsaSignature = _RSA.Signing.RSASignature(rawRepresentation: signature) - return isValidSignature(rsaSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(rsaSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable @@ -393,7 +393,7 @@ extension Curve25519.Signing.PublicKey { return false } - return isValidSignature(rawInnerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(rawInnerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable From d70ef465bd13a8635a53981d9aa3f4ba56b6c5d4 Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 14:38:32 +0000 Subject: [PATCH 10/11] Formatting --- Tests/X509Tests/SignatureTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/X509Tests/SignatureTests.swift b/Tests/X509Tests/SignatureTests.swift index e76f78ac..52b5f0a4 100644 --- a/Tests/X509Tests/SignatureTests.swift +++ b/Tests/X509Tests/SignatureTests.swift @@ -1004,7 +1004,7 @@ final class SignatureTests: XCTestCase { 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, ]) } - + func testSignatureAlgorithmTranslatesToCorrectRFC8446Value() throws { for (value, algorithm) in SignatureTests.supportedRFC8446SignatureAlgorithms { XCTAssertEqual(value, try! algorithm.rfc8446SignatureSchemeValue) From 2ce872aad346afcd399b77c16e688e38bbf0498d Mon Sep 17 00:00:00 2001 From: Raphael Hiesgen Date: Tue, 18 Nov 2025 17:45:06 +0000 Subject: [PATCH 11/11] Add missing self. --- Sources/X509/Signature.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/X509/Signature.swift b/Sources/X509/Signature.swift index d9831b4c..c49295f1 100644 --- a/Sources/X509/Signature.swift +++ b/Sources/X509/Signature.swift @@ -342,7 +342,7 @@ extension _RSA.Signing.PublicKey { return false } - return isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) + return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm) } @inlinable