Files
xcodesApp-mirror/com.xcodesorg.xcodesapp.Helper/ConnectionVerifier.swift
2024-01-19 14:28:12 -06:00

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