mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-02-02 11:33:02 +01:00
125 lines
5.1 KiB
Swift
125 lines
5.1 KiB
Swift
// From https://github.com/securing/SimpleXPCApp/
|
|
|
|
import Foundation
|
|
import os.log
|
|
|
|
class ConnectionVerifier {
|
|
|
|
private static func prepareCodeReferencesFromAuditToken(connection: NSXPCConnection, secCodeOptional: inout SecCode?, secStaticCodeOptional: inout SecStaticCode?) -> Bool {
|
|
let auditTokenData = AuditTokenHack.getAuditTokenData(from: connection)
|
|
|
|
let attributesDictrionary = [
|
|
kSecGuestAttributeAudit : auditTokenData
|
|
]
|
|
|
|
if SecCodeCopyGuestWithAttributes(nil, attributesDictrionary as CFDictionary, SecCSFlags(rawValue: 0), &secCodeOptional) != errSecSuccess {
|
|
Logger.connectionVerifier.error("Couldn't get SecCode with the audit token")
|
|
return false
|
|
}
|
|
|
|
guard let secCode = secCodeOptional else {
|
|
Logger.connectionVerifier.error("Couldn't unwrap the secCode")
|
|
return false
|
|
}
|
|
|
|
SecCodeCopyStaticCode(secCode, SecCSFlags(rawValue: 0), &secStaticCodeOptional)
|
|
|
|
guard let _ = secStaticCodeOptional else {
|
|
Logger.connectionVerifier.error("Couldn't unwrap the secStaticCode")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private static func verifyHardenedRuntimeAndProblematicEntitlements(secStaticCode: SecStaticCode) -> Bool {
|
|
var signingInformationOptional: CFDictionary? = nil
|
|
if SecCodeCopySigningInformation(secStaticCode, SecCSFlags(rawValue: kSecCSDynamicInformation), &signingInformationOptional) != errSecSuccess {
|
|
Logger.connectionVerifier.error("Couldn't obtain signing information")
|
|
return false
|
|
}
|
|
|
|
guard let signingInformation = signingInformationOptional else {
|
|
return false
|
|
}
|
|
|
|
let signingInformationDict = signingInformation as NSDictionary
|
|
|
|
let signingFlagsOptional = signingInformationDict.object(forKey: "flags") as? UInt32
|
|
|
|
if let signingFlags = signingFlagsOptional {
|
|
let hardenedRuntimeFlag: UInt32 = 0x10000
|
|
if (signingFlags & hardenedRuntimeFlag) != hardenedRuntimeFlag {
|
|
Logger.connectionVerifier.error("Hardened runtime is not set for the sender")
|
|
return false
|
|
}
|
|
} else {
|
|
return false
|
|
}
|
|
|
|
let entitlementsOptional = signingInformationDict.object(forKey: "entitlements-dict") as? NSDictionary
|
|
guard let entitlements = entitlementsOptional else {
|
|
return false
|
|
}
|
|
Logger.connectionVerifier.info("Entitlements are \(entitlements)")
|
|
let problematicEntitlements = [
|
|
"com.apple.security.get-task-allow",
|
|
"com.apple.security.cs.disable-library-validation",
|
|
"com.apple.security.cs.allow-dyld-environment-variables"
|
|
]
|
|
|
|
// Skip this check for debug builds because they'll have the get-task-allow entitlement
|
|
#if !DEBUG
|
|
for problematicEntitlement in problematicEntitlements {
|
|
if let presentEntitlement = entitlements.object(forKey: problematicEntitlement) {
|
|
if presentEntitlement as! Int == 1 {
|
|
Logger.connectionVerifier.error("The sender has \(problematicEntitlement) entitlement set to true")
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true
|
|
}
|
|
|
|
private static func verifyWithRequirementString(secCode: SecCode) -> Bool {
|
|
// Code Signing Requirement Language
|
|
// https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html#//apple_ref/doc/uid/TP40005929-CH5-SW1
|
|
let requirementString = "identifier \"\(clientBundleID)\" and info [CFBundleShortVersionString] >= \"1.0.0\" and anchor apple generic and certificate leaf[subject.OU] = \"\(subjectOrganizationalUnit)\"" as NSString
|
|
|
|
var secRequirement: SecRequirement? = nil
|
|
if SecRequirementCreateWithString(requirementString as CFString, SecCSFlags(rawValue: 0), &secRequirement) != errSecSuccess {
|
|
Logger.connectionVerifier.error("Couldn't create the requirement string")
|
|
return false
|
|
}
|
|
|
|
if SecCodeCheckValidity(secCode, SecCSFlags(rawValue: 0), secRequirement) != errSecSuccess {
|
|
Logger.connectionVerifier.error("NSXPC client does not meet the requirements")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
public static func isValid(connection: NSXPCConnection) -> Bool {
|
|
var secCodeOptional: SecCode? = nil
|
|
var secStaticCodeOptional: SecStaticCode? = nil
|
|
|
|
if !prepareCodeReferencesFromAuditToken(connection: connection, secCodeOptional: &secCodeOptional, secStaticCodeOptional: &secStaticCodeOptional) {
|
|
return false
|
|
}
|
|
|
|
if !verifyHardenedRuntimeAndProblematicEntitlements(secStaticCode: secStaticCodeOptional!) {
|
|
return false
|
|
}
|
|
|
|
if !verifyWithRequirementString(secCode: secCodeOptional!) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
}
|