#include "diskrep.h"
#include "codedirectory.h"
#include "csutilities.h"
+#include "notarization.h"
#include "StaticCode.h"
#include <CoreServices/CoreServicesPriv.h>
#include "SecCodePriv.h"
#undef check // Macro! Yech.
-extern "C" {
-#include <OpenScriptingUtilPriv.h>
-}
-
-
namespace Security {
namespace CodeSigning {
static void authorizeUpdate(SecAssessmentFlags flags, CFDictionaryRef context);
-static bool codeInvalidityExceptions(SecStaticCodeRef code, CFMutableDictionaryRef result);
static CFTypeRef installerPolicy() CF_RETURNS_RETAINED;
SQLite3::int64 disabled = query[6];
// const char *filter = query[7];
// const char *remarks = query[8];
-
- secdebug("gk", "considering rule %d(%s) requirement %s", int(id), label ? label : "UNLABELED", reqString);
+
+ secdebug("gk", "considering rule %d(%s) requirement %s", int(id), label ? label : "UNLABELED", reqString);
CFRef<SecRequirementRef> requirement;
MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly | kSecCSCheckGatekeeperArchitectures, requirement)) {
MacOSError::throwMe(rc); // general error; pass to caller
}
- // if this rule is disabled, skip it but record the first matching one for posterity
- if (disabled && latentID == 0) {
- latentID = id;
- latentLabel = label ? label : "";
+ // If this rule is disabled, do not continue any further and just continue iterating
+ // until we find one that is enabled.
+ if (disabled) {
+ // ...but always record the first matching rule for informational purposes.
+ if (latentID == 0) {
+ latentID = id;
+ latentLabel = label ? label : "";
+ }
continue;
}
-
+
// current rule is first rule (in priority order) that matched. Apply it
secnotice("gk", "rule %d applies - allow=%d", int(id), allow);
if (nested && allow) // success, nothing to record
}
CFCopyRef<SecStaticCodeRef> code;
- MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
+ MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags | kSecCSForceOnlineNotarizationCheck, &code.aref()));
SecCSFlags validationFlags = kSecCSEnforceRevocationChecks | kSecCSCheckAllArchitectures;
if (!(flags & kSecAssessmentFlagAllowWeak))
// deal with a very special case (broken 10.6/10.7 Applet bundles)
OSStatus rc = SecStaticCodeCheckValidity(code, validationFlags | kSecCSBasicValidateOnly, NULL);
if (rc == errSecCSSignatureFailed) {
- if (!codeInvalidityExceptions(code, result)) { // invalidly signed, no exceptions -> error
- if (SYSPOLICY_ASSESS_OUTCOME_BROKEN_ENABLED())
- SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, false);
- MacOSError::throwMe(rc);
- }
- // recognized exception - treat as unsigned
- if (SYSPOLICY_ASSESS_OUTCOME_BROKEN_ENABLED())
- SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, true);
- rc = errSecCSUnsigned;
+ MacOSError::throwMe(rc);
}
// ad-hoc sign unsigned code
}
return NULL;
}));
-
+
// go for it!
SecCSFlags topFlags = validationFlags | kSecCSCheckNestedCode | kSecCSRestrictSymlinks | kSecCSReportProgress;
if (type == kAuthorityExecute && !appOk)
default:
MacOSError::throwMe(rc);
}
+
+ // Copy notarization date, if present, from code signing information
+ CFRef<CFDictionaryRef> info;
+ OSStatus status = SecCodeCopySigningInformation(code, kSecCSInternalInformation, &info.aref());
+ if (status == 0 && info) {
+ CFDateRef date = (CFDateRef)CFDictionaryGetValue(info, kSecCodeInfoNotarizationDate);
+ if (date) {
+ cfadd(result, "{%O=%O}", kSecAssessmentAssessmentNotarizationDate, date);
+ }
+ } else {
+ secerror("Unable to copy signing information: %d", (int)status);
+ }
if (nestedFailure && CFEqual(CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict), kCFBooleanTrue)) {
// structure intact, top level approved, nested code failed policy
if (CFRef<CFArrayRef> certs = xar.copyCertChain()) {
CFRef<CFTypeRef> policy = installerPolicy();
CFRef<SecTrustRef> trust;
+ CFRef<CFDataRef> checksum;
+ CFRef<CFStringRef> teamID;
+ CFRef<CFMutableDictionaryRef> requirementContext = makeCFMutableDictionary();
MacOSError::check(SecTrustCreateWithCertificates(certs, policy, &trust.aref()));
// MacOSError::check(SecTrustSetAnchorCertificates(trust, cfEmptyArray())); // no anchors
MacOSError::check(SecTrustSetOptions(trust, kSecTrustOptionAllowExpired | kSecTrustOptionImplicitAnchors));
}
}
+ xar.registerStapledNotarization();
+ checksum.take(xar.createPackageChecksum());
+ if (checksum) {
+ double notarizationDate = NAN;
+
+ // Force a single online check for the checksum, which is always SHA1.
+ bool is_revoked = checkNotarizationServiceForRevocation(checksum, kSecCodeSignatureHashSHA1, ¬arizationDate);
+ if (is_revoked) {
+ MacOSError::throwMe(errSecCSRevokedNotarization);
+ }
+
+ // Extract a team identifier from the certificates. This isn't validated and could be spoofed,
+ // but since the 'legacy' keyword is only used in addition to the Developer ID requirement,
+ // this is still stafe for now.
+ SecCertificateRef leaf = SecCertificateRef(CFArrayGetValueAtIndex(certs, 0));
+ CFRef<CFArrayRef> orgUnits = SecCertificateCopyOrganizationalUnit(leaf);
+ if (orgUnits.get() && CFArrayGetCount(orgUnits) == 1) {
+ teamID = (CFStringRef)CFArrayGetValueAtIndex(orgUnits, 0);
+ }
+
+ // Create the appropriate requirement context entry to allow notarized requirement check.
+ CFRef<CFNumberRef> algorithm = makeCFNumber((uint32_t)xar.checksumDigestAlgorithm());
+ cfadd(requirementContext, "{%O=%O}", kSecRequirementKeyPackageChecksum, checksum.get());
+ cfadd(requirementContext, "{%O=%O}", kSecRequirementKeyChecksumAlgorithm, algorithm.get());
+ if (teamID.get()) {
+ cfadd(requirementContext, "{%O=%O}", kSecRequirementKeyTeamIdentifier, teamID.get());
+ }
+
+ if (!isnan(notarizationDate)) {
+ CFRef<CFDateRef> date = CFDateCreate(NULL, notarizationDate);
+ if (date) {
+ cfadd(result, "{%O=%O}", kSecAssessmentAssessmentNotarizationDate, date.get());
+ }
+ }
+ }
+
SQLite::Statement query(*this,
"SELECT allow, requirement, id, label, flags, disabled FROM scan_authority"
" WHERE type = :type"
const char *label = query[3];
//sqlite_uint64 ruleFlags = query[4];
SQLite3::int64 disabled = query[5];
-
+
CFRef<SecRequirementRef> requirement;
MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
- switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, NULL, kSecCSDefaultFlags)) {
+ switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, requirementContext.get(), kSecCSDefaultFlags)) {
case errSecSuccess: // success
break;
case errSecCSReqFailed: // requirement missed, but otherwise okay
}
MacOSError::check(rc);
case errSecCSSignatureFailed:
- // recover certain cases of broken signatures (well, try)
- if (codeInvalidityExceptions(code, NULL)) {
- // Ad-hoc sign the code in place (requiring a writable subject). This requires root privileges.
- CFRef<SecCodeSignerRef> signer;
- CFTemp<CFDictionaryRef> arguments("{%O=#N}", kSecCodeSignerIdentity);
- MacOSError::check(SecCodeSignerCreate(arguments, kSecCSSignOpaque, &signer.aref()));
- MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags));
- MacOSError::check(SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref()));
- break;
- }
- MacOSError::check(rc);
default:
MacOSError::check(rc);
}
}
}
-
-//
-// Process special overrides for invalidly signed code.
-// This is the (hopefully minimal) concessions we make to keep hurting our customers
-// for our own prior mistakes...
-//
-static bool codeInvalidityExceptions(SecStaticCodeRef code, CFMutableDictionaryRef result)
-{
- CFRef<CFDictionaryRef> info;
- MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
- if (CFURLRef executable = CFURLRef(CFDictionaryGetValue(info, kSecCodeInfoMainExecutable))) {
- SInt32 error;
- if (OSAIsRecognizedExecutableURL(executable, &error)) {
- if (result)
- CFDictionaryAddValue(result,
- kSecAssessmentAssessmentAuthorityOverride, CFSTR("ignoring known invalid applet signature"));
- return true;
- }
- }
- return false;
-}
-
-
} // end namespace CodeSigning
} // end namespace Security