107 lines
4.4 KiB
Swift
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
|
|
}
|
|
}
|