Request Attribution (#59)

This commit is contained in:
Max Goedjen 2020-03-17 00:56:55 -07:00 committed by GitHub
parent 4b66e874a7
commit 2b5fdf541d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 9 deletions

View File

@ -14,7 +14,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}() }()
let notifier = Notifier() let notifier = Notifier()
lazy var agent: Agent = { lazy var agent: Agent = {
Agent(storeList: storeList/*, notifier: notifier*/) Agent(storeList: storeList, witness: notifier)
}() }()
lazy var socketController: SocketController = { lazy var socketController: SocketController = {
let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String let path = (NSHomeDirectory() as NSString).appendingPathComponent("socket.ssh") as String

View File

@ -11,11 +11,11 @@ class Notifier {
} }
} }
func notify(accessTo secret: AnySecret) { func notify(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) {
let notificationCenter = UNUserNotificationCenter.current() let notificationCenter = UNUserNotificationCenter.current()
let notificationContent = UNMutableNotificationContent() let notificationContent = UNMutableNotificationContent()
notificationContent.title = "Signed Request" 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) let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
notificationCenter.add(request, withCompletionHandler: nil) notificationCenter.add(request, withCompletionHandler: nil)
} }
@ -24,8 +24,8 @@ class Notifier {
extension Notifier: SigningWitness { extension Notifier: SigningWitness {
func witness(accessTo secret: AnySecret) throws { func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws {
notify(accessTo: secret) notify(accessTo: secret, by: provenance)
} }
} }

View File

@ -2,12 +2,15 @@ import Foundation
import CryptoKit import CryptoKit
import OSLog import OSLog
import SecretKit import SecretKit
import SecretAgentKit
import AppKit
public class Agent { public class Agent {
fileprivate let storeList: SecretStoreList fileprivate let storeList: SecretStoreList
fileprivate let witness: SigningWitness? fileprivate let witness: SigningWitness?
fileprivate let writer = OpenSSHKeyWriter() fileprivate let writer = OpenSSHKeyWriter()
fileprivate let requestTracer = SigningRequestTracer()
public init(storeList: SecretStoreList, witness: SigningWitness? = nil) { public init(storeList: SecretStoreList, witness: SigningWitness? = nil) {
os_log(.debug, "Agent is running") os_log(.debug, "Agent is running")
@ -40,7 +43,7 @@ extension Agent {
os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription) os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentIdentitiesAnswer.debugDescription)
case .signRequest: case .signRequest:
response.append(SSHAgent.ResponseType.agentSignResponse.data) 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) os_log(.debug, "Agent returned %@", SSHAgent.ResponseType.agentSignResponse.debugDescription)
} }
} catch { } catch {
@ -74,7 +77,7 @@ extension Agent {
return countData + keyData return countData + keyData
} }
func sign(data: Data) throws -> Data { func sign(data: Data, from pid: Int32) throws -> Data {
let reader = OpenSSHReader(data: data) let reader = OpenSSHReader(data: data)
let hash = try reader.readNextChunk() let hash = try reader.readNextChunk()
guard let (store, secret) = secret(matching: hash) else { guard let (store, secret) = secret(matching: hash) else {
@ -82,8 +85,9 @@ extension Agent {
throw AgentError.noMatchingKey throw AgentError.noMatchingKey
} }
let provenance = requestTracer.provenance(from: pid)
if let witness = witness { if let witness = witness {
try witness.witness(accessTo: secret) try witness.witness(accessTo: secret, by: provenance)
} }
let dataToSign = try reader.readNextChunk() let dataToSign = try reader.readNextChunk()

View File

@ -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
}
}
}

View File

@ -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)
}
}

View File

@ -3,6 +3,6 @@ import SecretKit
public protocol SigningWitness { public protocol SigningWitness {
func witness(accessTo secret: AnySecret) throws func witness(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws
} }

View File

@ -35,6 +35,8 @@
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; }; 507CE4ED2420A3C70029F750 /* Agent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79F24026B9900D209EA /* Agent.swift */; };
507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; }; 507CE4EE2420A3CA0029F750 /* SocketController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A3B79D24026B9900D209EA /* SocketController.swift */; };
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4EF2420A4C50029F750 /* SigningWitness.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 */; }; 508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; };
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; }; 508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; };
508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = "<group>"; };
@ -468,6 +472,8 @@
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */, 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */,
50A3B79D24026B9900D209EA /* SocketController.swift */, 50A3B79D24026B9900D209EA /* SocketController.swift */,
507CE4EF2420A4C50029F750 /* SigningWitness.swift */, 507CE4EF2420A4C50029F750 /* SigningWitness.swift */,
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */,
50A3B79F24026B9900D209EA /* Agent.swift */, 50A3B79F24026B9900D209EA /* Agent.swift */,
5099A06F240242BA0062B6F2 /* Info.plist */, 5099A06F240242BA0062B6F2 /* Info.plist */,
); );
@ -850,6 +856,8 @@
5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */, 5099A08A240242C20062B6F2 /* SSHAgentProtocol.swift in Sources */,
507CE4ED2420A3C70029F750 /* Agent.swift in Sources */, 507CE4ED2420A3C70029F750 /* Agent.swift in Sources */,
507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */, 507CE4F02420A4C50029F750 /* SigningWitness.swift in Sources */,
507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */,
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };