This commit is contained in:
Max Goedjen 2022-12-18 17:01:07 -08:00
parent eaee8aaaa2
commit 4171a7264d
No known key found for this signature in database
6 changed files with 30 additions and 34 deletions

View File

@ -22,7 +22,7 @@ public class Agent {
logger.debug("Agent is running")
self.storeList = storeList
self.witness = witness
certificateHandler.reloadCertificates(for: storeList.stores.flatMap(\.secrets))
certificateHandler.reloadCertificates(for: storeList.allSecrets)
}
}
@ -67,9 +67,6 @@ extension Agent {
response.append(SSHAgent.ResponseType.agentSignResponse.data)
response.append(try sign(data: data, provenance: provenance))
logger.debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)")
case .addIdentity:
try addIdentity(data: data)
response.append(SSHAgent.ResponseType.agentSuccess.data)
}
} catch {
response.removeAll()
@ -87,7 +84,8 @@ extension Agent {
/// Lists the identities available for signing operations
/// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations.
func identities() -> Data {
let secrets = storeList.stores.flatMap(\.secrets)
let secrets = storeList.allSecrets
certificateHandler.reloadCertificates(for: secrets)
var count = UInt32(secrets.count).bigEndian
let countData = Data(bytes: &count, count: UInt32.bitWidth/8)
var keyData = Data()
@ -188,18 +186,6 @@ extension Agent {
return signedData
}
/// Stub for the ssh-add operation, which reloads from the store and reloads any OpenSSH certificate public keys.
/// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations.
func addIdentity(data: Data) throws {
// FIXME: This
// guard isCertificate else throw { AgentError.notOpenSSHCertificate }
// FIXME: READ REAL SECRET HASH
// let secret = secret(matching: hash)
let secret = AnySecret(storeList.stores.first!.secrets.first!)
try certificateHandler.copyCertificate(data: data, for: secret)
print(data)
}
}
extension Agent {

View File

@ -10,7 +10,6 @@ extension SSHAgent {
case requestIdentities = 11
case signRequest = 13
case addIdentity = 17
public var debugDescription: String {
switch self {
@ -18,8 +17,6 @@ extension SSHAgent {
return "RequestIdentities"
case .signRequest:
return "SignRequest"
case .addIdentity:
return "AddIdentity"
}
}
}

View File

@ -16,23 +16,20 @@ public class OpenSSHCertificateHandler {
/// Reloads any certificates in the PublicKeys folder.
/// - Parameter secrets: the secrets to look up corresponding certificates for.
public func reloadCertificates(for secrets: [AnySecret]) {
guard publicKeyFileStoreController.hasAnyCertificates else {
logger.log("No certificates, short circuiting")
return
}
keyBlobsAndNames = secrets.reduce(into: [:]) { partialResult, next in
partialResult[next] = try? loadKeyblobAndName(for: next)
}
}
/// Copies a certificate to the PublicKeys folder, if it's not already tehre.
/// - Parameter url: the URL of the certificate to copy.
public func copyCertificate(data: Data, for secret: AnySecret) throws {
try data.write(to: URL(fileURLWithPath: publicKeyFileStoreController.sshCertificatePath(for: secret))
)
}
/// Whether or not the certificate handler has a certifiicate associated with a given secret.
/// - Parameter secret: The secret to check for a certificate.
/// - Returns: A boolean describing whether or not the certificate handler has a certifiicate associated with a given secret
public func hasCertificate(for secret: AnySecret) -> Bool {
keyBlobsAndNames[secret] != nil
public func hasCertificate<SecretType: Secret>(for secret: SecretType) -> Bool {
keyBlobsAndNames[AnySecret(secret)] != nil
}
@ -63,14 +60,14 @@ public class OpenSSHCertificateHandler {
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
/// - Parameter secret: The secret to search for a certificate with
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
public func keyBlobAndName(for secret: AnySecret) throws -> (Data, Data)? {
keyBlobsAndNames[secret]
public func keyBlobAndName<SecretType: Secret>(for secret: SecretType) throws -> (Data, Data)? {
keyBlobsAndNames[AnySecret(secret)]
}
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
/// - Parameter secret: The secret to search for a certificate with
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
private func loadKeyblobAndName(for secret: AnySecret) throws -> (Data, Data)? {
private func loadKeyblobAndName<SecretType: Secret>(for secret: SecretType) throws -> (Data, Data)? {
let certificatePath = publicKeyFileStoreController.sshCertificatePath(for: secret)
guard FileManager.default.fileExists(atPath: certificatePath) else {
return nil

View File

@ -45,6 +45,18 @@ public class PublicKeyFileStoreController {
return directory.appending("/").appending("\(minimalHex).pub")
}
/// Short-circuit check to ship enumerating a bunch of paths if there's nothing in the cert directory.
public var hasAnyCertificates: Bool {
do {
return try FileManager.default
.contentsOfDirectory(atPath: directory)
.filter { $0.hasSuffix("-cert.pub") }
.isEmpty == false
} catch {
return false
}
}
/// The path for a Secret's SSH Certificate public key.
/// - Parameter secret: The Secret to return the path for.
/// - Returns: The path to the SSH Certificate public key.

View File

@ -31,6 +31,10 @@ public class SecretStoreList: ObservableObject {
stores.reduce(false, { $0 || $1.isAvailable })
}
public var allSecrets: [AnySecret] {
stores.flatMap(\.secrets)
}
}
extension SecretStoreList {

View File

@ -34,9 +34,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
self.socketController.handler = self.agent.handle(reader:writer:)
}
NotificationCenter.default.addObserver(forName: .secretStoreReloaded, object: nil, queue: .main) { [self] _ in
try? publicKeyFileStoreController.generatePublicKeys(for: storeList.stores.flatMap({ $0.secrets }), clear: true)
try? publicKeyFileStoreController.generatePublicKeys(for: storeList.allSecrets, clear: true)
}
try? publicKeyFileStoreController.generatePublicKeys(for: storeList.stores.flatMap({ $0.secrets }), clear: true)
try? publicKeyFileStoreController.generatePublicKeys(for: storeList.allSecrets, clear: true)
notifier.prompt()
updateSink = updater.$update.sink { update in
guard let update = update else { return }