Request Attribution (#59)
This commit is contained in:
parent
4b66e874a7
commit
2b5fdf541d
|
@ -14,7 +14,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}()
|
||||
let notifier = Notifier()
|
||||
lazy var agent: Agent = {
|
||||
Agent(storeList: storeList/*, notifier: notifier*/)
|
||||
Agent(storeList: storeList, witness: notifier)
|
||||
}()
|
||||
lazy var socketController: SocketController = {
|
||||
let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String
|
||||
|
|
|
@ -11,11 +11,11 @@ class Notifier {
|
|||
}
|
||||
}
|
||||
|
||||
func notify(accessTo secret: AnySecret) {
|
||||
func notify(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) {
|
||||
let notificationCenter = UNUserNotificationCenter.current()
|
||||
let notificationContent = UNMutableNotificationContent()
|
||||
notificationContent.title = "Signed Request"
|
||||
notificationContent.body = "\(secret.name) was used to sign a request."
|
||||
notificationContent.body = "\(secret.name) was used to sign a request from \(provenance.origin.name)."
|
||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
|
||||
notificationCenter.add(request, withCompletionHandler: nil)
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ class Notifier {
|
|||
|
||||
extension Notifier: SigningWitness {
|
||||
|
||||
func witness(accessTo secret: AnySecret) throws {
|
||||
notify(accessTo: secret)
|
||||
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
|
||||
notify(accessTo: secret, by: provenance)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,12 +2,15 @@ import Foundation
|
|||
import CryptoKit
|
||||
import OSLog
|
||||
import SecretKit
|
||||
import SecretAgentKit
|
||||
import AppKit
|
||||
|
||||
public class Agent {
|
||||
|
||||
fileprivate let storeList: SecretStoreList
|
||||
fileprivate let witness: SigningWitness?
|
||||
fileprivate let writer = OpenSSHKeyWriter()
|
||||
fileprivate let requestTracer = SigningRequestTracer()
|
||||
|
||||
public init(storeList: SecretStoreList, witness: SigningWitness? = nil) {
|
||||
os_log(.debug, "Agent is running")
|
||||
|
@ -40,7 +43,7 @@ extension Agent {
|
|||
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)
|
||||
case .signRequest:
|
||||
response.append(SSHAgent.ResponseType.agentSignResponse.data)
|
||||
response.append(try sign(data: data))
|
||||
response.append(try sign(data: data, from: fileHandle.fileDescriptor))
|
||||
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription)
|
||||
}
|
||||
} catch {
|
||||
|
@ -74,7 +77,7 @@ extension Agent {
|
|||
return countData + keyData
|
||||
}
|
||||
|
||||
func sign(data: Data) throws -> Data {
|
||||
func sign(data: Data, from pid: Int32) throws -> Data {
|
||||
let reader = OpenSSHReader(data: data)
|
||||
let hash = try reader.readNextChunk()
|
||||
guard let (store, secret) = secret(matching: hash) else {
|
||||
|
@ -82,8 +85,9 @@ extension Agent {
|
|||
throw AgentError.noMatchingKey
|
||||
}
|
||||
|
||||
let provenance = requestTracer.provenance(from: pid)
|
||||
if let witness = witness {
|
||||
try witness.witness(accessTo: secret)
|
||||
try witness.witness(accessTo: secret, by: provenance)
|
||||
}
|
||||
|
||||
let dataToSign = try reader.readNextChunk()
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import Foundation
|
||||
import AppKit
|
||||
|
||||
public struct SigningRequestProvenance {
|
||||
|
||||
public var chain: [Process]
|
||||
public init(root: Process) {
|
||||
self.chain = [root]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SigningRequestProvenance {
|
||||
|
||||
public var origin: Process {
|
||||
chain.last!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SigningRequestProvenance {
|
||||
|
||||
public struct Process {
|
||||
|
||||
public let pid: Int32
|
||||
public let name: String
|
||||
public let path: String
|
||||
let parentPID: Int32?
|
||||
|
||||
init(pid: Int32, name: String, path: String, parentPID: Int32?) {
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
self.path = path
|
||||
self.parentPID = parentPID
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import Foundation
|
||||
import AppKit
|
||||
|
||||
struct SigningRequestTracer {
|
||||
|
||||
func provenance(from pid: Int32) -> SigningRequestProvenance {
|
||||
let pidPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
|
||||
var len = socklen_t(MemoryLayout<Int32>.size)
|
||||
getsockopt(pid, SOCK_STREAM, LOCAL_PEERPID, pidPointer, &len)
|
||||
let pid = pidPointer.load(as: Int32.self)
|
||||
let firstInfo = process(from: pid)
|
||||
|
||||
var provenance = SigningRequestProvenance(root: firstInfo)
|
||||
while NSRunningApplication(processIdentifier: provenance.origin.pid) == nil && provenance.origin.parentPID != nil {
|
||||
provenance.chain.append(process(from: provenance.origin.parentPID!))
|
||||
}
|
||||
return provenance
|
||||
}
|
||||
|
||||
func pidAndNameInfo(from pid: Int32) -> kinfo_proc {
|
||||
var len = MemoryLayout<kinfo_proc>.size
|
||||
let infoPointer = UnsafeMutableRawPointer.allocate(byteCount: len, alignment: 1)
|
||||
var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, pid]
|
||||
sysctl(&name, UInt32(name.count), infoPointer, &len, nil, 0)
|
||||
return infoPointer.load(as: kinfo_proc.self)
|
||||
}
|
||||
|
||||
func process(from pid: Int32) -> SigningRequestProvenance.Process {
|
||||
var pidAndNameInfo = self.pidAndNameInfo(from: pid)
|
||||
let ppid = pidAndNameInfo.kp_eproc.e_ppid != 0 ? pidAndNameInfo.kp_eproc.e_ppid : nil
|
||||
let procName = String(cString: &pidAndNameInfo.kp_proc.p_comm.0)
|
||||
return SigningRequestProvenance.Process(pid: pid, name: procName, path: "", parentPID: ppid)
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,6 @@ import SecretKit
|
|||
|
||||
public protocol SigningWitness {
|
||||
|
||||
func witness(accessTo secret: AnySecret) throws
|
||||
func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; };
|
||||
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; };
|
||||
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.swift */; };
|
||||
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; };
|
||||
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; };
|
||||
508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
|
||||
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
|
||||
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; };
|
||||
|
@ -203,6 +205,8 @@
|
|||
50731665241DF8660023809E /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
|
||||
50731668241E00C20023809E /* NoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeView.swift; sourceTree = "<group>"; };
|
||||
507CE4EF2420A4C50029F750 /* SigningWitness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningWitness.swift; sourceTree = "<group>"; };
|
||||
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestProvenance.swift; sourceTree = "<group>"; };
|
||||
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigningRequestTracer.swift; sourceTree = "<group>"; };
|
||||
508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = "<group>"; };
|
||||
508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; };
|
||||
|
@ -468,6 +472,8 @@
|
|||
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */,
|
||||
50A3B79D24026B9900D209EA /* SocketController.swift */,
|
||||
507CE4EF2420A4C50029F750 /* SigningWitness.swift */,
|
||||
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
|
||||
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */,
|
||||
50A3B79F24026B9900D209EA /* Agent.swift */,
|
||||
5099A06F240242BA0062B6F2 /* Info.plist */,
|
||||
);
|
||||
|
@ -850,6 +856,8 @@
|
|||
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */,
|
||||
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */,
|
||||
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */,
|
||||
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */,
|
||||
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue