#include "legacydevid.h"
#include "SecAssessment.h"
#include "requirement.h"
#include <Security/SecCertificatePriv.h>
namespace Security {
namespace CodeSigning {
static const CFStringRef kLegacyPolicyPreferenceDomain = CFSTR("com.apple.security.syspolicy");
static const CFStringRef kLegacyPolicyAccountCreationCutOff = CFSTR("AccountCreationCutOffDate");
static const CFStringRef kLegacyPolicySecureTimestampCutOff = CFSTR("SecureTimestampCutOffDate");
static const CFAbsoluteTime kLegacyPolicyAccountCreationDefaultCutOff = 576374400.0; static const CFAbsoluteTime kLegacyPolicySecureTimestampDefaultCutOff = 581040000.0;
static CFDateRef
copyCutOffDate(const CFStringRef key, CFAbsoluteTime defaultCutoff)
{
CFDateRef defaultDate = CFDateCreate(NULL, defaultCutoff);
CFDateRef outputDate = defaultDate;
CFDateRef prefDate = NULL;
CFTypeRef prefVal = (CFDateRef)CFPreferencesCopyValue(key,
kLegacyPolicyPreferenceDomain,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
if (prefVal && CFGetTypeID(prefVal) == CFDateGetTypeID()) {
prefDate = (CFDateRef)prefVal;
}
if (prefDate) {
CFComparisonResult res = CFDateCompare(defaultDate, prefDate, NULL);
if (res > 0) {
outputDate = prefDate;
}
}
CFRetain(outputDate);
if (prefVal) {
CFRelease(prefVal);
}
if (defaultDate) {
CFRelease(defaultDate);
}
return outputDate;
}
bool
meetsDeveloperIDLegacyAllowedPolicy(const Requirement::Context *context)
{
CFRef<CFDataRef> cd;
CFRef<CFErrorRef> error;
CFRef<CFStringRef> teamID;
bool meets_legacy_policy = false;
SecCSDigestAlgorithm hashType = kSecCodeSignatureNoHash;
SecCertificateRef cert = NULL;
CFAbsoluteTime accountCreationTime = 0.0;
if (context == NULL) {
meets_legacy_policy = false;
goto lb_exit;
}
cert = context->cert(Requirement::leafCert);
if (SecCertificateGetDeveloperIDDate(cert, &accountCreationTime, &error.aref())) {
CFRef<CFDateRef> accountCreationDate = CFDateCreate(NULL, accountCreationTime);
CFRef<CFDateRef> accountCreationCutoffDate = copyCutOffDate(kLegacyPolicyAccountCreationCutOff,
kLegacyPolicyAccountCreationDefaultCutOff);
secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Account Creation Date Cutoff: %@", accountCreationCutoffDate.get());
secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Account Creation date: %@", accountCreationDate.get());
CFComparisonResult res = CFDateCompare(accountCreationDate, accountCreationCutoffDate, NULL);
if (res >= 0) {
meets_legacy_policy = false;
secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Account creation date %@ is after cut-off %@", accountCreationDate.get(), accountCreationCutoffDate.get());
goto lb_exit;
}
} else {
CFIndex errorCode = CFErrorGetCode(error);
if (errorCode != errSecMissingRequiredExtension) {
secerror("Unexpected error checking account creation date: %ld", errorCode);
meets_legacy_policy = false;
goto lb_exit;
}
}
if (context->secureTimestamp) {
CFRef<CFDateRef> secureTimestampCutoffDate = copyCutOffDate(kLegacyPolicySecureTimestampCutOff,
kLegacyPolicySecureTimestampDefaultCutOff);
secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Secure Timestamp Cutoff Date cutoff: %@", secureTimestampCutoffDate.get());
secinfo("meetsDevleoperIDLegacyAllowedPolicy", "Secure Timestamp: %@", context->secureTimestamp);
CFComparisonResult res = CFDateCompare(context->secureTimestamp, secureTimestampCutoffDate, NULL);
if (res >= 0) {
meets_legacy_policy = false;
secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Secure timestamp %@ is after cut-off %@", context->secureTimestamp, secureTimestampCutoffDate.get());
} else {
meets_legacy_policy = true;
}
}
if (!meets_legacy_policy) {
if (context->directory) {
cd.take(context->directory->cdhash());
hashType = (SecCSDigestAlgorithm)context->directory->hashType;
} else if (context->packageChecksum) {
cd = context->packageChecksum;
hashType = context->packageAlgorithm;
}
if (cd.get() == NULL) {
meets_legacy_policy = false;
goto lb_exit;
}
if (context->teamIdentifier) {
teamID.take(CFStringCreateWithCString(kCFAllocatorDefault, context->teamIdentifier, kCFStringEncodingUTF8));
}
secnotice("legacy_list", "checking the legacy list for %d, %@, %@", hashType, cd.get(), teamID.get());
#if TARGET_OS_OSX
if (SecAssessmentLegacyCheck(cd, hashType, teamID, &error.aref())) {
meets_legacy_policy = true;
} else {
meets_legacy_policy = false;
if (error.get() != NULL) {
secerror("Error checking with notarization daemon: %ld", CFErrorGetCode(error));
}
}
#endif
}
lb_exit:
secnotice("legacy_list", "meetsDeveloperIDLegacyAllowedPolicy = %d", meets_legacy_policy);
return meets_legacy_policy;
}
}
}