diff --git a/Sources/Packages/Package.swift b/Sources/Packages/Package.swift index 4dcb725..52f187a 100644 --- a/Sources/Packages/Package.swift +++ b/Sources/Packages/Package.swift @@ -28,6 +28,9 @@ let package = Package( .library( name: "XPCWrappers", targets: ["XPCWrappers"]), + .library( + name: "SSHProtocolKit", + targets: ["SSHProtocolKit"]), ], dependencies: [ ], @@ -57,7 +60,7 @@ let package = Package( ), .target( name: "SecretAgentKit", - dependencies: ["SecretKit"], + dependencies: ["SecretKit", "SSHProtocolKit"], resources: [localization], swiftSettings: swiftSettings, ), @@ -65,9 +68,19 @@ let package = Package( name: "SecretAgentKitTests", dependencies: ["SecretAgentKit"], ), + .target( + name: "SSHProtocolKit", + dependencies: ["SecretKit"], + resources: [localization], + swiftSettings: swiftSettings, + ), + .testTarget( + name: "SSHProtocolKitTests", + dependencies: ["SSHProtocolKit"], + ), .target( name: "Brief", - dependencies: ["XPCWrappers"], + dependencies: ["XPCWrappers", "SSHProtocolKit"], resources: [localization], swiftSettings: swiftSettings, ), diff --git a/Sources/Packages/Sources/SSHProtocolKit/Data+Hex.swift b/Sources/Packages/Sources/SSHProtocolKit/Data+Hex.swift new file mode 100644 index 0000000..bf1bb1d --- /dev/null +++ b/Sources/Packages/Sources/SSHProtocolKit/Data+Hex.swift @@ -0,0 +1,37 @@ +import Foundation +import CryptoKit + +public struct HexDataStyle: Hashable, Codable { + + let separator: String + + public init(separator: String) { + self.separator = separator + } + +} + +extension HexDataStyle: FormatStyle where SequenceType.Element == UInt8 { + + public func format(_ value: SequenceType) -> String { + value + .compactMap { ("0" + String($0, radix: 16, uppercase: false)).suffix(2) } + .joined(separator: separator) + } + +} + +extension FormatStyle where Self == HexDataStyle { + + public static func hex(separator: String = "") -> HexDataStyle { + HexDataStyle(separator: separator) + } + +} +extension FormatStyle where Self == HexDataStyle { + + public static func hex(separator: String = ":") -> HexDataStyle { + HexDataStyle(separator: separator) + } + +} diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/LengthAndData.swift b/Sources/Packages/Sources/SSHProtocolKit/LengthAndData.swift similarity index 100% rename from Sources/Packages/Sources/SecretKit/OpenSSH/LengthAndData.swift rename to Sources/Packages/Sources/SSHProtocolKit/LengthAndData.swift diff --git a/Sources/Packages/Sources/SSHProtocolKit/OpenSSHCertificate.swift b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHCertificate.swift new file mode 100644 index 0000000..59fc367 --- /dev/null +++ b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHCertificate.swift @@ -0,0 +1,65 @@ +import Foundation +import OSLog + +public struct OpenSSHCertificate: Sendable, Codable, Equatable, Hashable, Identifiable, CustomDebugStringConvertible { + + public var id: Int { hashValue } + public var type: CertificateType + public let name: String? + public let data: Data + + public var debugDescription: String { + "OpenSSH Certificate \(name, default: "Unnamed"): \(data.formatted(.hex()))" + } + +} + +extension OpenSSHCertificate { + + public enum CertificateType: String, Sendable, Codable { + case ecdsa256 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" + case ecdsa384 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" + case nistp521 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" + + var keyIdentifier: String { + rawValue.replacingOccurrences(of: "-cert-v01@openssh.com", with: "") + } + } + +} + +public protocol OpenSSHCertificateParserProtocol { + func parse(data: Data) async throws -> OpenSSHCertificate +} + +public struct OpenSSHCertificateParser: OpenSSHCertificateParserProtocol, Sendable { + + private let logger = Logger(subsystem: "com.maxgoedjen.secretive", category: "OpenSSHCertificateParser") + + public init() { + } + + public func parse(data: Data) throws(OpenSSHCertificateError) -> OpenSSHCertificate { + let string = String(decoding: data, as: UTF8.self) + var elements = string + .trimmingCharacters(in: .whitespacesAndNewlines) + .components(separatedBy: " ") + guard elements.count >= 2 else { + throw OpenSSHCertificateError.parsingFailed + } + let typeString = elements.removeFirst() + guard let type = OpenSSHCertificate.CertificateType(rawValue: typeString) else { throw .unsupportedType } + let encodedKey = elements.removeFirst() + guard let decoded = Data(base64Encoded: encodedKey) else { + throw OpenSSHCertificateError.parsingFailed + } + let name = elements.first + return OpenSSHCertificate(type: type, name: name, data: decoded) + } + +} + +public enum OpenSSHCertificateError: Error, Codable { + case unsupportedType + case parsingFailed +} diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHPublicKeyWriter.swift similarity index 96% rename from Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift rename to Sources/Packages/Sources/SSHProtocolKit/OpenSSHPublicKeyWriter.swift index 30249e0..2c669db 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift +++ b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHPublicKeyWriter.swift @@ -1,5 +1,6 @@ import Foundation import CryptoKit +import SecretKit /// Generates OpenSSH representations of the public key sof secrets. public struct OpenSSHPublicKeyWriter: Sendable { @@ -49,9 +50,7 @@ public struct OpenSSHPublicKeyWriter: Sendable { /// Generates an OpenSSH MD5 fingerprint string. /// - Returns: OpenSSH MD5 fingerprint string. public func openSSHMD5Fingerprint(secret: SecretType) -> String { - Insecure.MD5.hash(data: data(secret: secret)) - .compactMap { ("0" + String($0, radix: 16, uppercase: false)).suffix(2) } - .joined(separator: ":") + Insecure.MD5.hash(data: data(secret: secret)).formatted(.hex(separator: ":")) } public func comment(secret: SecretType) -> String { diff --git a/Sources/Packages/Sources/SecretAgentKit/OpenSSHReader.swift b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHReader.swift similarity index 100% rename from Sources/Packages/Sources/SecretAgentKit/OpenSSHReader.swift rename to Sources/Packages/Sources/SSHProtocolKit/OpenSSHReader.swift diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHSignatureWriter.swift similarity index 99% rename from Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift rename to Sources/Packages/Sources/SSHProtocolKit/OpenSSHSignatureWriter.swift index b713d53..e5c618d 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift +++ b/Sources/Packages/Sources/SSHProtocolKit/OpenSSHSignatureWriter.swift @@ -1,5 +1,6 @@ import Foundation import CryptoKit +import SecretKit /// Generates OpenSSH representations of Secrets. public struct OpenSSHSignatureWriter: Sendable { diff --git a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift b/Sources/Packages/Sources/SSHProtocolKit/PublicKeyStandinFileController.swift similarity index 99% rename from Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift rename to Sources/Packages/Sources/SSHProtocolKit/PublicKeyStandinFileController.swift index 49e417e..d532172 100644 --- a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift +++ b/Sources/Packages/Sources/SSHProtocolKit/PublicKeyStandinFileController.swift @@ -1,5 +1,6 @@ import Foundation import OSLog +import SecretKit /// Controller responsible for writing public keys to disk, so that they're easily accessible by scripts. public final class PublicKeyFileStoreController: Sendable { diff --git a/Sources/Packages/Sources/SecretAgentKit/SSHAgentInputParser.swift b/Sources/Packages/Sources/SSHProtocolKit/SSHAgentInputParser.swift similarity index 80% rename from Sources/Packages/Sources/SecretAgentKit/SSHAgentInputParser.swift rename to Sources/Packages/Sources/SSHProtocolKit/SSHAgentInputParser.swift index 6e9a2ee..fb7ae81 100644 --- a/Sources/Packages/Sources/SecretAgentKit/SSHAgentInputParser.swift +++ b/Sources/Packages/Sources/SSHProtocolKit/SSHAgentInputParser.swift @@ -74,21 +74,16 @@ extension SSHAgentInputParser { func certificatePublicKeyBlob(from hash: Data) -> Data? { let reader = OpenSSHReader(data: hash) do { - let certType = String(decoding: try reader.readNextChunk(), as: UTF8.self) - switch certType { - case "ecdsa-sha2-nistp256-cert-v01@openssh.com", - "ecdsa-sha2-nistp384-cert-v01@openssh.com", - "ecdsa-sha2-nistp521-cert-v01@openssh.com": - _ = try reader.readNextChunk() // nonce - let curveIdentifier = try reader.readNextChunk() - let publicKey = try reader.readNextChunk() - let openSSHIdentifier = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "") - return openSSHIdentifier.lengthAndData + - curveIdentifier.lengthAndData + + let certType = try reader.readNextChunkAsString() + guard let certType = OpenSSHCertificate.CertificateType(rawValue: certType) else { return nil } + _ = try reader.readNextChunk() // nonce + let curveIdentifier = try reader.readNextChunk() + let publicKey = try reader.readNextChunk() + let openSSHIdentifier = certType.keyIdentifier + return openSSHIdentifier.lengthAndData + + curveIdentifier.lengthAndData + publicKey.lengthAndData - default: - return nil - } + } catch { return nil } diff --git a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift b/Sources/Packages/Sources/SSHProtocolKit/SSHAgentProtocol.swift similarity index 100% rename from Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift rename to Sources/Packages/Sources/SSHProtocolKit/SSHAgentProtocol.swift diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index fbd739e..ee796fa 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -3,6 +3,7 @@ import CryptoKit import OSLog import SecretKit import AppKit +import SSHProtocolKit /// The `Agent` is an implementation of an SSH agent. It manages coordination and access between a socket, traces requests, notifies witnesses and passes requests to stores. public final class Agent: Sendable { @@ -11,7 +12,7 @@ public final class Agent: Sendable { private let witness: SigningWitness? private let publicKeyWriter = OpenSSHPublicKeyWriter() private let signatureWriter = OpenSSHSignatureWriter() - private let certificateHandler = OpenSSHCertificateHandler() +// private let certificateHandler = OpenSSHCertificateHandler() private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "Agent") /// Initializes an agent with a store list and a witness. @@ -23,7 +24,7 @@ public final class Agent: Sendable { self.storeList = storeList self.witness = witness Task { @MainActor in - await certificateHandler.reloadCertificates(for: storeList.allSecrets) +// await certificateHandler.reloadCertificates(for: storeList.allSecrets) } } @@ -66,7 +67,7 @@ extension Agent { /// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations. func identities() async -> Data { let secrets = await storeList.allSecrets - await certificateHandler.reloadCertificates(for: secrets) +// await certificateHandler.reloadCertificates(for: secrets) var count = 0 var keyData = Data() @@ -75,12 +76,12 @@ extension Agent { keyData.append(keyBlob.lengthAndData) keyData.append(publicKeyWriter.comment(secret: secret).lengthAndData) count += 1 - - if let (certificateData, name) = try? await certificateHandler.keyBlobAndName(for: secret) { - keyData.append(certificateData.lengthAndData) - keyData.append(name.lengthAndData) - count += 1 - } + +// if let (certificateData, name) = try? await certificateHandler.keyBlobAndName(for: secret) { +// keyData.append(certificateData.lengthAndData) +// keyData.append(name.lengthAndData) +// count += 1 +// } } logger.log("Agent enumerated \(count) identities") var countBigEndian = UInt32(count).bigEndian @@ -95,7 +96,7 @@ extension Agent { /// - Returns: An OpenSSH formatted Data payload containing the signed data response. func sign(data: Data, keyBlob: Data, provenance: SigningRequestProvenance) async throws -> Data { guard let (secret, store) = await secret(matching: keyBlob) else { - let keyBlobHex = keyBlob.compactMap { ("0" + String($0, radix: 16, uppercase: false)).suffix(2) }.joined() + let keyBlobHex = keyBlob.formatted(.hex()) logger.debug("Agent did not have a key matching \(keyBlobHex)") throw NoMatchingKeyError() } diff --git a/Sources/Packages/Sources/SecretAgentKit/OpenSSHCertificateHandler.swift b/Sources/Packages/Sources/SecretAgentKit/OpenSSHCertificateHandler.swift index 5451e49..88dd6fa 100644 --- a/Sources/Packages/Sources/SecretAgentKit/OpenSSHCertificateHandler.swift +++ b/Sources/Packages/Sources/SecretAgentKit/OpenSSHCertificateHandler.swift @@ -1,6 +1,7 @@ import Foundation import OSLog import SecretKit +import SSHProtocolKit /// Manages storage and lookup for OpenSSH certificates. public actor OpenSSHCertificateHandler: Sendable { @@ -21,9 +22,6 @@ public actor OpenSSHCertificateHandler: Sendable { logger.log("No certificates, short circuiting") return } - keyBlobsAndNames = secrets.reduce(into: [:]) { partialResult, next in - partialResult[next] = try? loadKeyblobAndName(for: next) - } } /// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret`` @@ -32,57 +30,6 @@ public actor OpenSSHCertificateHandler: Sendable { public func keyBlobAndName(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: SecretType) throws -> (Data, Data)? { - let certificatePath = publicKeyFileStoreController.sshCertificatePath(for: secret) - guard FileManager.default.fileExists(atPath: certificatePath) else { - return nil - } - - logger.debug("Found certificate for \(secret.name)") - let certContent = try String(contentsOfFile:certificatePath, encoding: .utf8) - let certElements = certContent.trimmingCharacters(in: .whitespacesAndNewlines).components(separatedBy: " ") - - guard certElements.count >= 2 else { - logger.warning("Certificate found for \(secret.name) but failed to load") - throw OpenSSHCertificateError.parsingFailed - } - guard let certDecoded = Data(base64Encoded: certElements[1] as String) else { - logger.warning("Certificate found for \(secret.name) but failed to decode base64 key") - throw OpenSSHCertificateError.parsingFailed - } - - if certElements.count >= 3 { - let certName = Data(certElements[2].utf8) - return (certDecoded, certName) - } - let certName = Data(secret.name.utf8) - logger.info("Certificate for \(secret.name) does not have a name tag, using secret name instead") - return (certDecoded, certName) - } } -extension OpenSSHCertificateHandler { - - enum OpenSSHCertificateError: LocalizedError { - case unsupportedType - case parsingFailed - case doesNotExist - - public var errorDescription: String? { - switch self { - case .unsupportedType: - return "The key type was unsupported" - case .parsingFailed: - return "Failed to properly parse the SSH certificate" - case .doesNotExist: - return "Certificate does not exist" - } - } - } - -} diff --git a/Sources/Packages/Tests/SecretKitTests/OpenSSHPublicKeyWriterTests.swift b/Sources/Packages/Tests/SSHProtocolKitTests/OpenSSHPublicKeyWriterTests.swift similarity index 100% rename from Sources/Packages/Tests/SecretKitTests/OpenSSHPublicKeyWriterTests.swift rename to Sources/Packages/Tests/SSHProtocolKitTests/OpenSSHPublicKeyWriterTests.swift diff --git a/Sources/SecretAgent/AppDelegate.swift b/Sources/SecretAgent/AppDelegate.swift index 28bef7e..0a4b85b 100644 --- a/Sources/SecretAgent/AppDelegate.swift +++ b/Sources/SecretAgent/AppDelegate.swift @@ -6,6 +6,7 @@ import SmartCardSecretKit import SecretAgentKit import Brief import Observation +import SSHProtocolKit @main class AppDelegate: NSObject, NSApplicationDelegate { diff --git a/Sources/SecretAgent/SecretAgent.entitlements b/Sources/SecretAgent/SecretAgent.entitlements index c9423c4..ab2c42b 100644 --- a/Sources/SecretAgent/SecretAgent.entitlements +++ b/Sources/SecretAgent/SecretAgent.entitlements @@ -2,6 +2,16 @@ + com.apple.security.hardened-process + + com.apple.security.hardened-process.dyld-ro + + com.apple.security.hardened-process.enhanced-security-version + 1 + com.apple.security.hardened-process.hardened-heap + + com.apple.security.hardened-process.platform-restrictions + 2 com.apple.security.smartcard keychain-access-groups diff --git a/Sources/SecretAgent/XPCInputParser.swift b/Sources/SecretAgent/XPCInputParser.swift index b78f316..b951bce 100644 --- a/Sources/SecretAgent/XPCInputParser.swift +++ b/Sources/SecretAgent/XPCInputParser.swift @@ -1,8 +1,8 @@ import Foundation -import SecretAgentKit +import OSLog +import SSHProtocolKit import Brief import XPCWrappers -import OSLog /// Delegates all agent input parsing to an XPC service which wraps OpenSSH public final class XPCAgentInputParser: SSHAgentInputParserProtocol { diff --git a/Sources/SecretAgentInputParser/SecretAgentInputParser.entitlements b/Sources/SecretAgentInputParser/SecretAgentInputParser.entitlements new file mode 100644 index 0000000..08818a6 --- /dev/null +++ b/Sources/SecretAgentInputParser/SecretAgentInputParser.entitlements @@ -0,0 +1,22 @@ + + + + + com.apple.security.hardened-process + + com.apple.security.hardened-process.checked-allocations + + com.apple.security.hardened-process.checked-allocations.enable-pure-data + + com.apple.security.hardened-process.checked-allocations.no-tagged-receive + + com.apple.security.hardened-process.dyld-ro + + com.apple.security.hardened-process.enhanced-security-version + 1 + com.apple.security.hardened-process.hardened-heap + + com.apple.security.hardened-process.platform-restrictions + 2 + + diff --git a/Sources/SecretAgentInputParser/SecretAgentInputParser.swift b/Sources/SecretAgentInputParser/SecretAgentInputParser.swift index cc0c8fd..676fafc 100644 --- a/Sources/SecretAgentInputParser/SecretAgentInputParser.swift +++ b/Sources/SecretAgentInputParser/SecretAgentInputParser.swift @@ -1,7 +1,7 @@ import Foundation import OSLog import XPCWrappers -import SecretAgentKit +import SSHProtocolKit final class SecretAgentInputParser: NSObject, XPCProtocol { diff --git a/Sources/Secretive.xcodeproj/project.pbxproj b/Sources/Secretive.xcodeproj/project.pbxproj index 356d09a..e87d550 100644 --- a/Sources/Secretive.xcodeproj/project.pbxproj +++ b/Sources/Secretive.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 504789232E697DD300B4556F /* BoxBackgroundStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */; }; 50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; }; 50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; }; + 505993512E7E59FB0092CFFA /* XPCCertificateParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505993502E7E59F70092CFFA /* XPCCertificateParser.swift */; }; 50617D8323FCE48E0099B055 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* App.swift */; }; 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; }; 50617D8A23FCE48E0099B055 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8923FCE48E0099B055 /* Preview Assets.xcassets */; }; @@ -49,7 +50,6 @@ 50692E5B2E6FF9D20043C7BB /* SecretAgentInputParser.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 50692E502E6FF9D20043C7BB /* SecretAgentInputParser.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 50692E682E6FF9E20043C7BB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50692E632E6FF9E20043C7BB /* main.swift */; }; 50692E692E6FF9E20043C7BB /* SecretAgentInputParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50692E642E6FF9E20043C7BB /* SecretAgentInputParser.swift */; }; - 50692E6C2E6FFA510043C7BB /* SecretAgentKit in Frameworks */ = {isa = PBXBuildFile; productRef = 50692E6B2E6FFA510043C7BB /* SecretAgentKit */; }; 50692E6D2E6FFA5F0043C7BB /* SecretiveUpdater.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 50692D122E6FDB880043C7BB /* SecretiveUpdater.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 50692E702E6FFA6E0043C7BB /* SecretAgentInputParser.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 50692E502E6FF9D20043C7BB /* SecretAgentInputParser.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5079BA0F250F29BF00EA86F4 /* StoreListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5079BA0E250F29BF00EA86F4 /* StoreListView.swift */; }; @@ -74,6 +74,13 @@ 50E4C4C32E7765DF00C73783 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E4C4C22E7765DF00C73783 /* AboutView.swift */; }; 50E4C4C82E777E4200C73783 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 50E4C4C72E777E4200C73783 /* AppIcon.icon */; }; 50E4C4C92E777E4200C73783 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 50E4C4C72E777E4200C73783 /* AppIcon.icon */; }; + 50E4C4D92E77C4B300C73783 /* SecretiveCertificateParser.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 50E4C4CE2E77C4B300C73783 /* SecretiveCertificateParser.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 50E4C4E82E77C53000C73783 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E4C4E32E77C53000C73783 /* main.swift */; }; + 50E4C4E92E77C53000C73783 /* SecretiveCertificateParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E4C4E52E77C53000C73783 /* SecretiveCertificateParser.swift */; }; + 50E4C4ED2E77C55E00C73783 /* XPCWrappers in Frameworks */ = {isa = PBXBuildFile; productRef = 50E4C4EC2E77C55E00C73783 /* XPCWrappers */; }; + 50E4C4EF2E77C8FC00C73783 /* SSHProtocolKit in Frameworks */ = {isa = PBXBuildFile; productRef = 50E4C4EE2E77C8FC00C73783 /* SSHProtocolKit */; }; + 50E4C4F12E77C90300C73783 /* SSHProtocolKit in Frameworks */ = {isa = PBXBuildFile; productRef = 50E4C4F02E77C90300C73783 /* SSHProtocolKit */; }; + 50E4C4F32E77CAC600C73783 /* XPCWrappers in Frameworks */ = {isa = PBXBuildFile; productRef = 50E4C4F22E77CAC600C73783 /* XPCWrappers */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -119,6 +126,13 @@ remoteGlobalIDString = 50692E4F2E6FF9D20043C7BB; remoteInfo = SecretAgentInputParser; }; + 50E4C4D72E77C4B300C73783 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 50617D7723FCE48D0099B055 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 50E4C4CD2E77C4B300C73783; + remoteInfo = SecretiveCertificateParser; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -129,6 +143,7 @@ dstSubfolderSpec = 16; files = ( 50692D1D2E6FDB880043C7BB /* SecretiveUpdater.xpc in Embed XPC Services */, + 50E4C4D92E77C4B300C73783 /* SecretiveCertificateParser.xpc in Embed XPC Services */, 50692E5B2E6FF9D20043C7BB /* SecretAgentInputParser.xpc in Embed XPC Services */, ); name = "Embed XPC Services"; @@ -195,6 +210,7 @@ 504789222E697DD300B4556F /* BoxBackgroundStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxBackgroundStyle.swift; sourceTree = ""; }; 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = ""; }; 50571E0424393D1500F76F6C /* LaunchAgentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAgentController.swift; sourceTree = ""; }; + 505993502E7E59F70092CFFA /* XPCCertificateParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XPCCertificateParser.swift; sourceTree = ""; }; 50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50617D8223FCE48E0099B055 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -241,6 +257,13 @@ 50E4C4522E73C78900C73783 /* WindowBackgroundStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowBackgroundStyle.swift; sourceTree = ""; }; 50E4C4C22E7765DF00C73783 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; 50E4C4C72E777E4200C73783 /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIcon.icon; sourceTree = ""; }; + 50E4C4CE2E77C4B300C73783 /* SecretiveCertificateParser.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = SecretiveCertificateParser.xpc; sourceTree = BUILT_PRODUCTS_DIR; }; + 50E4C4E02E77C4EE00C73783 /* SecretAgentInputParser.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecretAgentInputParser.entitlements; sourceTree = ""; }; + 50E4C4E12E77C4FA00C73783 /* SecretiveUpdater.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecretiveUpdater.entitlements; sourceTree = ""; }; + 50E4C4E22E77C53000C73783 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50E4C4E32E77C53000C73783 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 50E4C4E42E77C53000C73783 /* SecretiveCertificateParser.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecretiveCertificateParser.entitlements; sourceTree = ""; }; + 50E4C4E52E77C53000C73783 /* SecretiveCertificateParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretiveCertificateParser.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -268,7 +291,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 50692E6C2E6FFA510043C7BB /* SecretAgentKit in Frameworks */, + 50E4C4F32E77CAC600C73783 /* XPCWrappers in Frameworks */, + 50E4C4F12E77C90300C73783 /* SSHProtocolKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -284,6 +308,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 50E4C4CB2E77C4B300C73783 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50E4C4EF2E77C8FC00C73783 /* SSHProtocolKit in Frameworks */, + 50E4C4ED2E77C55E00C73783 /* XPCWrappers in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -356,6 +389,7 @@ 508A58AF241E144C0069DC07 /* Config */, 50692D272E6FDB8D0043C7BB /* SecretiveUpdater */, 50692E662E6FF9E20043C7BB /* SecretAgentInputParser */, + 50E4C4E72E77C53000C73783 /* SecretiveCertificateParser */, 50617D8023FCE48E0099B055 /* Products */, 5099A08B240243730062B6F2 /* Frameworks */, ); @@ -368,6 +402,7 @@ 50A3B78A24026B7500D209EA /* SecretAgent.app */, 50692D122E6FDB880043C7BB /* SecretiveUpdater.xpc */, 50692E502E6FF9D20043C7BB /* SecretAgentInputParser.xpc */, + 50E4C4CE2E77C4B300C73783 /* SecretiveCertificateParser.xpc */, ); name = Products; sourceTree = ""; @@ -403,6 +438,7 @@ 50692D272E6FDB8D0043C7BB /* SecretiveUpdater */ = { isa = PBXGroup; children = ( + 50E4C4E12E77C4FA00C73783 /* SecretiveUpdater.entitlements */, 50692D232E6FDB8D0043C7BB /* Info.plist */, 50692BA52E6D5CC90043C7BB /* InternetAccessPolicy.plist */, 50692D242E6FDB8D0043C7BB /* main.swift */, @@ -414,6 +450,7 @@ 50692E662E6FF9E20043C7BB /* SecretAgentInputParser */ = { isa = PBXGroup; children = ( + 50E4C4E02E77C4EE00C73783 /* SecretAgentInputParser.entitlements */, 50692E622E6FF9E20043C7BB /* Info.plist */, 50692E632E6FF9E20043C7BB /* main.swift */, 50692E642E6FF9E20043C7BB /* SecretAgentInputParser.swift */, @@ -449,6 +486,7 @@ 5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */, 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */, 50571E0424393D1500F76F6C /* LaunchAgentController.swift */, + 505993502E7E59F70092CFFA /* XPCCertificateParser.swift */, ); path = Controllers; sourceTree = ""; @@ -483,6 +521,17 @@ path = "Preview Content"; sourceTree = ""; }; + 50E4C4E72E77C53000C73783 /* SecretiveCertificateParser */ = { + isa = PBXGroup; + children = ( + 50E4C4E42E77C53000C73783 /* SecretiveCertificateParser.entitlements */, + 50E4C4E22E77C53000C73783 /* Info.plist */, + 50E4C4E32E77C53000C73783 /* main.swift */, + 50E4C4E52E77C53000C73783 /* SecretiveCertificateParser.swift */, + ); + path = SecretiveCertificateParser; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -503,6 +552,7 @@ 50142167278126B500BBAA70 /* PBXTargetDependency */, 50692D1C2E6FDB880043C7BB /* PBXTargetDependency */, 50692E5A2E6FF9D20043C7BB /* PBXTargetDependency */, + 50E4C4D82E77C4B300C73783 /* PBXTargetDependency */, ); name = Secretive; packageProductDependencies = ( @@ -550,7 +600,8 @@ ); name = SecretAgentInputParser; packageProductDependencies = ( - 50692E6B2E6FFA510043C7BB /* SecretAgentKit */, + 50E4C4F02E77C90300C73783 /* SSHProtocolKit */, + 50E4C4F22E77CAC600C73783 /* XPCWrappers */, ); productName = SecretAgentInputParser; productReference = 50692E502E6FF9D20043C7BB /* SecretAgentInputParser.xpc */; @@ -585,6 +636,27 @@ productReference = 50A3B78A24026B7500D209EA /* SecretAgent.app */; productType = "com.apple.product-type.application"; }; + 50E4C4CD2E77C4B300C73783 /* SecretiveCertificateParser */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50E4C4DB2E77C4B300C73783 /* Build configuration list for PBXNativeTarget "SecretiveCertificateParser" */; + buildPhases = ( + 50E4C4CA2E77C4B300C73783 /* Sources */, + 50E4C4CB2E77C4B300C73783 /* Frameworks */, + 50E4C4CC2E77C4B300C73783 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SecretiveCertificateParser; + packageProductDependencies = ( + 50E4C4EC2E77C55E00C73783 /* XPCWrappers */, + 50E4C4EE2E77C8FC00C73783 /* SSHProtocolKit */, + ); + productName = SecretiveCertificateParser; + productReference = 50E4C4CE2E77C4B300C73783 /* SecretiveCertificateParser.xpc */; + productType = "com.apple.product-type.xpc-service"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -608,6 +680,9 @@ 50A3B78924026B7500D209EA = { CreatedOnToolsVersion = 11.4; }; + 50E4C4CD2E77C4B300C73783 = { + CreatedOnToolsVersion = 26.0; + }; }; }; buildConfigurationList = 50617D7A23FCE48D0099B055 /* Build configuration list for PBXProject "Secretive" */; @@ -636,6 +711,7 @@ 50A3B78924026B7500D209EA /* SecretAgent */, 50692D112E6FDB880043C7BB /* SecretiveUpdater */, 50692E4F2E6FF9D20043C7BB /* SecretAgentInputParser */, + 50E4C4CD2E77C4B300C73783 /* SecretiveCertificateParser */, ); }; /* End PBXProject section */ @@ -678,6 +754,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 50E4C4CC2E77C4B300C73783 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -698,6 +781,7 @@ 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */, 504788F62E68206F00B4556F /* GettingStartedView.swift in Sources */, 50CF4ABC2E601B0F005588DC /* ActionButtonStyle.swift in Sources */, + 505993512E7E59FB0092CFFA /* XPCCertificateParser.swift in Sources */, 50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */, 5079BA0F250F29BF00EA86F4 /* StoreListView.swift in Sources */, 50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */, @@ -750,6 +834,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 50E4C4CA2E77C4B300C73783 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50E4C4E82E77C53000C73783 /* main.swift in Sources */, + 50E4C4E92E77C53000C73783 /* SecretiveCertificateParser.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -782,6 +875,11 @@ target = 50692E4F2E6FF9D20043C7BB /* SecretAgentInputParser */; targetProxy = 50692E712E6FFA6E0043C7BB /* PBXContainerItemProxy */; }; + 50E4C4D82E77C4B300C73783 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 50E4C4CD2E77C4B300C73783 /* SecretiveCertificateParser */; + targetProxy = 50E4C4D72E77C4B300C73783 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1025,6 +1123,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretiveUpdater/SecretiveUpdater.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -1032,9 +1131,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = Z72PRUAWF6; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_POINTER_AUTHENTICATION = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; ENABLE_RESOURCE_ACCESS_CALENDARS = NO; @@ -1068,13 +1169,16 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretiveUpdater/SecretiveUpdater.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_POINTER_AUTHENTICATION = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; ENABLE_RESOURCE_ACCESS_CALENDARS = NO; @@ -1107,6 +1211,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretiveUpdater/SecretiveUpdater.entitlements; CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; @@ -1114,9 +1219,11 @@ DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = Z72PRUAWF6; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_POINTER_AUTHENTICATION = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; ENABLE_RESOURCE_ACCESS_CALENDARS = NO; @@ -1150,13 +1257,16 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretAgentInputParser/SecretAgentInputParser.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = Z72PRUAWF6; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; + ENABLE_POINTER_AUTHENTICATION = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SecretAgentInputParser/Info.plist; @@ -1182,11 +1292,14 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretAgentInputParser/SecretAgentInputParser.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; + ENABLE_POINTER_AUTHENTICATION = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SecretAgentInputParser/Info.plist; @@ -1211,6 +1324,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretAgentInputParser/SecretAgentInputParser.entitlements; CODE_SIGN_IDENTITY = "Developer ID Application"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; @@ -1218,7 +1332,9 @@ DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = Z72PRUAWF6; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; + ENABLE_POINTER_AUTHENTICATION = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SecretAgentInputParser/Info.plist; @@ -1357,14 +1473,17 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = SecretAgent/SecretAgent.entitlements; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\""; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO; + ENABLE_POINTER_AUTHENTICATION = YES; ENABLE_PREVIEWS = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; @@ -1397,9 +1516,11 @@ DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\""; DEVELOPMENT_TEAM = Z72PRUAWF6; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO; + ENABLE_POINTER_AUTHENTICATION = YES; ENABLE_PREVIEWS = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; @@ -1433,9 +1554,11 @@ DEVELOPMENT_ASSET_PATHS = "\"SecretAgent/Preview Content\""; DEVELOPMENT_TEAM = Z72PRUAWF6; ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; ENABLE_OUTGOING_NETWORK_CONNECTIONS = NO; + ENABLE_POINTER_AUTHENTICATION = YES; ENABLE_PREVIEWS = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; @@ -1458,6 +1581,108 @@ }; name = Release; }; + 50E4C4DC2E77C4B300C73783 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretiveCertificateParser/SecretiveCertificateParser.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = Z72PRUAWF6; + ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_POINTER_AUTHENTICATION = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SecretiveCertificateParser/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SecretiveCertificateParser; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved."; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 26.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretiveCertificateParser; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 50E4C4DD2E77C4B300C73783 /* Test */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretiveCertificateParser/SecretiveCertificateParser.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_POINTER_AUTHENTICATION = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SecretiveCertificateParser/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SecretiveCertificateParser; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved."; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 26.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretiveCertificateParser; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Test; + }; + 50E4C4DE2E77C4B300C73783 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = SecretiveCertificateParser/SecretiveCertificateParser.entitlements; + CODE_SIGN_IDENTITY = "Developer ID Application"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_APP_SANDBOX = YES; + ENABLE_ENHANCED_SECURITY = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_POINTER_AUTHENTICATION = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SecretiveCertificateParser/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SecretiveCertificateParser; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Max Goedjen. All rights reserved."; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 26.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretiveCertificateParser; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + REGISTER_APP_GROUPS = YES; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1511,6 +1736,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 50E4C4DB2E77C4B300C73783 /* Build configuration list for PBXNativeTarget "SecretiveCertificateParser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50E4C4DC2E77C4B300C73783 /* Debug */, + 50E4C4DD2E77C4B300C73783 /* Test */, + 50E4C4DE2E77C4B300C73783 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1558,9 +1793,21 @@ isa = XCSwiftPackageProductDependency; productName = Brief; }; - 50692E6B2E6FFA510043C7BB /* SecretAgentKit */ = { + 50E4C4EC2E77C55E00C73783 /* XPCWrappers */ = { isa = XCSwiftPackageProductDependency; - productName = SecretAgentKit; + productName = XPCWrappers; + }; + 50E4C4EE2E77C8FC00C73783 /* SSHProtocolKit */ = { + isa = XCSwiftPackageProductDependency; + productName = SSHProtocolKit; + }; + 50E4C4F02E77C90300C73783 /* SSHProtocolKit */ = { + isa = XCSwiftPackageProductDependency; + productName = SSHProtocolKit; + }; + 50E4C4F22E77CAC600C73783 /* XPCWrappers */ = { + isa = XCSwiftPackageProductDependency; + productName = XPCWrappers; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/Sources/Secretive/Controllers/XPCCertificateParser.swift b/Sources/Secretive/Controllers/XPCCertificateParser.swift new file mode 100644 index 0000000..68d7236 --- /dev/null +++ b/Sources/Secretive/Controllers/XPCCertificateParser.swift @@ -0,0 +1,29 @@ +import Foundation +import OSLog +import SSHProtocolKit +import Brief +import XPCWrappers + +/// Delegates all agent input parsing to an XPC service which wraps OpenSSH +public final class XPCCertificateParser: OpenSSHCertificateParserProtocol { + + private let logger = Logger(subsystem: "com.maxgoedjen.secretive", category: "XPCCertificateParser") + private let session: XPCTypedSession + + public init() async throws { + logger.debug("Creating XPCCertificateParser") + session = try await XPCTypedSession(serviceName: "com.maxgoedjen.Secretive.SecretiveCertificateParser", warmup: true) + logger.debug("XPCCertificateParser is warmed up.") + } + + public func parse(data: Data) async throws -> OpenSSHCertificate { + logger.debug("Parsing input") + defer { logger.debug("Parsed input") } + return try await session.send(data) + } + + deinit { + session.complete() + } + +} diff --git a/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift b/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift index d23679a..cb96fe7 100644 --- a/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift +++ b/Sources/Secretive/Views/Configuration/ToolConfigurationView.swift @@ -1,5 +1,6 @@ import SwiftUI import SecretKit +import SSHProtocolKit struct ToolConfigurationView: View { diff --git a/Sources/Secretive/Views/Secrets/SecretDetailView.swift b/Sources/Secretive/Views/Secrets/SecretDetailView.swift index b3940ff..a124e7e 100644 --- a/Sources/Secretive/Views/Secrets/SecretDetailView.swift +++ b/Sources/Secretive/Views/Secrets/SecretDetailView.swift @@ -1,5 +1,6 @@ import SwiftUI import SecretKit +import SSHProtocolKit struct SecretDetailView: View { diff --git a/Sources/Secretive/Views/Views/ContentView.swift b/Sources/Secretive/Views/Views/ContentView.swift index 7c395df..7c1d102 100644 --- a/Sources/Secretive/Views/Views/ContentView.swift +++ b/Sources/Secretive/Views/Views/ContentView.swift @@ -3,6 +3,7 @@ import SecretKit import SecureEnclaveSecretKit import SmartCardSecretKit import Brief +import SSHProtocolKit struct ContentView: View { @@ -42,6 +43,16 @@ struct ContentView: View { runningSetup = true } } + .dropDestination(for: URL.self) { items, location in + guard let url = items.first, url.pathExtension == "pub" else { return false } + Task { + let data = try! Data(contentsOf: url) + let parser = try! await XPCCertificateParser() + let cert = try! await parser.parse(data: data) + print(cert) + } + return true + } isTargeted: { _ in } .focusedSceneValue(\.showCreateSecret, .init(isEnabled: !runningSetup) { showingCreation = true }) diff --git a/Sources/SecretiveCertificateParser/Info.plist b/Sources/SecretiveCertificateParser/Info.plist new file mode 100644 index 0000000..c123a5d --- /dev/null +++ b/Sources/SecretiveCertificateParser/Info.plist @@ -0,0 +1,11 @@ + + + + + XPCService + + ServiceType + Application + + + diff --git a/Sources/SecretiveCertificateParser/SecretiveCertificateParser.entitlements b/Sources/SecretiveCertificateParser/SecretiveCertificateParser.entitlements new file mode 100644 index 0000000..08818a6 --- /dev/null +++ b/Sources/SecretiveCertificateParser/SecretiveCertificateParser.entitlements @@ -0,0 +1,22 @@ + + + + + com.apple.security.hardened-process + + com.apple.security.hardened-process.checked-allocations + + com.apple.security.hardened-process.checked-allocations.enable-pure-data + + com.apple.security.hardened-process.checked-allocations.no-tagged-receive + + com.apple.security.hardened-process.dyld-ro + + com.apple.security.hardened-process.enhanced-security-version + 1 + com.apple.security.hardened-process.hardened-heap + + com.apple.security.hardened-process.platform-restrictions + 2 + + diff --git a/Sources/SecretiveCertificateParser/SecretiveCertificateParser.swift b/Sources/SecretiveCertificateParser/SecretiveCertificateParser.swift new file mode 100644 index 0000000..8c7aab7 --- /dev/null +++ b/Sources/SecretiveCertificateParser/SecretiveCertificateParser.swift @@ -0,0 +1,17 @@ +import Foundation +import OSLog +import XPCWrappers +import SSHProtocolKit + +final class SecretiveCertificateParser: NSObject, XPCProtocol { + + private let logger = Logger(subsystem: "com.maxgoedjen.secretive.SecretiveCertificateParser", category: "SecretiveCertificateParser") + + func process(_ data: Data) async throws -> OpenSSHCertificate { + let parser = OpenSSHCertificateParser() + let result = try parser.parse(data: data) + logger.log("Parser parsed certificate \(result.debugDescription)") + return result + } + +} diff --git a/Sources/SecretiveCertificateParser/main.swift b/Sources/SecretiveCertificateParser/main.swift new file mode 100644 index 0000000..c1516f0 --- /dev/null +++ b/Sources/SecretiveCertificateParser/main.swift @@ -0,0 +1,7 @@ +import Foundation +import XPCWrappers + +let delegate = XPCServiceDelegate(exportedObject: SecretiveCertificateParser()) +let listener = NSXPCListener.service() +listener.delegate = delegate +listener.resume() diff --git a/Sources/SecretiveUpdater/SecretiveUpdater.entitlements b/Sources/SecretiveUpdater/SecretiveUpdater.entitlements new file mode 100644 index 0000000..08818a6 --- /dev/null +++ b/Sources/SecretiveUpdater/SecretiveUpdater.entitlements @@ -0,0 +1,22 @@ + + + + + com.apple.security.hardened-process + + com.apple.security.hardened-process.checked-allocations + + com.apple.security.hardened-process.checked-allocations.enable-pure-data + + com.apple.security.hardened-process.checked-allocations.no-tagged-receive + + com.apple.security.hardened-process.dyld-ro + + com.apple.security.hardened-process.enhanced-security-version + 1 + com.apple.security.hardened-process.hardened-heap + + com.apple.security.hardened-process.platform-restrictions + 2 + +