diff --git a/Sources/X509/CMakeLists.txt b/Sources/X509/CMakeLists.txt index dd9b2c8..45d1b65 100644 --- a/Sources/X509/CMakeLists.txt +++ b/Sources/X509/CMakeLists.txt @@ -82,6 +82,7 @@ add_library(X509 "RandomNumberGenerator+bytes.swift" "RelativeDistinguishedName.swift" "SEC1PrivateKey.swift" + "SecKeyWrapper.swift" "Signature.swift" "SignatureAlgorithm.swift" "Verifier/AllOfPolicies.swift" diff --git a/Sources/X509/CertificatePrivateKey.swift b/Sources/X509/CertificatePrivateKey.swift index f1082ed..928565b 100644 --- a/Sources/X509/CertificatePrivateKey.swift +++ b/Sources/X509/CertificatePrivateKey.swift @@ -21,7 +21,7 @@ extension Certificate { /// A private key that can be used with a certificate. /// /// This type provides an opaque wrapper around the various private key types - /// provided by `swift-crypto`. Users are expected to construct this key from + /// provided by `swift-crypto` and `Security`. Users are expected to construct this key from /// one of those types. /// /// As private keys are never sent over the wire, this type does not offer @@ -70,6 +70,13 @@ extension Certificate { public init(_ secureEnclaveP256: SecureEnclave.P256.Signing.PrivateKey) { self.backing = .secureEnclaveP256(secureEnclaveP256) } + + /// Construct a private key wrapping a SecKey private key. + /// - Parameter secKey: The SecKey private key to wrap. + @inlinable + public init(_ secKey: SecKey) throws { + self.backing = .secKey(try SecKeyWrapper(key: secKey)) + } #endif @inlinable @@ -93,6 +100,8 @@ extension Certificate { #if canImport(Darwin) case .secureEnclaveP256(let secureEnclaveP256): return try secureEnclaveP256.signature(for: bytes, digestAlgorithm: digestAlgorithm) + case .secKey(let secKeyWrapper): + return try secKeyWrapper.signature(for: bytes, digestAlgorithm: digestAlgorithm) #endif } } @@ -113,6 +122,8 @@ extension Certificate { #if canImport(Darwin) case .secureEnclaveP256(let secureEnclaveP256): return PublicKey(secureEnclaveP256.publicKey) + case .secKey(let secKeyWrapper): + return secKeyWrapper.publicKey #endif } } @@ -139,6 +150,21 @@ extension Certificate { reason: "Cannot use \(algorithm) with ECDSA key \(self)" ) } + case .secKey(let key): + switch key.type { + case .ECDSA: + if !algorithm.isECDSA { + throw CertificateError.unsupportedSignatureAlgorithm( + reason: "Cannot use \(algorithm) with ECDSA key \(self)" + ) + } + case .RSA: + if !algorithm.isRSA { + throw CertificateError.unsupportedSignatureAlgorithm( + reason: "Cannot use \(algorithm) with RSA key \(self)" + ) + } + } #endif } @@ -164,6 +190,8 @@ extension Certificate.PrivateKey: CustomStringConvertible { #if canImport(Darwin) case .secureEnclaveP256: return "SecureEnclave.P256.PrivateKey" + case .secKey: + return "SecKey" #endif } } @@ -178,6 +206,7 @@ extension Certificate.PrivateKey { case rsa(_CryptoExtras._RSA.Signing.PrivateKey) #if canImport(Darwin) case secureEnclaveP256(SecureEnclave.P256.Signing.PrivateKey) + case secKey(SecKeyWrapper) #endif @inlinable @@ -194,6 +223,8 @@ extension Certificate.PrivateKey { #if canImport(Darwin) case (.secureEnclaveP256(let l), .secureEnclaveP256(let r)): return l.dataRepresentation == r.dataRepresentation + case (.secKey(let l), .secKey(let r)): + return l.publicKey.backing == r.publicKey.backing #endif default: return false @@ -219,6 +250,10 @@ extension Certificate.PrivateKey { case .secureEnclaveP256(let digest): hasher.combine(4) hasher.combine(digest.dataRepresentation) + case .secKey(let secKeyWrapper): + hasher.combine(5) + hasher.combine(secKeyWrapper.privateKey.hashValue) + hasher.combine(secKeyWrapper.publicKey.hashValue) #endif } } @@ -305,6 +340,7 @@ extension Certificate.PrivateKey { throw CertificateError.unsupportedPrivateKey( reason: "secure enclave private keys can not be serialised as PEM" ) + case .secKey(let key): return try key.pemDocument() #endif } } diff --git a/Sources/X509/SecKeyWrapper.swift b/Sources/X509/SecKeyWrapper.swift new file mode 100644 index 0000000..8205944 --- /dev/null +++ b/Sources/X509/SecKeyWrapper.swift @@ -0,0 +1,329 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftCertificates open source project +// +// Copyright (c) 2024 Apple Inc. and the SwiftCertificates project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if canImport(Darwin) +import SwiftASN1 +import Foundation +@preconcurrency import Crypto +@preconcurrency import _CryptoExtras +@preconcurrency import Security + +extension Certificate.PrivateKey { + /// A wrapper around ``Security.SecKey`` to allow the use of `SecKey` with certificates. + @usableFromInline + struct SecKeyWrapper: Sendable { + @usableFromInline + let privateKey: SecKey + @usableFromInline + let publicKey: Certificate.PublicKey + @usableFromInline + let type: KeyType + @usableFromInline + let attributes: [String: any Sendable] + + @usableFromInline + enum ECKeySize: Sendable { + case P256 + case P384 + case P521 + } + + @usableFromInline + enum KeyType: Sendable { + case RSA + case ECDSA(ECKeySize) + } + + /// Init with an existing `SecKey`. + /// + /// This parses the given `SecKey` and attempts to pre-emptively extract + /// data that will be needed at later points. Importantly, some of these operations + /// can throw, so these are performs during initialisation rather than at later + /// stages where throwing is unacceptable. + @inlinable + init(key: SecKey) throws { + self.privateKey = key + + self.attributes = try Self.keyAttributes(key: key) + + try Self.validateSecKey(attributes: self.attributes) + + self.type = try Self.keyType(attributes: self.attributes) + + self.publicKey = try Self.publicKey(privateKey: key, type: self.type) + } + + @usableFromInline + static func keyAttributes(key: SecKey) throws -> [String: any Sendable] { + guard let attributes = SecKeyCopyAttributes(key) as? [CFString: Any] else { + throw CertificateError.unsupportedPrivateKey( + reason: "cannot copy SecKey attributes" + ) + } + + return attributes as [String: any Sendable] + } + + @usableFromInline + static func validateSecKey(attributes: [String: any Sendable]) throws { + guard let keyClassType = attributes[kSecAttrKeyClass as String] as? String else { + throw CertificateError.unsupportedPrivateKey( + reason: "cannot determine class of SecKey" + ) + } + + let privateKeyClassType = kSecAttrKeyClassPrivate as String + if keyClassType != privateKeyClassType { + throw CertificateError.unsupportedPrivateKey( + reason: "SecKey class must be \(privateKeyClassType), not \(keyClassType)" + ) + } + } + + @usableFromInline + static func publicKeyData(privateKey: SecKey) throws -> Data { + var error: Unmanaged? = nil + guard let publicSecKey = SecKeyCopyPublicKey(privateKey), + let publicKeyData = SecKeyCopyExternalRepresentation(publicSecKey, &error) as Data? + else { + if let error = error?.takeRetainedValue() { + throw CertificateError.unsupportedPrivateKey( + reason: "cannot get public key from SecKey instance: \(error)" + ) + } + + throw CertificateError.unsupportedPrivateKey( + reason: "SecKeyCopyExternalRepresentation returned empty data" + ) + } + + return publicKeyData + } + + @usableFromInline + static func keyType(attributes: [String: any Sendable]) throws -> KeyType { + guard let privateKeyType = attributes[kSecAttrKeyType as String] as? String else { + throw CertificateError.unsupportedPrivateKey( + reason: "cannot get SecKey type" + ) + } + + if privateKeyType == (kSecAttrKeyTypeECDSA as String) { + let keySize = attributes[kSecAttrKeySizeInBits as String] as? Int ?? -1 + + if keySize == 256 { + return .ECDSA(.P256) + } else if keySize == 384 { + return .ECDSA(.P384) + } else if keySize == 521 { + return .ECDSA(.P521) + } else { + throw CertificateError.unsupportedPrivateKey( + reason: "unsupported SecKey key size: \(keySize)" + ) + } + } else if privateKeyType == (kSecAttrKeyTypeRSA as String) { + return .RSA + } else { + throw CertificateError.unsupportedPrivateKey( + reason: "unsupported SecKey key type: \(privateKeyType)" + ) + } + } + + @usableFromInline + static func publicKey(privateKey: SecKey, type: KeyType) throws -> Certificate.PublicKey { + let publicKeyData = try Self.publicKeyData(privateKey: privateKey) + + do { + switch type { + case .ECDSA(let keySize): + if keySize == .P256 { + return Certificate.PublicKey(try P256.Signing.PublicKey(x963Representation: publicKeyData)) + } else if keySize == .P384 { + return Certificate.PublicKey(try P384.Signing.PublicKey(x963Representation: publicKeyData)) + } else if keySize == .P521 { + return Certificate.PublicKey(try P521.Signing.PublicKey(x963Representation: publicKeyData)) + } else { + throw CertificateError.unsupportedPrivateKey( + reason: "unsupported SecKey ECDSA key size: \(keySize)" + ) + } + case .RSA: + return Certificate.PublicKey(try _RSA.Signing.PublicKey(derRepresentation: publicKeyData)) + } + } catch { + throw CertificateError.unsupportedPrivateKey( + reason: "cannot get public key from SecKey instance \(error)" + ) + } + } + + static func signatureData( + key: SecKey, + type: KeyType, + digestAlgorithm: AlgorithmIdentifier, + bytes: Bytes + ) throws -> Data { + + let signatureAlgorithm = try Self.signatureAlgorithm(digestAlgorithm: digestAlgorithm, type: type) + + var error: Unmanaged? + guard + let signatureData = SecKeyCreateSignature( + key, + signatureAlgorithm, + Data(bytes) as CFData, + &error + ) as Data? + else { + if let error = error?.takeRetainedValue() { + throw CertificateError.unsupportedPrivateKey( + reason: "could not create signature with SecKey: \(error)" + ) + } + + throw CertificateError.unsupportedPrivateKey(reason: "SecKeyCreateSignature returned empty data") + } + + return signatureData + } + + static func signatureAlgorithm(digestAlgorithm: AlgorithmIdentifier, type: KeyType) throws -> SecKeyAlgorithm { + let algorithm: SecKeyAlgorithm + switch type { + case .RSA: + switch digestAlgorithm { + case .sha1, .sha1UsingNil: + algorithm = .rsaSignatureMessagePKCS1v15SHA1 + case .sha256, .sha256UsingNil: + algorithm = .rsaSignatureMessagePKCS1v15SHA256 + case .sha384, .sha384UsingNil: + algorithm = .rsaSignatureMessagePKCS1v15SHA384 + case .sha512, .sha512UsingNil: + algorithm = .rsaSignatureMessagePKCS1v15SHA512 + default: + throw CertificateError.unsupportedPrivateKey( + reason: "unsupported SecKey RSA digest algorithm: \(digestAlgorithm)" + ) + } + case .ECDSA: + switch digestAlgorithm { + case .sha1, .sha1UsingNil: + algorithm = .ecdsaSignatureMessageX962SHA1 + case .sha256, .sha256UsingNil: + algorithm = .ecdsaSignatureMessageX962SHA256 + case .sha384, .sha384UsingNil: + algorithm = .ecdsaSignatureMessageX962SHA384 + case .sha512, .sha512UsingNil: + algorithm = .ecdsaSignatureMessageX962SHA512 + default: + throw CertificateError.unsupportedPrivateKey( + reason: "unsupported SecKey ECDSA digest algorithm: \(digestAlgorithm)" + ) + } + } + + return algorithm + } + + @usableFromInline + func signature( + for bytes: Bytes, + digestAlgorithm: AlgorithmIdentifier + ) throws -> Certificate.Signature { + + let signatureData = try Self.signatureData( + key: self.privateKey, + type: self.type, + digestAlgorithm: digestAlgorithm, + bytes: bytes + ) + + switch self.type { + case .RSA: + let signature = _RSA.Signing.RSASignature(rawRepresentation: signatureData) + return Certificate.Signature(backing: .rsa(signature)) + case .ECDSA(let keySize): + switch keySize { + case .P256: + let signature = try P256.Signing.ECDSASignature(derRepresentation: signatureData) + return Certificate.Signature(backing: .ecdsa(.init(signature))) + case .P384: + let signature = try P384.Signing.ECDSASignature(derRepresentation: signatureData) + return Certificate.Signature(backing: .ecdsa(.init(signature))) + case .P521: + let signature = try P521.Signing.ECDSASignature(derRepresentation: signatureData) + return Certificate.Signature(backing: .ecdsa(.init(signature))) + } + } + } + + @usableFromInline + var isSerializable: Bool { + if let extractable = self.attributes[kSecAttrIsExtractable as String] as? Bool { + return extractable + } + + return false + } + + @available(macOS 11.0, iOS 14, tvOS 14, watchOS 7, *) + @inlinable + func pemDocument() throws -> PEMDocument { + if !self.isSerializable { + throw CertificateError.unsupportedPrivateKey( + reason: "SecKey private key PEM cannot be extracted" + ) + } + + var error: Unmanaged? + guard let keyData = SecKeyCopyExternalRepresentation(self.privateKey, &error) as Data? else { + if let error = error?.takeRetainedValue() { + throw CertificateError.unsupportedPrivateKey( + reason: "cannot get external representation of SecKey: \(error)" + ) + } + + throw CertificateError.unsupportedPrivateKey( + reason: "SecKeyCopyExternalRepresentation returned empty data" + ) + } + + let derData: Data + let type: String + + switch self.type { + case .RSA: + type = "RSA PRIVATE KEY" + // keyData is DER-encoded private key + derData = keyData + case .ECDSA(let keySize): + type = "EC PRIVATE KEY" + switch keySize { + case .P256: + derData = try P256.Signing.PrivateKey(x963Representation: keyData).derRepresentation + case .P384: + derData = try P384.Signing.PrivateKey(x963Representation: keyData).derRepresentation + case .P521: + derData = try P521.Signing.PrivateKey(x963Representation: keyData).derRepresentation + } + } + + let array = [UInt8](derData) + return PEMDocument(type: type, derBytes: array) + } + } +} +#endif diff --git a/Tests/X509Tests/SecKeyWrapperTests.swift b/Tests/X509Tests/SecKeyWrapperTests.swift new file mode 100644 index 0000000..6435376 --- /dev/null +++ b/Tests/X509Tests/SecKeyWrapperTests.swift @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftCertificates open source project +// +// Copyright (c) 2024 Apple Inc. and the SwiftCertificates project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import XCTest +@_spi(Testing) @testable import X509 + +#if canImport(Darwin) +final class SecKeyWrapperTests: XCTestCase { + struct CandidateKey { + let key: SecKey + let type: String + let keySize: Int + let sep: Bool + } + + func generateCandidateKeys() throws -> [CandidateKey] { + var keys: [CandidateKey] = [] + + // RSA + keys.append( + CandidateKey( + key: try SignatureTests.generateSecKey(keyType: kSecAttrKeyTypeRSA, keySize: 2048, useSEP: false), + type: "RSA", + keySize: 2048, + sep: false + ) + ) + + // eliptic curves + for keyType in [kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyTypeEC, kSecAttrKeyTypeECDSA] { + for keySize in [256, 384] { + for useSEP in [true, false] { + keys.append( + CandidateKey( + key: try SignatureTests.generateSecKey(keyType: keyType, keySize: keySize, useSEP: useSEP), + type: "EC-\(keyType)", + keySize: keySize, + sep: useSEP + ) + ) + } + } + } + return keys + } + + func testPEMExport() throws { + for candidate in try generateCandidateKeys() { + try XCTContext.runActivity(named: "Testing \(candidate.type) key (size: \(candidate.keySize))") { _ in + let secKeyWrapper = try Certificate.PrivateKey.SecKeyWrapper(key: candidate.key) + + if !candidate.sep { + let pemString = try secKeyWrapper.pemDocument() + XCTAssertNotNil(pemString) + } else { + XCTAssertThrowsError(try secKeyWrapper.pemDocument()) + } + } + } + } +} +#endif diff --git a/Tests/X509Tests/SignatureTests.swift b/Tests/X509Tests/SignatureTests.swift index c94ccef..e810a88 100644 --- a/Tests/X509Tests/SignatureTests.swift +++ b/Tests/X509Tests/SignatureTests.swift @@ -29,6 +29,21 @@ final class SignatureTests: XCTestCase { static let rsaKey = try! _RSA.Signing.PrivateKey(keySize: .bits2048) #if canImport(Darwin) static let secureEnclaveP256 = try? SecureEnclave.P256.Signing.PrivateKey() + static let secKeyRSA = try? generateSecKey(keyType: kSecAttrKeyTypeRSA, keySize: 2048, useSEP: false) + static let secKeyEC256 = try? generateSecKey(keyType: kSecAttrKeyTypeECSECPrimeRandom, keySize: 256, useSEP: false) + static let secKeyEC384 = try? generateSecKey(keyType: kSecAttrKeyTypeECSECPrimeRandom, keySize: 384, useSEP: false) + static let secKeyEC521 = try? generateSecKey(keyType: kSecAttrKeyTypeECSECPrimeRandom, keySize: 521, useSEP: false) + // SEP currently supports 256 and 384 bit EC keys + static let secKeyEnclaveEC256 = try? generateSecKey( + keyType: kSecAttrKeyTypeECSECPrimeRandom, + keySize: 256, + useSEP: true + ) + static let secKeyEnclaveEC384 = try? generateSecKey( + keyType: kSecAttrKeyTypeECSECPrimeRandom, + keySize: 384, + useSEP: true + ) #endif func testP384Signature() throws { @@ -382,6 +397,277 @@ final class SignatureTests: XCTestCase { } #if canImport(Darwin) + static func generateSecKey(keyType: CFString, keySize: Int, useSEP: Bool) throws -> SecKey { + let access = SecAccessControlCreateWithFlags( + kCFAllocatorDefault, + kSecAttrAccessibleWhenUnlockedThisDeviceOnly, + .privateKeyUsage, + nil + )! + + let attributes: NSMutableDictionary = [ + kSecAttrKeyType: keyType, + kSecAttrKeySizeInBits: keySize, + kSecPrivateKeyAttrs: [ + kSecAttrIsPermanent: false, + kSecAttrAccessControl: access, + ], + ] + + if useSEP { + attributes[kSecAttrTokenID] = kSecAttrTokenIDSecureEnclave + } + + var error: Unmanaged? = nil + guard let secKey = SecKeyCreateRandomKey(attributes, &error) else { + throw error!.takeRetainedValue() as Error + } + + return secKey + } + + func testHashFunctionMismatch_secKeyRSA_sha1WithRSAEncryption() throws { + guard let secKeyRSA = Self.secKeyRSA else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyRSA), + signatureAlgorithm: .sha1WithRSAEncryption, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyRSA_sha256WithRSAEncryption() throws { + guard let secKeyRSA = Self.secKeyRSA else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyRSA), + signatureAlgorithm: .sha256WithRSAEncryption, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyRSA_sha384WithRSAEncryption() throws { + guard let secKeyRSA = Self.secKeyRSA else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyRSA), + signatureAlgorithm: .sha384WithRSAEncryption, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyRSA_sha512WithRSAEncryption() throws { + guard let secKeyRSA = Self.secKeyRSA else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyRSA), + signatureAlgorithm: .sha512WithRSAEncryption, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyRSA_ecdsaWithSHA256() throws { + guard let secKeyRSA = Self.secKeyRSA else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyRSA), + signatureAlgorithm: .ecdsaWithSHA256, + validCombination: false + ) + } + + func testHashFunctionMismatch_secKeyEC256_ecdsaWithSHA256() throws { + guard let secKeyEC256 = Self.secKeyEC256 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC256), + signatureAlgorithm: .ecdsaWithSHA256, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC256_ecdsaWithSHA384() throws { + guard let secKeyEC256 = Self.secKeyEC256 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC256), + signatureAlgorithm: .ecdsaWithSHA384, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC256_ecdsaWithSHA512() throws { + guard let secKeyEC256 = Self.secKeyEC256 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC256), + signatureAlgorithm: .ecdsaWithSHA512, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC384_ecdsaWithSHA256() throws { + guard let secKeyEC384 = Self.secKeyEC384 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC384), + signatureAlgorithm: .ecdsaWithSHA256, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC384_ecdsaWithSHA384() throws { + guard let secKeyEC384 = Self.secKeyEC384 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC384), + signatureAlgorithm: .ecdsaWithSHA384, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC384_ecdsaWithSHA512() throws { + guard let secKeyEC384 = Self.secKeyEC384 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC384), + signatureAlgorithm: .ecdsaWithSHA512, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC521_ecdsaWithSHA256() throws { + guard let secKeyEC521 = Self.secKeyEC521 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC521), + signatureAlgorithm: .ecdsaWithSHA256, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC521_ecdsaWithSHA384() throws { + guard let secKeyEC521 = Self.secKeyEC521 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC521), + signatureAlgorithm: .ecdsaWithSHA384, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC521_ecdsaWithSHA512() throws { + guard let secKeyEC521 = Self.secKeyEC521 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC521), + signatureAlgorithm: .ecdsaWithSHA512, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEC521_sha512WithRSAEncryption() throws { + guard let secKeyEC521 = Self.secKeyEC521 else { + throw XCTSkip("Key Error") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEC521), + signatureAlgorithm: .sha512WithRSAEncryption, + validCombination: false + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC256_ecdsaWithSHA256() throws { + guard let secKeyEnclaveEC256 = Self.secKeyEnclaveEC256 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC256), + signatureAlgorithm: .ecdsaWithSHA256, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC256_ecdsaWithSHA384() throws { + guard let secKeyEnclaveEC256 = Self.secKeyEnclaveEC256 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC256), + signatureAlgorithm: .ecdsaWithSHA384, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC256_ecdsaWithSHA512() throws { + guard let secKeyEnclaveEC256 = Self.secKeyEnclaveEC256 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC256), + signatureAlgorithm: .ecdsaWithSHA512, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC384_ecdsaWithSHA256() throws { + guard let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC384), + signatureAlgorithm: .ecdsaWithSHA256, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC384_ecdsaWithSHA384() throws { + guard let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC384), + signatureAlgorithm: .ecdsaWithSHA384, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC384_ecdsaWithSHA512() throws { + guard let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC384), + signatureAlgorithm: .ecdsaWithSHA512, + validCombination: true + ) + } + + func testHashFunctionMismatch_secKeyEnclaveEC384_sha512WithRSAEncryption() throws { + guard let secKeyEnclaveEC384 = Self.secKeyEnclaveEC384 else { + throw XCTSkip("No SEP") + } + try self.hashFunctionMismatchTest( + privateKey: .init(secKeyEnclaveEC384), + signatureAlgorithm: .sha512WithRSAEncryption, + validCombination: false + ) + } + func testHashFunctionMismatch_secureEnclaveP256_ecdsaWithSHA256() throws { guard let secureEnclaveP256 = Self.secureEnclaveP256 else { throw XCTSkip("No SEP")