Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore TeamID and SigningID rules for dev signed code #1241

Merged
merged 4 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ objc_library(
"//Source/common:SNTDeepCopy",
"//Source/common:SNTFileInfo",
"//Source/common:SNTLogging",
"//Source/common:SNTMetricSet",
"//Source/common:SNTRule",
"@FMDB",
"@MOLCertificate",
Expand Down
120 changes: 46 additions & 74 deletions Source/santad/SNTPolicyProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#import "Source/santad/SNTPolicyProcessor.h"
#include <Foundation/Foundation.h>

#include <Availability.h>
#include <Kernel/kern/cs_blobs.h>
#import <MOLCodesignChecker/MOLCodesignChecker.h>
#import <Security/SecCode.h>
Expand All @@ -26,22 +25,12 @@
#import "Source/common/SNTDeepCopy.h"
#import "Source/common/SNTFileInfo.h"
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTMetricSet.h"
#import "Source/common/SNTRule.h"
#import "Source/santad/DataLayer/SNTRuleTable.h"

NSArray<NSString *> *FieldValuesForProperties(BOOL csDevFlagSet, BOOL validationCategoryThree,
BOOL oidsSet) {
#define SNT_BOOL_STR(b) (b) ? @"True" : @"False"
return
@[ SNT_BOOL_STR(csDevFlagSet), SNT_BOOL_STR(validationCategoryThree), SNT_BOOL_STR(oidsSet) ];
#undef SNT_BOOL_STR
}

@interface SNTPolicyProcessor ()
@property SNTRuleTable *ruleTable;
@property SNTConfigurator *configurator;
@property SNTMetricCounter *experimentalDevMetrics;
@end

@implementation SNTPolicyProcessor
Expand All @@ -51,11 +40,6 @@ - (instancetype)initWithRuleTable:(SNTRuleTable *)ruleTable {
if (self) {
_ruleTable = ruleTable;
_configurator = [SNTConfigurator configurator];

_experimentalDevMetrics = [[SNTMetricSet sharedInstance]
counterWithName:@"/santa/tmp_signing_info_experiment"
fieldNames:@[ @"CSDevFlagSet", @"ValidationCategory", @"DevOIDSet" ]
helpText:@"Temporary experiment for dev signed code"];
}
return self;
}
Expand All @@ -65,7 +49,7 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn
certificateSHA256:(nullable NSString *)certificateSHA256
teamID:(nullable NSString *)teamID
signingID:(nullable NSString *)signingID
targetProcess:(nullable const es_process_t *)targetProc
isProdSignedCallback:(BOOL (^_Nonnull)())isProdSignedCallback
entitlementsFilterCallback:
(NSDictionary *_Nullable (^_Nullable)(
NSDictionary *_Nullable entitlements))entitlementsFilterCallback {
Expand Down Expand Up @@ -126,57 +110,23 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn
cd.entitlements = [entitlements sntDeepCopy];
cd.entitlementsFiltered = NO;
}

#if defined(MAC_OS_VERSION_13_3) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_3
if (@available(macOS 13.0, *)) {
// Temporary experiment code...
if (targetProc != NULL && fileInfo.path != nil) {
// Doing a second SecStaticCodeCreate to not need to worry about modifying the
// dependency...
SecStaticCodeRef codeRef = NULL;
OSStatus status = SecStaticCodeCreateWithPath(
(__bridge CFURLRef)[NSURL fileURLWithPath:fileInfo.path], kSecCSDefaultFlags, &codeRef);
if (status == errSecSuccess) {
CFDictionaryRef cfSigningInfo = NULL;
SecCodeCopySigningInformation(
codeRef, kSecCSSigningInformation | kSecCSRequirementInformation, &cfSigningInfo);
NSDictionary *signingInfo = CFBridgingRelease(cfSigningInfo);

// Taken from Security framework: LWCRHelper.mm
NSString *reqVaidationCategryKey = @"validation-category";
// Taken from Security framework:
NSArray *keys = @[ @"1.2.840.113635.100.6.1.2", @"1.2.840.113635.100.6.1.12" ];
NSDictionary *lwCodeReq = signingInfo[(
__bridge NSString *)kSecCodeInfoDefaultDesignatedLightweightCodeRequirement];

NSDictionary *vals = CFBridgingRelease(SecCertificateCopyValues(
csInfo.leafCertificate.certRef, (__bridge CFArrayRef)keys, NULL));

BOOL validationCategoryThree = [lwCodeReq[reqVaidationCategryKey] intValue] == 3;
BOOL csDevFlagSet = ((targetProc->codesigning_flags & CS_DEV_CODE) != 0);
BOOL oidsSet = vals.count > 0;

[self.experimentalDevMetrics
incrementForFieldValues:FieldValuesForProperties(csDevFlagSet,
validationCategoryThree, oidsSet)];

if (!(csDevFlagSet == validationCategoryThree && csDevFlagSet == oidsSet)) {
NSDictionary *certVals = CFBridgingRelease(
SecCertificateCopyValues(csInfo.leafCertificate.certRef, NULL, NULL));
LOGI(@"EXPERIMENTAL Unexpected state difference: %@ | Flags(%d): 0x%08x, VC(%d): %d, "
@"oids(%d): %@",
fileInfo.path, csDevFlagSet, targetProc->codesigning_flags,
validationCategoryThree, [lwCodeReq[reqVaidationCategryKey] intValue], oidsSet,
[certVals allKeys]);
}
}
}
}
#endif
}
}
cd.quarantineURL = fileInfo.quarantineDataURL;

// Do not evaluate TeamID/SigningID rules for dev-signed code based on the
// assumption that orgs are generally more relaxed about dev signed cert
// protections and users can more easily produce dev-signed code that
// would otherwise be inadvertently allowed.
// Note: Only perform the check if the SigningID is still set, otherwise
// it is unsigned or had issues above that already cleared the values.
if (cd.signingID && !isProdSignedCallback()) {
LOGD(@"Ignoring TeamID and SigningID rules for code not signed with production cert: %@",
cd.signingID);
cd.teamID = nil;
cd.signingID = nil;
}

SNTRule *rule = [self.ruleTable ruleForBinarySHA256:cd.sha256
signingID:cd.signingID
certificateSHA256:cd.certSHA256
Expand Down Expand Up @@ -328,14 +278,16 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn
}

return [self decisionForFileInfo:fileInfo
fileSHA256:nil
certificateSHA256:nil
teamID:teamID
signingID:signingID
targetProcess:targetProc
entitlementsFilterCallback:^NSDictionary *(NSDictionary *entitlements) {
return entitlementsFilterCallback(entitlementsFilterTeamID, entitlements);
}];
fileSHA256:nil
certificateSHA256:nil
teamID:teamID
signingID:signingID
isProdSignedCallback:^BOOL() {
return ((targetProc->codesigning_flags & CS_DEV_CODE) == 0);
}
entitlementsFilterCallback:^NSDictionary *(NSDictionary *entitlements) {
mlw marked this conversation as resolved.
Show resolved Hide resolved
return entitlementsFilterCallback(entitlementsFilterTeamID, entitlements);
}];
}

// Used by `$ santactl fileinfo`.
Expand All @@ -345,15 +297,35 @@ - (nonnull SNTCachedDecision *)decisionForFilePath:(nonnull NSString *)filePath
teamID:(nullable NSString *)teamID
signingID:(nullable NSString *)signingID {
SNTFileInfo *fileInfo;
MOLCodesignChecker *csInfo;
NSError *error;

fileInfo = [[SNTFileInfo alloc] initWithPath:filePath error:&error];
mlw marked this conversation as resolved.
Show resolved Hide resolved
if (!fileInfo) LOGW(@"Failed to read file %@: %@", filePath, error.localizedDescription);
if (!fileInfo) {
LOGW(@"Failed to read file %@: %@", filePath, error.localizedDescription);
} else {
csInfo = [fileInfo codesignCheckerWithError:&error];
if (error) {
LOGW(@"Failed to get codesign ingo for file %@: %@", filePath, error.localizedDescription);
}
}

return [self decisionForFileInfo:fileInfo
fileSHA256:fileSHA256
certificateSHA256:certificateSHA256
teamID:teamID
signingID:signingID
targetProcess:NULL
isProdSignedCallback:^BOOL() {
mlw marked this conversation as resolved.
Show resolved Hide resolved
if (csInfo) {
// Development OID values taken from Security framework
mlw marked this conversation as resolved.
Show resolved Hide resolved
NSArray *keys = @[ @"1.2.840.113635.100.6.1.2", @"1.2.840.113635.100.6.1.12" ];
NSDictionary *vals = CFBridgingRelease(SecCertificateCopyValues(
csInfo.leafCertificate.certRef, (__bridge CFArrayRef)keys, NULL));
return vals.count == 0;
} else {
return NO;
}
}
entitlementsFilterCallback:nil];
}

Expand Down