diff --git a/Sources/ShieldSecurity/SecKeyPair.swift b/Sources/ShieldSecurity/SecKeyPair.swift index 891fd7b38..3a2c5b324 100644 --- a/Sources/ShieldSecurity/SecKeyPair.swift +++ b/Sources/ShieldSecurity/SecKeyPair.swift @@ -29,6 +29,10 @@ public struct SecKeyPair { public class Builder { + + public enum Flag { + case secureEnclave + } public let type: SecKeyType? public let keySize: Int? @@ -46,31 +50,44 @@ public struct SecKeyPair { return Builder(type: type, keySize: keySize) } - public func generate(label: String? = nil) throws -> SecKeyPair { + public func generate(label: String? = nil, flags: Set = []) throws -> SecKeyPair { guard let type = type else { fatalError("missing key type") } guard let keySize = keySize else { fatalError("missing key size") } - var attrs: [String: Any] = [ - kSecAttrKeyType as String: type.systemValue, - kSecAttrKeySizeInBits as String: keySize, + var attrs: [CFString: Any] = [ + kSecAttrKeyType: type.systemValue, + kSecAttrKeySizeInBits: keySize ] if let label = label { - attrs[kSecAttrLabel as String] = label + attrs[kSecAttrLabel] = label + } + + if flags.contains(.secureEnclave) { + attrs[kSecAttrTokenID] = kSecAttrTokenIDSecureEnclave } var publicKey: SecKey?, privateKey: SecKey? let status = SecKeyGeneratePair(attrs as CFDictionary, &publicKey, &privateKey) - if status != errSecSuccess { + if status != errSecSuccess { throw SecKeyPair.Error.generateFailed } - #if os(iOS) || os(watchOS) || os(tvOS) +#if os(iOS) || os(watchOS) || os(tvOS) + if !flags.contains(.secureEnclave) { + try privateKey!.save() + } + try publicKey!.save() - try privateKey!.save() - #endif +#elseif os(macOS) + + if flags.contains(.secureEnclave) { + try publicKey!.save() + } + +#endif return SecKeyPair(privateKey: privateKey!, publicKey: publicKey!) } @@ -120,6 +137,7 @@ public struct SecKeyPair { try publicKey.delete() try privateKey.delete() + } public func persistentReferences() throws -> (Data, Data) { diff --git a/Tests/SecKeyPairTests.swift b/Tests/SecKeyPairTests.swift index 44afd7272..c76348410 100644 --- a/Tests/SecKeyPairTests.swift +++ b/Tests/SecKeyPairTests.swift @@ -94,4 +94,15 @@ class SecKeyPairTests: XCTestCase { XCTAssertEqual(plainText, plainText4) } + + func testGenerateSecureEnclave() throws { + try XCTSkipIf(true, "Only runs on iPhone/iPad/AppleTV or a Mac with T2") + + let keyPairBuilder = SecKeyPair.Builder(type: .ec, keySize: 256) + + var keyPair: SecKeyPair? = nil + XCTAssertNoThrow(keyPair = try keyPairBuilder.generate(label: "Test Secure Key", flags: [.secureEnclave])) + XCTAssertNoThrow(try keyPair?.delete()) + } + } diff --git a/Tests/SecKeyTests.swift b/Tests/SecKeyTests.swift index 487140d3f..4f49451de 100644 --- a/Tests/SecKeyTests.swift +++ b/Tests/SecKeyTests.swift @@ -150,7 +150,6 @@ class SecKeyTests: ParameterizedTestCase { } func testECGeneration() throws { - try [192, 256, 384, 521].forEach { keySize in let keyPair = try SecKeyPair.Builder(type: .ec, keySize: keySize).generate(label: "Test")