Show request details in Secure prompts (#146)

This commit is contained in:
Max Goedjen 2020-09-23 21:51:48 -07:00 committed by GitHub
parent 85e096f8cc
commit 3774352dfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 27 additions and 16 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 192 KiB

View File

@ -93,7 +93,7 @@ extension Agent {
} }
let dataToSign = reader.readNextChunk() let dataToSign = reader.readNextChunk()
let derSignature = try store.sign(data: dataToSign, with: secret) let derSignature = try store.sign(data: dataToSign, with: secret, for: provenance)
let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)! let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import AppKit import AppKit
import Security import Security
import SecretKit
struct SigningRequestTracer { struct SigningRequestTracer {

View File

@ -48,7 +48,7 @@ extension Stub {
print("Public Key OpenSSH: \(OpenSSHKeyWriter().openSSHString(secret: secret))") print("Public Key OpenSSH: \(OpenSSHKeyWriter().openSSHString(secret: secret))")
} }
public func sign(data: Data, with secret: Secret) throws -> Data { public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data {
guard !shouldThrow else { guard !shouldThrow else {
throw NSError() throw NSError()
} }

View File

@ -8,7 +8,7 @@ public class AnySecretStore: SecretStore {
private let _id: () -> UUID private let _id: () -> UUID
private let _name: () -> String private let _name: () -> String
private let _secrets: () -> [AnySecret] private let _secrets: () -> [AnySecret]
private let _sign: (Data, AnySecret) throws -> Data private let _sign: (Data, AnySecret, SigningRequestProvenance) throws -> Data
private var sink: AnyCancellable? private var sink: AnyCancellable?
public init<SecretStoreType>(_ secretStore: SecretStoreType) where SecretStoreType: SecretStore { public init<SecretStoreType>(_ secretStore: SecretStoreType) where SecretStoreType: SecretStore {
@ -17,7 +17,7 @@ public class AnySecretStore: SecretStore {
_name = { secretStore.name } _name = { secretStore.name }
_id = { secretStore.id } _id = { secretStore.id }
_secrets = { secretStore.secrets.map { AnySecret($0) } } _secrets = { secretStore.secrets.map { AnySecret($0) } }
_sign = { try secretStore.sign(data: $0, with: $1.base as! SecretStoreType.SecretType) } _sign = { try secretStore.sign(data: $0, with: $1.base as! SecretStoreType.SecretType, for: $2) }
sink = secretStore.objectWillChange.sink { _ in sink = secretStore.objectWillChange.sink { _ in
self.objectWillChange.send() self.objectWillChange.send()
} }
@ -39,8 +39,8 @@ public class AnySecretStore: SecretStore {
return _secrets() return _secrets()
} }
public func sign(data: Data, with secret: AnySecret) throws -> Data { public func sign(data: Data, with secret: AnySecret, for provenance: SigningRequestProvenance) throws -> Data {
try _sign(data, secret) try _sign(data, secret, provenance)
} }
} }

View File

@ -9,7 +9,7 @@ public protocol SecretStore: ObservableObject, Identifiable {
var name: String { get } var name: String { get }
var secrets: [SecretType] { get } var secrets: [SecretType] { get }
func sign(data: Data, with secret: SecretType) throws -> Data func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data
} }

View File

@ -17,7 +17,7 @@ extension SigningRequestProvenance {
} }
public var intact: Bool { public var intact: Bool {
return chain.reduce(true) { $0 && $1.validSignature } chain.allSatisfy { $0.validSignature }
} }
} }
@ -30,9 +30,9 @@ extension SigningRequestProvenance {
public let name: String public let name: String
public let path: String public let path: String
public let validSignature: Bool public let validSignature: Bool
let parentPID: Int32? public let parentPID: Int32?
init(pid: Int32, name: String, path: String, validSignature: Bool, parentPID: Int32?) { public init(pid: Int32, name: String, path: String, validSignature: Bool, parentPID: Int32?) {
self.pid = pid self.pid = pid
self.name = name self.name = name
self.path = path self.path = path

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import Security import Security
import CryptoTokenKit import CryptoTokenKit
import LocalAuthentication
extension SecureEnclave { extension SecureEnclave {
@ -75,7 +76,10 @@ extension SecureEnclave {
reloadSecrets() reloadSecrets()
} }
public func sign(data: Data, with secret: SecretType) throws -> Data { public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data {
let context = LAContext()
context.localizedReason = "sign a request from \"\(provenance.origin.name)\" using secret \"\(secret.name)\""
context.localizedCancelTitle = "Deny"
let attributes = [ let attributes = [
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyClass: kSecAttrKeyClassPrivate,
@ -83,6 +87,7 @@ extension SecureEnclave {
kSecAttrKeyType: Constants.keyType, kSecAttrKeyType: Constants.keyType,
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
kSecAttrApplicationTag: Constants.keyTag, kSecAttrApplicationTag: Constants.keyTag,
kSecUseAuthenticationContext: context,
kSecReturnRef: true kSecReturnRef: true
] as CFDictionary ] as CFDictionary
var untyped: CFTypeRef? var untyped: CFTypeRef?

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import Security import Security
import CryptoTokenKit import CryptoTokenKit
import LocalAuthentication
// TODO: Might need to split this up into "sub-stores?" // TODO: Might need to split this up into "sub-stores?"
// ie, each token has its own Store. // ie, each token has its own Store.
@ -43,13 +44,17 @@ extension SmartCard {
fatalError("Keys must be deleted on the smart card.") fatalError("Keys must be deleted on the smart card.")
} }
public func sign(data: Data, with secret: SecretType) throws -> Data { public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data {
guard let tokenID = tokenID else { fatalError() } guard let tokenID = tokenID else { fatalError() }
let context = LAContext()
context.localizedReason = "sign a request from \"\(provenance.origin.name)\" using secret \"\(secret.name)\""
context.localizedCancelTitle = "Deny"
let attributes = [ let attributes = [
kSecClass: kSecClassKey, kSecClass: kSecClassKey,
kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeyClass: kSecAttrKeyClassPrivate,
kSecAttrApplicationLabel: secret.id as CFData, kSecAttrApplicationLabel: secret.id as CFData,
kSecAttrTokenID: tokenID, kSecAttrTokenID: tokenID,
kSecUseAuthenticationContext: context,
kSecReturnRef: true kSecReturnRef: true
] as CFDictionary ] as CFDictionary
var untyped: CFTypeRef? var untyped: CFTypeRef?

View File

@ -11,6 +11,7 @@
50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; }; 50153E20250AFCB200525160 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E1F250AFCB200525160 /* UpdateView.swift */; };
50153E22250DECA300525160 /* SecretListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E21250DECA300525160 /* SecretListView.swift */; }; 50153E22250DECA300525160 /* SecretListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50153E21250DECA300525160 /* SecretListView.swift */; };
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; }; 5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
501B7AE1251C56F700776EC7 /* SigningRequestProvenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */; };
50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */; }; 50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */; };
50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; }; 50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; };
50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; }; 50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; };
@ -49,7 +50,6 @@
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 */; }; 507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */; };
507EE34224281E12003C4FE3 /* FileHandleProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */; }; 507EE34224281E12003C4FE3 /* FileHandleProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */; };
507EE34624281F89003C4FE3 /* StubFileHandleReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */; }; 507EE34624281F89003C4FE3 /* StubFileHandleReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507EE34524281F89003C4FE3 /* StubFileHandleReader.swift */; };
@ -381,6 +381,7 @@
504BA92D243171F20064740E /* Types */ = { 504BA92D243171F20064740E /* Types */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
50617DCA23FCECA10099B055 /* Secret.swift */, 50617DCA23FCECA10099B055 /* Secret.swift */,
50617DC623FCE4EA0099B055 /* SecretStore.swift */, 50617DC623FCE4EA0099B055 /* SecretStore.swift */,
); );
@ -593,7 +594,6 @@
5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */, 5099A089240242C20062B6F2 /* SSHAgentProtocol.swift */,
50A3B79D24026B9900D209EA /* SocketController.swift */, 50A3B79D24026B9900D209EA /* SocketController.swift */,
507CE4EF2420A4C50029F750 /* SigningWitness.swift */, 507CE4EF2420A4C50029F750 /* SigningWitness.swift */,
507CE4F32420A8C10029F750 /* SigningRequestProvenance.swift */,
507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */, 507CE4F52420A96F0029F750 /* SigningRequestTracer.swift */,
50A3B79F24026B9900D209EA /* Agent.swift */, 50A3B79F24026B9900D209EA /* Agent.swift */,
507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */, 507EE34124281E12003C4FE3 /* FileHandleProtocols.swift */,
@ -1026,6 +1026,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
501B7AE1251C56F700776EC7 /* SigningRequestProvenance.swift in Sources */,
50617DC723FCE4EA0099B055 /* SecretStore.swift in Sources */, 50617DC723FCE4EA0099B055 /* SecretStore.swift in Sources */,
5099A02723FE34FA0062B6F2 /* SmartCard.swift in Sources */, 5099A02723FE34FA0062B6F2 /* SmartCard.swift in Sources */,
50617DCB23FCECA10099B055 /* Secret.swift in Sources */, 50617DCB23FCECA10099B055 /* Secret.swift in Sources */,
@ -1078,7 +1079,6 @@
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 */, 507CE4F62420A96F0029F750 /* SigningRequestTracer.swift in Sources */,
507CE4F42420A8C10029F750 /* SigningRequestProvenance.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -35,7 +35,7 @@ extension Preview {
self.secrets.append(contentsOf: new) self.secrets.append(contentsOf: new)
} }
func sign(data: Data, with secret: Preview.Secret) throws -> Data { func sign(data: Data, with secret: Preview.Secret, for provenance: SigningRequestProvenance) throws -> Data {
return data return data
} }