diff --git a/Sources/Packages/Sources/Brief/UpdaterProtocol.swift b/Sources/Packages/Sources/Brief/UpdaterProtocol.swift index 1930a0f..a5c5edc 100644 --- a/Sources/Packages/Sources/Brief/UpdaterProtocol.swift +++ b/Sources/Packages/Sources/Brief/UpdaterProtocol.swift @@ -1,4 +1,5 @@ import Foundation +import Combine /// A protocol for retreiving the latest available version of an app. public protocol UpdaterProtocol: ObservableObject { diff --git a/Sources/Packages/Sources/SecretKit/KeychainDictionary.swift b/Sources/Packages/Sources/SecretKit/KeychainDictionary.swift new file mode 100644 index 0000000..460af92 --- /dev/null +++ b/Sources/Packages/Sources/SecretKit/KeychainDictionary.swift @@ -0,0 +1,5 @@ +import Foundation + +public func KeychainDictionary(_ dictionary: [CFString: Any]) -> CFDictionary { + dictionary as CFDictionary +} diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index 13e15e2..8c4784a 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -1,4 +1,5 @@ import Foundation +import Combine import Security import CryptoTokenKit import LocalAuthentication @@ -48,7 +49,7 @@ extension SecureEnclave { throw error.takeRetainedValue() as Error } - let attributes = [ + let attributes = KeychainDictionary([ kSecAttrLabel: name, kSecAttrKeyType: Constants.keyType, kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, @@ -57,7 +58,7 @@ extension SecureEnclave { kSecAttrIsPermanent: true, kSecAttrAccessControl: access ] - ] as CFDictionary + ]) var createKeyError: SecurityError? let keypair = SecKeyCreateRandomKey(attributes, &createKeyError) @@ -72,10 +73,10 @@ extension SecureEnclave { } public func delete(secret: Secret) throws { - let deleteAttributes = [ + let deleteAttributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrApplicationLabel: secret.id as CFData - ] as CFDictionary + ]) let status = SecItemDelete(deleteAttributes) if status != errSecSuccess { throw KeychainError(statusCode: status) @@ -84,14 +85,14 @@ extension SecureEnclave { } public func update(secret: Secret, name: String) throws { - let updateQuery = [ + let updateQuery = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrApplicationLabel: secret.id as CFData - ] as CFDictionary + ]) - let updatedAttributes = [ + let updatedAttributes = KeychainDictionary([ kSecAttrLabel: name, - ] as CFDictionary + ]) let status = SecItemUpdate(updateQuery, updatedAttributes) if status != errSecSuccess { @@ -110,7 +111,7 @@ extension SecureEnclave { context = newContext } context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\"" - let attributes = [ + let attributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrApplicationLabel: secret.id as CFData, @@ -119,7 +120,7 @@ extension SecureEnclave { kSecAttrApplicationTag: Constants.keyTag, kSecUseAuthenticationContext: context, kSecReturnRef: true - ] as CFDictionary + ]) var untyped: CFTypeRef? let status = SecItemCopyMatching(attributes, &untyped) if status != errSecSuccess { @@ -189,7 +190,7 @@ extension SecureEnclave.Store { /// Loads all secrets from the store. private func loadSecrets() { - let publicAttributes = [ + let publicAttributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrKeyType: SecureEnclave.Constants.keyType, kSecAttrApplicationTag: SecureEnclave.Constants.keyTag, @@ -197,11 +198,11 @@ extension SecureEnclave.Store { kSecReturnRef: true, kSecMatchLimit: kSecMatchLimitAll, kSecReturnAttributes: true - ] as CFDictionary + ]) var publicUntyped: CFTypeRef? SecItemCopyMatching(publicAttributes, &publicUntyped) guard let publicTyped = publicUntyped as? [[CFString: Any]] else { return } - let privateAttributes = [ + let privateAttributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrKeyType: SecureEnclave.Constants.keyType, kSecAttrApplicationTag: SecureEnclave.Constants.keyTag, @@ -209,7 +210,7 @@ extension SecureEnclave.Store { kSecReturnRef: true, kSecMatchLimit: kSecMatchLimitAll, kSecReturnAttributes: true - ] as CFDictionary + ]) var privateUntyped: CFTypeRef? SecItemCopyMatching(privateAttributes, &privateUntyped) guard let privateTyped = privateUntyped as? [[CFString: Any]] else { return } @@ -247,7 +248,7 @@ extension SecureEnclave.Store { /// - publicKey: The public key to save. /// - name: A user-facing name for the key. private func savePublicKey(_ publicKey: SecKey, name: String) throws { - let attributes = [ + let attributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrKeyType: SecureEnclave.Constants.keyType, kSecAttrKeyClass: kSecAttrKeyClassPublic, @@ -256,7 +257,7 @@ extension SecureEnclave.Store { kSecAttrIsPermanent: true, kSecReturnData: true, kSecAttrLabel: name - ] as CFDictionary + ]) let status = SecItemAdd(attributes, nil) if status != errSecSuccess { throw SecureEnclave.KeychainError(statusCode: status) diff --git a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift index ef7c23e..28026ce 100644 --- a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift +++ b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift @@ -1,4 +1,5 @@ import Foundation +import Combine import Security import CryptoTokenKit import LocalAuthentication @@ -49,14 +50,14 @@ extension SmartCard { let context = LAContext() context.localizedReason = "sign a request from \"\(provenance.origin.displayName)\" using secret \"\(secret.name)\"" context.localizedCancelTitle = "Deny" - let attributes = [ + let attributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrApplicationLabel: secret.id as CFData, kSecAttrTokenID: tokenID, kSecUseAuthenticationContext: context, kSecReturnRef: true - ] as CFDictionary + ]) var untyped: CFTypeRef? let status = SecItemCopyMatching(attributes, &untyped) if status != errSecSuccess { @@ -136,14 +137,14 @@ extension SmartCard.Store { } } - let attributes = [ + let attributes = KeychainDictionary([ kSecClass: kSecClassKey, kSecAttrTokenID: tokenID, kSecAttrKeyType: kSecAttrKeyTypeEC, // Restrict to EC kSecReturnRef: true, kSecMatchLimit: kSecMatchLimitAll, kSecReturnAttributes: true - ] as CFDictionary + ]) var untyped: CFTypeRef? SecItemCopyMatching(attributes, &untyped) guard let typed = untyped as? [[CFString: Any]] else { return } diff --git a/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift b/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift index ae6af46..cc6cb3b 100644 --- a/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift +++ b/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift @@ -27,7 +27,7 @@ extension Stub { flags, nil) as Any - let attributes = [ + let attributes = KeychainDictionary([ kSecAttrLabel: name, kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits: size, @@ -35,11 +35,10 @@ extension Stub { kSecAttrIsPermanent: true, kSecAttrAccessControl: access ] - ] as CFDictionary + ]) - var privateKey: SecKey! = nil - var publicKey: SecKey! = nil - SecKeyGeneratePair(attributes, &publicKey, &privateKey) + let privateKey = SecKeyCreateRandomKey(attributes, nil)! + let publicKey = SecKeyCopyPublicKey(privateKey)! let publicAttributes = SecKeyCopyAttributes(publicKey) as! [CFString: Any] let privateAttributes = SecKeyCopyAttributes(privateKey) as! [CFString: Any] let publicData = (publicAttributes[kSecValueData] as! Data) @@ -53,11 +52,11 @@ extension Stub { guard !shouldThrow else { throw NSError(domain: "test", code: 0, userInfo: nil) } - let privateKey = SecKeyCreateWithData(secret.privateKey as CFData, [ + let privateKey = SecKeyCreateWithData(secret.privateKey as CFData, KeychainDictionary([ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits: secret.keySize, kSecAttrKeyClass: kSecAttrKeyClassPrivate - ] as CFDictionary + ]) , nil)! let signatureAlgorithm: SecKeyAlgorithm switch secret.keySize {