Files
2020-12-02 19:49:25 +03:00

107 lines
4.4 KiB
Swift

//
// CodesignCheck.swift
// SMJobLess
//
// Created by Jura on 3/12/20.
// Copyright © 2020 Juraldinio. All rights reserved.
//
import Foundation
import Security
enum CodesignCheckError: Error {
case message(String)
}
struct CodesignCheck {
// MARK: - Compare
public static func codeSigningMatches(pid: pid_t) throws -> Bool {
return try self.codeSigningCertificatesForSelf() == self.codeSigningCertificates(forPID: pid)
}
// MARK: - Public
public static func codeSigningCertificatesForSelf() throws -> [SecCertificate] {
guard let secStaticCode = try secStaticCodeSelf() else { return [] }
return try codeSigningCertificates(forStaticCode: secStaticCode)
}
public static func codeSigningCertificates(forPID pid: pid_t) throws -> [SecCertificate] {
guard let secStaticCode = try secStaticCode(forPID: pid) else { return [] }
return try codeSigningCertificates(forStaticCode: secStaticCode)
}
public static func codeSigningCertificates(forURL url: URL) throws -> [SecCertificate] {
guard let secStaticCode = try secStaticCode(forURL: url) else { return [] }
return try codeSigningCertificates(forStaticCode: secStaticCode)
}
// MARK: - Private
private static func executeSecFunction(_ secFunction: () -> (OSStatus) ) throws {
let osStatus = secFunction()
guard osStatus == errSecSuccess else {
throw CodesignCheckError.message(String(describing: SecCopyErrorMessageString(osStatus, nil)))
}
}
private static func secStaticCodeSelf() throws -> SecStaticCode? {
var secCodeSelf: SecCode?
try executeSecFunction { SecCodeCopySelf(SecCSFlags(rawValue: 0), &secCodeSelf) }
guard let secCode = secCodeSelf else {
throw CodesignCheckError.message("SecCode returned empty from SecCodeCopySelf")
}
return try secStaticCode(forSecCode: secCode)
}
private static func secStaticCode(forPID pid: pid_t) throws -> SecStaticCode? {
var secCodePID: SecCode?
try executeSecFunction { SecCodeCopyGuestWithAttributes(nil, [kSecGuestAttributePid: pid] as CFDictionary, [], &secCodePID) }
guard let secCode = secCodePID else {
throw CodesignCheckError.message("SecCode returned empty from SecCodeCopyGuestWithAttributes")
}
return try secStaticCode(forSecCode: secCode)
}
private static func secStaticCode(forURL url: URL) throws -> SecStaticCode? {
var secStaticCodePath: SecStaticCode?
try executeSecFunction { SecStaticCodeCreateWithPath(url as CFURL, [], &secStaticCodePath) }
guard let secStaticCode = secStaticCodePath else {
throw CodesignCheckError.message("SecStaticCode returned empty from SecStaticCodeCreateWithPath")
}
return secStaticCode
}
private static func secStaticCode(forSecCode secCode: SecCode) throws -> SecStaticCode? {
var secStaticCodeCopy: SecStaticCode?
try executeSecFunction { SecCodeCopyStaticCode(secCode, [], &secStaticCodeCopy) }
guard let secStaticCode = secStaticCodeCopy else {
throw CodesignCheckError.message("SecStaticCode returned empty from SecCodeCopyStaticCode")
}
return secStaticCode
}
private static func isValid(secStaticCode: SecStaticCode) throws {
try executeSecFunction { SecStaticCodeCheckValidity(secStaticCode, SecCSFlags(rawValue: kSecCSDoNotValidateResources | kSecCSCheckNestedCode), nil) }
}
private static func secCodeInfo(forStaticCode secStaticCode: SecStaticCode) throws -> [String: Any]? {
try isValid(secStaticCode: secStaticCode)
var secCodeInfoCFDict: CFDictionary?
try executeSecFunction { SecCodeCopySigningInformation(secStaticCode, SecCSFlags(rawValue: kSecCSSigningInformation), &secCodeInfoCFDict) }
guard let secCodeInfo = secCodeInfoCFDict as? [String: Any] else {
throw CodesignCheckError.message("CFDictionary returned empty from SecCodeCopySigningInformation")
}
return secCodeInfo
}
private static func codeSigningCertificates(forStaticCode secStaticCode: SecStaticCode) throws -> [SecCertificate] {
guard
let secCodeInfo = try secCodeInfo(forStaticCode: secStaticCode),
let secCertificates = secCodeInfo[kSecCodeInfoCertificates as String] as? [SecCertificate] else { return [] }
return secCertificates
}
}