Factor out some common keychain functionality (#456)

* Factor out some common keychain functionality

* Remove redundant

* Remove redundant
This commit is contained in:
Max Goedjen
2023-03-11 17:58:39 -08:00
committed by GitHub
parent 93e79470b7
commit be58ddd324
8 changed files with 101 additions and 138 deletions

View File

@@ -32,3 +32,9 @@ SecretKit is a collection of protocols describing secrets and stores.
### Authentication Persistence
- ``PersistedAuthenticationContext``
### Errors
- ``KeychainError``
- ``SigningError``
- ``SecurityError``

View File

@@ -1,5 +0,0 @@
import Foundation
public func KeychainDictionary(_ dictionary: [CFString: Any]) -> CFDictionary {
dictionary as CFDictionary
}

View File

@@ -0,0 +1,71 @@
import Foundation
public typealias SecurityError = Unmanaged<CFError>
/// Wraps a Swift dictionary in a CFDictionary.
/// - Parameter dictionary: The Swift dictionary to wrap.
/// - Returns: A CFDictionary containing the keys and values.
public func KeychainDictionary(_ dictionary: [CFString: Any]) -> CFDictionary {
dictionary as CFDictionary
}
public extension CFError {
/// The CFError returned when a verification operation fails.
static let verifyError = CFErrorCreate(nil, NSOSStatusErrorDomain as CFErrorDomain, CFIndex(errSecVerifyFailed), nil)!
/// Equality operation that only considers domain and code.
static func ~=(lhs: CFError, rhs: CFError) -> Bool {
CFErrorGetDomain(lhs) == CFErrorGetDomain(rhs) && CFErrorGetCode(lhs) == CFErrorGetCode(rhs)
}
}
/// A wrapper around an error code reported by a Keychain API.
public struct KeychainError: Error {
/// The status code involved, if one was reported.
public let statusCode: OSStatus?
/// Initializes a KeychainError with an optional error code.
/// - Parameter statusCode: The status code returned by the keychain operation, if one is applicable.
public init(statusCode: OSStatus?) {
self.statusCode = statusCode
}
}
/// A signing-related error.
public struct SigningError: Error {
/// The underlying error reported by the API, if one was returned.
public let error: SecurityError?
/// Initializes a SigningError with an optional SecurityError.
/// - Parameter statusCode: The SecurityError, if one is applicable.
public init(error: SecurityError?) {
self.error = error
}
}
public extension SecretStore {
/// Returns the appropriate keychian signature algorithm to use for a given secret.
/// - Parameters:
/// - secret: The secret which will be used for signing.
/// - allowRSA: Whether or not RSA key types should be permited.
/// - Returns: The appropriate algorithm.
func signatureAlgorithm(for secret: SecretType, allowRSA: Bool = false) -> SecKeyAlgorithm {
switch (secret.algorithm, secret.keySize) {
case (.ellipticCurve, 256):
return .ecdsaSignatureMessageX962SHA256
case (.ellipticCurve, 384):
return .ecdsaSignatureMessageX962SHA384
case (.rsa, 1024), (.rsa, 2048):
guard allowRSA else { fatalError() }
return .rsaSignatureMessagePKCS1v15SHA512
default:
fatalError()
}
}
}

View File

@@ -79,15 +79,3 @@ extension NSNotification.Name {
public static let secretStoreReloaded = NSNotification.Name("com.maxgoedjen.Secretive.secretStore.reloaded")
}
public typealias SecurityError = Unmanaged<CFError>
extension CFError {
public static let verifyError = CFErrorCreate(nil, NSOSStatusErrorDomain as CFErrorDomain, CFIndex(errSecVerifyFailed), nil)!
static public func ~=(lhs: CFError, rhs: CFError) -> Bool {
CFErrorGetDomain(lhs) == CFErrorGetDomain(rhs) && CFErrorGetCode(lhs) == CFErrorGetCode(rhs)
}
}