From fb6cebe92f26eb0681f69403344c9bb6dbe9f12d Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sat, 1 Jan 2022 18:39:21 -0800 Subject: [PATCH] Add docs (#309) --- .../Documentation.docc/Documentation.md | 3 ++ .../SecureEnclave.swift | 1 + .../SecureEnclaveSecret.swift | 1 + .../SecureEnclaveStore.swift | 30 +++++++++++++++---- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 Sources/Packages/Sources/SecureEnclaveSecretKit/Documentation.docc/Documentation.md diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/Documentation.docc/Documentation.md b/Sources/Packages/Sources/SecureEnclaveSecretKit/Documentation.docc/Documentation.md new file mode 100644 index 0000000..1a1f46b --- /dev/null +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/Documentation.docc/Documentation.md @@ -0,0 +1,3 @@ +# ````SecureEnclaveSecretKit```` + +SecureEnclaveSecretKit contains implementations of SecretKit protocols backed by the Secure Enclave. diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclave.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclave.swift index 5955575..6d4c78f 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclave.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclave.swift @@ -1 +1,2 @@ +/// Namespace for the Secure Enclave implementations. public enum SecureEnclave {} diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift index b64e266..c8a87ba 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift @@ -4,6 +4,7 @@ import SecretKit extension SecureEnclave { + /// An implementation of Secret backed by the Secure Enclave. public struct Secret: SecretKit.Secret { public let id: Data diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index 9e2fb95..af6b364 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -6,6 +6,7 @@ import SecretKit extension SecureEnclave { + /// An implementation of Store backed by the Secure Enclave. public class Store: SecretStoreModifiable { public var isAvailable: Bool { @@ -20,6 +21,7 @@ extension SecureEnclave { private var persistedAuthenticationContexts: [Secret: PersistentAuthenticationContext] = [:] + /// Initializes a Store. public init() { DistributedNotificationCenter.default().addObserver(forName: .secretStoreUpdated, object: nil, queue: .main) { _ in self.reloadSecrets(notify: false) @@ -97,6 +99,7 @@ extension SecureEnclave { } reloadSecrets() } + public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> SignedData { let context: LAContext if let existing = persistedAuthenticationContexts[secret], existing.valid { @@ -140,10 +143,6 @@ extension SecureEnclave { return SignedData(data: signature as Data, requiredAuthentication: requiredAuthentication) } - /// <#Description#> - /// - Parameters: - /// - secret: <#secret description#> - /// - duration: <#duration description#> public func persistAuthentication(secret: Secret, forDuration duration: TimeInterval) throws { let newContext = LAContext() newContext.touchIDAuthenticationAllowableReuseDuration = duration @@ -171,6 +170,8 @@ extension SecureEnclave { extension SecureEnclave.Store { + /// Reloads all secrets from the store. + /// - Parameter notify: A boolean indicating whether a distributed notification should be posted, notifying other processes (ie, the SecretAgent) to reload their stores as well. private func reloadSecrets(notify: Bool = true) { secrets.removeAll() loadSecrets() @@ -179,6 +180,7 @@ extension SecureEnclave.Store { } } + /// Loads all secrets from the store. private func loadSecrets() { let attributes = [ kSecClass: kSecClassKey, @@ -203,6 +205,10 @@ extension SecureEnclave.Store { secrets.append(contentsOf: wrapped) } + /// Saves a public key. + /// - Parameters: + /// - publicKey: The public key to save. + /// - name: A user-facing name for the key. private func savePublicKey(_ publicKey: SecKey, name: String) throws { let attributes = [ kSecClass: kSecClassKey, @@ -224,11 +230,15 @@ extension SecureEnclave.Store { extension SecureEnclave { + /// 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? } + /// A signing-related error. public struct SigningError: Error { + /// The underlying error reported by the API, if one was returned. public let error: SecurityError? } @@ -252,13 +262,22 @@ extension SecureEnclave { extension SecureEnclave { + /// A context describing a persisted authentication. private struct PersistentAuthenticationContext { + /// The Secret to persist authentication for. let secret: Secret + /// The LAContext used to authorize the persistent context. let context: LAContext - // Monotonic time instead of Date() to prevent people setting the clock back. + /// An expiration date for the context. + /// - Note - Monotonic time instead of Date() to prevent people setting the clock back. let expiration: UInt64 + /// Initializes a context. + /// - Parameters: + /// - secret: The Secret to persist authentication for. + /// - context: The LAContext used to authorize the persistent context. + /// - duration: The duration of the authorization context, in seconds. init(secret: Secret, context: LAContext, duration: TimeInterval) { self.secret = secret self.context = context @@ -266,6 +285,7 @@ extension SecureEnclave { self.expiration = clock_gettime_nsec_np(CLOCK_MONOTONIC) + UInt64(durationInNanoSeconds) } + /// A boolean describing whether or not the context is still valid. var valid: Bool { clock_gettime_nsec_np(CLOCK_MONOTONIC) < expiration }