This commit is contained in:
Max Goedjen
2026-09-07 12:49:44 -07:00
39 changed files with 1961 additions and 293 deletions
@@ -13,7 +13,7 @@ import CertificateKit
@Test func emptyStores() async throws {
let agent = Agent(storeList: SecretStoreList(), certificateStore: CertificateStore())
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestIdentities)
let response = await agent.handle(request: request, provenance: .test)
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
#expect(response == Constants.Responses.requestIdentitiesEmpty)
}
@@ -21,7 +21,7 @@ import CertificateKit
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let agent = Agent(storeList: list, certificateStore: CertificateStore())
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestIdentities)
let response = await agent.handle(request: request, provenance: .test)
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
let actual = OpenSSHReader(data: response)
let expected = OpenSSHReader(data: Constants.Responses.requestIdentitiesMultiple)
@@ -35,7 +35,7 @@ import CertificateKit
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let agent = Agent(storeList: list, certificateStore: CertificateStore())
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignatureWithNoneMatching)
let response = await agent.handle(request: request, provenance: .test)
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
#expect(response == Constants.Responses.requestFailure)
}
@@ -44,7 +44,7 @@ import CertificateKit
guard case SSHAgent.Request.signRequest(let context) = request else { return }
let list = await storeList(with: [Constants.Secrets.ecdsa256Secret, Constants.Secrets.ecdsa384Secret])
let agent = Agent(storeList: list, certificateStore: CertificateStore())
let response = await agent.handle(request: request, provenance: .test)
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
let responseReader = OpenSSHReader(data: response)
let length = try responseReader.readNextBytes(as: UInt32.self)
let type = try responseReader.readNextBytes(as: UInt8.self)
@@ -68,7 +68,7 @@ import CertificateKit
let signature = try P256.Signing.ECDSASignature(rawRepresentation: rs)
// Correct signature
#expect(try P256.Signing.PublicKey(x963Representation: Constants.Secrets.ecdsa256Secret.publicKey)
.isValidSignature(signature, for: context.dataToSign))
.isValidSignature(signature, for: context.dataToSign.raw))
}
// MARK: Witness protocol
@@ -79,7 +79,7 @@ import CertificateKit
return true
}, witness: { _, _ in })
let agent = Agent(storeList: list, certificateStore: CertificateStore(), witness: witness)
let response = await agent.handle(request: .signRequest(.empty), provenance: .test)
let response = await agent.handle(request: .signRequest(.empty), provenance: .test, hosts: nil)
#expect(response == Constants.Responses.requestFailure)
}
@@ -93,7 +93,7 @@ import CertificateKit
})
let agent = Agent(storeList: list, certificateStore: CertificateStore(), witness: witness)
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
_ = await agent.handle(request: request, provenance: .test)
_ = await agent.handle(request: request, provenance: .test, hosts: nil)
#expect(witnessed)
}
@@ -109,7 +109,7 @@ import CertificateKit
})
let agent = Agent(storeList: list, certificateStore: CertificateStore(), witness: witness)
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
_ = await agent.handle(request: request, provenance: .test)
_ = await agent.handle(request: request, provenance: .test, hosts: nil)
#expect(witnessTrace == speakNowTrace)
#expect(witnessTrace == .test)
}
@@ -122,7 +122,7 @@ import CertificateKit
store.shouldThrow = true
let agent = Agent(storeList: list, certificateStore: CertificateStore())
let request = try SSHAgentInputParser().parse(data: Constants.Requests.requestSignature)
let response = await agent.handle(request: request, provenance: .test)
let response = await agent.handle(request: request, provenance: .test, hosts: nil)
#expect(response == Constants.Responses.requestFailure)
}
@@ -130,7 +130,7 @@ import CertificateKit
@Test func unhandledAdd() async throws {
let agent = Agent(storeList: SecretStoreList(), certificateStore: CertificateStore())
let response = await agent.handle(request: .addIdentity, provenance: .test)
let response = await agent.handle(request: .addIdentity, provenance: .test, hosts: nil)
#expect(response == Constants.Responses.requestFailure)
}
@@ -2,6 +2,7 @@ import Foundation
import SecretKit
import CryptoKit
import SSHProtocolKit
import LocalAuthentication
struct Stub {}
@@ -49,7 +50,7 @@ extension Stub {
print("Public Key OpenSSH: \(OpenSSHPublicKeyWriter().openSSHString(secret: secret))")
}
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance, context: AuthenticationContextProtocol?) throws -> Data {
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance, target: SigningRequestTarget?, context: LAContext?) throws -> Data {
guard !shouldThrow else {
throw NSError(domain: "test", code: 0, userInfo: nil)
}
@@ -57,13 +58,6 @@ extension Stub {
return try privateKey.signature(for: data).rawRepresentation
}
public func existingAuthenticationContextProtocol(secret: Stub.Secret) -> AuthenticationContextProtocol? {
nil
}
public func persistAuthentication(secret: Stub.Secret, forDuration duration: TimeInterval) throws {
}
public func reloadSecrets() {
}
@@ -10,14 +10,14 @@ struct StubWitness {
extension StubWitness: SigningWitness {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, from store: AnySecretStore, by provenance: SigningRequestProvenance) throws {
func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, from store: AnySecretStore, by provenance: SigningRequestProvenance, target: SigningRequestTarget?) throws {
let objection = speakNow(secret, provenance)
if objection {
throw TheresMyChance()
}
}
func witness(accessTo secret: AnySecret, from store: AnySecretStore, by provenance: SigningRequestProvenance) throws {
func witness(accessTo secret: AnySecret, from store: AnySecretStore, by provenance: SigningRequestProvenance, target: SigningRequestTarget?) throws {
witness(secret, provenance)
}