mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-04-10 17:47:19 +00:00
Expose verify as public api
This commit is contained in:
parent
7adc5da26f
commit
49306b9457
@ -10,6 +10,7 @@ public class AnySecretStore: SecretStore {
|
|||||||
private let _name: () -> String
|
private let _name: () -> String
|
||||||
private let _secrets: () -> [AnySecret]
|
private let _secrets: () -> [AnySecret]
|
||||||
private let _sign: (Data, AnySecret, SigningRequestProvenance) throws -> Data
|
private let _sign: (Data, AnySecret, SigningRequestProvenance) throws -> Data
|
||||||
|
private let _verify: (Data, Data, AnySecret) throws -> Bool
|
||||||
private let _existingPersistedAuthenticationContext: (AnySecret) -> PersistedAuthenticationContext?
|
private let _existingPersistedAuthenticationContext: (AnySecret) -> PersistedAuthenticationContext?
|
||||||
private let _persistAuthentication: (AnySecret, TimeInterval) throws -> Void
|
private let _persistAuthentication: (AnySecret, TimeInterval) throws -> Void
|
||||||
private let _reloadSecrets: () -> Void
|
private let _reloadSecrets: () -> Void
|
||||||
@ -23,6 +24,7 @@ public class AnySecretStore: SecretStore {
|
|||||||
_id = { secretStore.id }
|
_id = { secretStore.id }
|
||||||
_secrets = { secretStore.secrets.map { AnySecret($0) } }
|
_secrets = { secretStore.secrets.map { AnySecret($0) } }
|
||||||
_sign = { try secretStore.sign(data: $0, with: $1.base as! SecretStoreType.SecretType, for: $2) }
|
_sign = { try secretStore.sign(data: $0, with: $1.base as! SecretStoreType.SecretType, for: $2) }
|
||||||
|
_verify = { try secretStore.verify(data: $0, signature: $1, with: $2.base as! SecretStoreType.SecretType) }
|
||||||
_existingPersistedAuthenticationContext = { secretStore.existingPersistedAuthenticationContext(secret: $0.base as! SecretStoreType.SecretType) }
|
_existingPersistedAuthenticationContext = { secretStore.existingPersistedAuthenticationContext(secret: $0.base as! SecretStoreType.SecretType) }
|
||||||
_persistAuthentication = { try secretStore.persistAuthentication(secret: $0.base as! SecretStoreType.SecretType, forDuration: $1) }
|
_persistAuthentication = { try secretStore.persistAuthentication(secret: $0.base as! SecretStoreType.SecretType, forDuration: $1) }
|
||||||
_reloadSecrets = { secretStore.reloadSecrets() }
|
_reloadSecrets = { secretStore.reloadSecrets() }
|
||||||
@ -51,6 +53,10 @@ public class AnySecretStore: SecretStore {
|
|||||||
try _sign(data, secret, provenance)
|
try _sign(data, secret, provenance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func verify(data: Data, signature: Data, with secret: AnySecret) throws -> Bool {
|
||||||
|
try _verify(data, signature, secret)
|
||||||
|
}
|
||||||
|
|
||||||
public func existingPersistedAuthenticationContext(secret: AnySecret) -> PersistedAuthenticationContext? {
|
public func existingPersistedAuthenticationContext(secret: AnySecret) -> PersistedAuthenticationContext? {
|
||||||
_existingPersistedAuthenticationContext(secret)
|
_existingPersistedAuthenticationContext(secret)
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,14 @@ public protocol SecretStore: ObservableObject, Identifiable {
|
|||||||
/// - Returns: The signed data.
|
/// - Returns: The signed data.
|
||||||
func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data
|
func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data
|
||||||
|
|
||||||
|
/// Verifies that a signature is valid over a specified payload.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - data: The data to verify the signature of.
|
||||||
|
/// - signature: The signature over the data.
|
||||||
|
/// - secret: The secret whose signature to verify.
|
||||||
|
/// - Returns: Whether the signature was verified.
|
||||||
|
func verify(data: Data, signature: Data, with secret: SecretType) throws -> Bool
|
||||||
|
|
||||||
/// Checks to see if there is currently a valid persisted authentication for a given secret.
|
/// Checks to see if there is currently a valid persisted authentication for a given secret.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - secret: The ``Secret`` to check if there is a persisted authentication for.
|
/// - secret: The ``Secret`` to check if there is a persisted authentication for.
|
||||||
|
@ -101,7 +101,7 @@ extension SecureEnclave {
|
|||||||
reloadSecretsInternal()
|
reloadSecretsInternal()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data {
|
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data {
|
||||||
let context: LAContext
|
let context: LAContext
|
||||||
if let existing = persistedAuthenticationContexts[secret], existing.valid {
|
if let existing = persistedAuthenticationContexts[secret], existing.valid {
|
||||||
context = existing.context
|
context = existing.context
|
||||||
@ -138,6 +138,37 @@ extension SecureEnclave {
|
|||||||
return signature as Data
|
return signature as Data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func verify(data: Data, signature: Data, with secret: Secret) throws -> Bool {
|
||||||
|
let context = LAContext()
|
||||||
|
context.localizedReason = "verify a signature using secret \"\(secret.name)\""
|
||||||
|
context.localizedCancelTitle = "Deny"
|
||||||
|
let attributes = KeychainDictionary([
|
||||||
|
kSecClass: kSecClassKey,
|
||||||
|
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||||
|
kSecAttrApplicationLabel: secret.id as CFData,
|
||||||
|
kSecAttrKeyType: Constants.keyType,
|
||||||
|
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
|
||||||
|
kSecAttrApplicationTag: Constants.keyTag,
|
||||||
|
kSecUseAuthenticationContext: context,
|
||||||
|
kSecReturnRef: true
|
||||||
|
])
|
||||||
|
var verifyError: SecurityError?
|
||||||
|
var untyped: CFTypeRef?
|
||||||
|
let status = SecItemCopyMatching(attributes, &untyped)
|
||||||
|
if status != errSecSuccess {
|
||||||
|
throw KeychainError(statusCode: status)
|
||||||
|
}
|
||||||
|
guard let untypedSafe = untyped else {
|
||||||
|
throw KeychainError(statusCode: errSecSuccess)
|
||||||
|
}
|
||||||
|
let key = untypedSafe as! SecKey
|
||||||
|
let signature = SecKeyVerifySignature(key, .ecdsaSignatureMessageX962SHA256, data as CFData, signature as CFData, &verifyError)
|
||||||
|
if !signature {
|
||||||
|
throw SigningError(error: verifyError)
|
||||||
|
}
|
||||||
|
return signature
|
||||||
|
}
|
||||||
|
|
||||||
public func existingPersistedAuthenticationContext(secret: Secret) -> PersistedAuthenticationContext? {
|
public func existingPersistedAuthenticationContext(secret: Secret) -> PersistedAuthenticationContext? {
|
||||||
guard let persisted = persistedAuthenticationContexts[secret], persisted.valid else { return nil }
|
guard let persisted = persistedAuthenticationContexts[secret], persisted.valid else { return nil }
|
||||||
return persisted
|
return persisted
|
||||||
|
@ -40,6 +40,10 @@ extension Preview {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verify(data: Data, signature: Data, with secret: Preview.Secret) throws -> Bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
func existingPersistedAuthenticationContext(secret: Preview.Secret) -> PersistedAuthenticationContext? {
|
func existingPersistedAuthenticationContext(secret: Preview.Secret) -> PersistedAuthenticationContext? {
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user