From 56cc559a97e1058db208af85f9f2fbddb972b826 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sat, 1 Jan 2022 17:54:40 -0800 Subject: [PATCH] Docs --- .../SecretKit/OpenSSH/OpenSSHReader.swift | 5 ++++ .../Sources/SecretKit/Types/SecretStore.swift | 27 +++++++++++++++++++ .../Sources/SecretKit/Types/SignedData.swift | 7 +++++ .../Types/SigningRequestProvenance.swift | 23 ++++++++++++++++ .../SecureEnclaveStore.swift | 5 +++- 5 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHReader.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHReader.swift index 5e89055..89ae564 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHReader.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHReader.swift @@ -1,13 +1,18 @@ import Foundation +/// Reads OpenSSH protocol data. public class OpenSSHReader { var remaining: Data + /// Initialize the reader with an OpenSSH data payload. + /// - Parameter data: the data to read. public init(data: Data) { remaining = Data(data) } + /// Reads the next chunk of data from the playload. + /// - Returns: The next chunk of data. public func readNextChunk() -> Data { let lengthRange = 0..<(UInt32.bitWidth/8) let lengthChunk = remaining[lengthRange] diff --git a/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift b/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift index 2f835c8..6f35e3f 100644 --- a/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift +++ b/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift @@ -1,25 +1,52 @@ import Foundation import Combine +/// Manages access to Secrets, and performs signature operations on data using those Secrets. public protocol SecretStore: ObservableObject, Identifiable { associatedtype SecretType: Secret + /// A boolean indicating whether or not the store is available. var isAvailable: Bool { get } + /// A unique identifier for the store. var id: UUID { get } + /// A user-facing name for the store. var name: String { get } + /// The secrets the store manages. var secrets: [SecretType] { get } + /// Signs a data payload with a specified Secret. + /// - Parameters: + /// - data: The data to sign. + /// - secret: The ``Secret`` to sign with. + /// - provenance: A ``SigningRequestProvenance`` describing where the request came from. + /// - Returns: A ``SignedData`` object, containing the signature and metadata about the signature process. func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> SignedData + /// Persists user authorization for access to a secret. + /// - Parameters: + /// - secret: The ``Secret`` to persist the authorization for. + /// - duration: The duration that the authorization should persist for. + /// - Note: This is used for temporarily unlocking access to a secret which would otherwise require authentication every single use. This is useful for situations where the user anticipates several rapid accesses to a authorization-guarded secret. func persistAuthentication(secret: SecretType, forDuration duration: TimeInterval) throws } +/// A SecretStore that the Secretive admin app can modify. public protocol SecretStoreModifiable: SecretStore { + /// Creates a new ``Secret`` in the store. + /// - Parameters: + /// - name: The user-facing name for the ``Secret``. + /// - requiresAuthentication: A boolean indicating whether or not the user will be required to authenticate before performing signature operations with the secret. func create(name: String, requiresAuthentication: Bool) throws + + /// Deletes a Secret in the store. + /// - Parameters: + /// - secret: The ``Secret`` to delete. func delete(secret: SecretType) throws + + func update(secret: SecretType, name: String) throws } diff --git a/Sources/Packages/Sources/SecretKit/Types/SignedData.swift b/Sources/Packages/Sources/SecretKit/Types/SignedData.swift index bcaf171..1468867 100644 --- a/Sources/Packages/Sources/SecretKit/Types/SignedData.swift +++ b/Sources/Packages/Sources/SecretKit/Types/SignedData.swift @@ -1,10 +1,17 @@ import Foundation +/// Describes the output of a sign request. public struct SignedData { + /// The signed data. public let data: Data + /// A boolean describing whether authentication was required during the signature process. public let requiredAuthentication: Bool + /// Initializes a new SignedData. + /// - Parameters: + /// - data: The signed data. + /// - requiredAuthentication: A boolean describing whether authentication was required during the signature process. public init(data: Data, requiredAuthentication: Bool) { self.data = data self.requiredAuthentication = requiredAuthentication diff --git a/Sources/Packages/Sources/SecretKit/Types/SigningRequestProvenance.swift b/Sources/Packages/Sources/SecretKit/Types/SigningRequestProvenance.swift index 271c8c0..a1095fd 100644 --- a/Sources/Packages/Sources/SecretKit/Types/SigningRequestProvenance.swift +++ b/Sources/Packages/Sources/SecretKit/Types/SigningRequestProvenance.swift @@ -1,8 +1,11 @@ import Foundation import AppKit +/// Describes the chain of applications that requested a signature operation. public struct SigningRequestProvenance: Equatable { + /// A list of processes involved in the request. + /// - Note: A chain will typically consist of many elements even for a simple request. For example, running `git fetch` in Terminal.app would generate a request chain of `ssh` -> `git` -> `zsh` -> `login` -> `Terminal.app` public var chain: [Process] public init(root: Process) { self.chain = [root] @@ -12,10 +15,12 @@ public struct SigningRequestProvenance: Equatable { extension SigningRequestProvenance { + /// The `Process` which initiated the signing request. public var origin: Process { chain.last! } + /// A boolean describing whether all processes in the request chain had a valid code signature. public var intact: Bool { chain.allSatisfy { $0.validSignature } } @@ -24,16 +29,33 @@ extension SigningRequestProvenance { extension SigningRequestProvenance { + /// Describes a process in a `SigningRequestProvenance` chain. public struct Process: Equatable { + /// The pid of the process. public let pid: Int32 + /// A user-facing name for the process. public let processName: String + /// A user-facing name for the application, if one exists. public let appName: String? + /// An icon representation of the application, if one exists. public let iconURL: URL? + /// The path the process exists at. public let path: String + /// A boolean describing whether or not the process has a valid code signature. public let validSignature: Bool + /// The pid of the process's parent. public let parentPID: Int32? + /// Initializes a Process. + /// - Parameters: + /// - pid: The pid of the process. + /// - processName: A user-facing name for the process. + /// - appName: A user-facing name for the application, if one exists. + /// - iconURL: An icon representation of the application, if one exists. + /// - path: The path the process exists at. + /// - validSignature: A boolean describing whether or not the process has a valid code signature. + /// - parentPID: The pid of the process's parent. public init(pid: Int32, processName: String, appName: String?, iconURL: URL?, path: String, validSignature: Bool, parentPID: Int32?) { self.pid = pid self.processName = processName @@ -44,6 +66,7 @@ extension SigningRequestProvenance { self.parentPID = parentPID } + /// The best user-facing name to display for the process. public var displayName: String { appName ?? processName } diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index c50ccf2..9e2fb95 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -97,7 +97,6 @@ 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 { @@ -141,6 +140,10 @@ 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