Files
santa/Source/common/SNTCodesignChecker.m.old
Russell Hancox 07988686ae Initial commit
2014-11-20 16:23:13 -05:00

214 lines
6.3 KiB
Mathematica

#import "SNTCodesignChecker.h"
#import <Security/Security.h>
#import "SNTCertificate.h"
// kStaticSigningFlags are the flags used when validating signatures on disk.
//
// Don't validate resources but do validate nested code. Ignoring resources _dramatically_ speeds
// up validation (see below) but does mean images, plists, etc will not be checked and modifying
// these will not be considered invalid. To ensure any code inside the binary is still checked,
// we check nested code.
//
// Timings with different flags:
// Checking Xcode 5.1.1 bundle:
// kSecCSDefaultFlags: 3.895s
// kSecCSDoNotValidateResources: 0.013s
// kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.013s
//
// Checking Google Chrome 36.0.1985.143 bundle:
// kSecCSDefaultFlags: 0.529s
// kSecCSDoNotValidateResources: 0.032s
// kSecCSDoNotValidateResources | kSecCSCheckNestedCode: 0.033s
//
const SecCSFlags kStaticSigningFlags = kSecCSDoNotValidateResources | kSecCSCheckNestedCode;
// kSigningFlags are the flags used when validating signatures for running binaries.
//
// No special flags needed currently.
const SecCSFlags kSigningFlags = kSecCSDefaultFlags;
@implementation SNTCodesignChecker
#pragma mark Init/dealloc
- (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef {
self = [super init];
if (self) {
_codeRef = codeRef;
CFRetain(_codeRef);
}
return self;
}
- (instancetype)initWithBinaryPath:(NSString *)binaryPath {
SecStaticCodeRef codeRef = NULL;
// Get SecStaticCodeRef for binary
if (SecStaticCodeCreateWithPath((__bridge CFURLRef)[NSURL fileURLWithPath:binaryPath
isDirectory:NO],
kSecCSDefaultFlags,
&codeRef) == errSecSuccess) {
self = [self initWithSecStaticCodeRef:codeRef];
} else {
self = nil;
}
if (codeRef) CFRelease(codeRef);
return self;
}
- (instancetype)initWithPID:(pid_t)PID {
SecCodeRef codeRef = NULL;
NSDictionary *attributes = @{(__bridge NSString *)kSecGuestAttributePid: @(PID)};
if (SecCodeCopyGuestWithAttributes(NULL,
(__bridge CFDictionaryRef)attributes,
kSecCSDefaultFlags,
&codeRef) == errSecSuccess) {
self = [self initWithSecStaticCodeRef:codeRef];
} else {
self = nil;
}
if (codeRef) CFRelease(codeRef);
return self;
}
- (instancetype)initWithSelf {
SecCodeRef codeSelf = NULL;
if (SecCodeCopySelf(kSecCSDefaultFlags, &codeSelf) == errSecSuccess) {
self = [self initWithSecStaticCodeRef:codeSelf];
} else {
self = nil;
}
if (codeSelf) CFRelease(codeSelf);
return self;
}
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (void)dealloc {
if (_codeRef) CFRelease(_codeRef);
}
#pragma mark Validate
- (OSStatus)validate {
return [self validateWithRequirement:NULL];
}
- (OSStatus)validateAppleAnchor {
SecRequirementRef req = NULL;
SecRequirementCreateWithString(CFSTR("anchor apple"), kSecCSDefaultFlags, &req);
return [self validateWithRequirement:req];
}
- (OSStatus)validateAppleAnchorGeneric {
SecRequirementRef req = NULL;
SecRequirementCreateWithString(CFSTR("anchor apple generic"), kSecCSDefaultFlags, &req);
return [self validateWithRequirement:req];
}
- (OSStatus)validateWithRequirement:(SecRequirementRef)requirement {
// Validate the binary and save the return code.
if (CFGetTypeID(self.codeRef) == SecStaticCodeGetTypeID()) {
return SecStaticCodeCheckValidity(self.codeRef, kStaticSigningFlags, requirement);
} else if (CFGetTypeID(self.codeRef) == SecCodeGetTypeID()) {
return SecCodeCheckValidity((SecCodeRef)self.codeRef, kSigningFlags, requirement);
} else {
return errSecCSSignatureNotVerifiable;
}
}
#pragma mark Description
- (NSString *)description {
NSString *retStr;
if (CFGetTypeID(self.codeRef) == SecStaticCodeGetTypeID()) {
retStr = @"On-disk binary, ";
} else {
retStr = @"In-memory binary, ";
}
if ([self validate] == errSecSuccess) {
[retStr appendFormat:@"signed by %@, ", self.leafCertificate.orgName];
} else {
[retStr appendFormat:@"unsigned, "];
}
[retStr appendFormat:@"located at: %@", self.binaryPath];
return retStr;
}
#pragma mark Public accessors
- (NSDictionary *)signingInformation {
static NSDictionary *signingInformation = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Get dictionary of signing information for binary
CFDictionaryRef signingDict = NULL;
SecCodeCopySigningInformation(self.codeRef, kSecCSSigningInformation, &signingDict);
signingInformation = CFBridgingRelease(signingDict);
});
return signingInformation;
}
- (NSArray *)certificates {
static NSArray *certificates = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Get array of certificates, wrap each one in a SNTCertificate and store in a new array.
NSArray *certs = self.signingInformation[(__bridge NSString *)kSecCodeInfoCertificates];
NSMutableArray *tempCerts = [[NSMutableArray alloc] initWithCapacity:certs.count];
for (id cert in certs) {
SNTCertificate *newCert =
[[SNTCertificate alloc] initWithSecCertificateRef:(SecCertificateRef)cert];
if (newCert) [tempCerts addObject:newCert];
}
certificates = [tempCerts copy];
});
return certificates;
}
- (SNTCertificate *)leafCertificate {
return [self.certificates firstObject];
}
- (NSString *)binaryPath {
CFURLRef path;
OSStatus status = SecCodeCopyPath(_codeRef, kSecCSDefaultFlags, &path);
NSURL *pathURL = CFBridgingRelease(path);
if (status != errSecSuccess) return nil;
return [pathURL path];
}
#pragma mark Comparisons
- (BOOL)signingChainMatches:(SNTCodesignChecker *)otherChecker {
return [self.certificates isEqual:otherChecker.certificates];
}
- (BOOL)teamSigningMatches:(SNTCodesignChecker *)otherChecker {
SNTCertificate *myLeaf = [self.certificates firstObject];
SNTCertificate *otherLeaf = [otherChecker.certificates firstObject];
return ([myLeaf.orgUnit isEqual:otherLeaf.orgUnit] &&
[self validateAppleAnchorGeneric] &&
[otherChecker validateAppleAnchorGeneric]);
}
@end