//
// reqinterp - Requirement language (exprOp) interpreter
//
+
#include "reqinterp.h"
#include "codesigning_dtrace.h"
#include <Security/SecTrustSettingsPriv.h>
#include <IOKit/IOCFUnserialize.h>
#include "csutilities.h"
#include "notarization.h"
+#include "legacydevid.h"
namespace Security {
namespace CodeSigning {
Match match(*this);
return certFieldGeneric(key, match, cert);
}
+ case opCertFieldDate:
+ {
+ SecCertificateRef cert = mContext->cert(get<int32_t>());
+ string key = getString();
+ Match match(*this);
+ return certFieldDate(key, match, cert);
+ }
case opCertPolicy:
{
SecCertificateRef cert = mContext->cert(get<int32_t>());
{
return isNotarized(mContext);
}
+ case opLegacyDevID:
+ {
+ return meetsDeveloperIDLegacyAllowedPolicy(mContext);
+ }
default:
// opcode not recognized - handle generically if possible, fail otherwise
if (op & (opGenericFalse | opGenericSkip)) {
if (mContext->info) // we have an Info.plist
if (CFTypeRef value = CFDictionaryGetValue(mContext->info, CFTempString(key)))
return match(value);
- return false;
+ return match(kCFNull);
}
if (mContext->entitlements) // we have an Info.plist
if (CFTypeRef value = CFDictionaryGetValue(mContext->entitlements, CFTempString(key)))
return match(value);
- return false;
+ return match(kCFNull);
}
bool Requirement::Interpreter::certFieldGeneric(const CssmOid &oid, const Match &match, SecCertificateRef cert)
{
- return cert && certificateHasField(cert, oid) && match(kCFBooleanTrue);
+ return cert && match(certificateHasField(cert, oid) ? (CFTypeRef)kCFBooleanTrue : (CFTypeRef)kCFNull);
+}
+
+bool Requirement::Interpreter::certFieldDate(const string &key, const Match &match, SecCertificateRef cert)
+{
+ // the key is actually a (binary) OID value
+ CssmOid oid((char *)key.data(), key.length());
+ return certFieldDate(oid, match, cert);
+}
+
+bool Requirement::Interpreter::certFieldDate(const CssmOid &oid, const Match &match, SecCertificateRef cert)
+{
+ CFTypeRef value = cert != NULL ? certificateCopyFieldDate(cert, oid) : NULL;
+ bool matching = match(value != NULL ? value : kCFNull);
+
+ if (value) {
+ CFRelease(value);
+ }
+
+ return matching;
}
bool Requirement::Interpreter::certFieldPolicy(const string &key, const Match &match, SecCertificateRef cert)
bool Requirement::Interpreter::certFieldPolicy(const CssmOid &oid, const Match &match, SecCertificateRef cert)
{
- return cert && certificateHasPolicy(cert, oid) && match(kCFBooleanTrue);
+ return cert && match(certificateHasPolicy(cert, oid) ? (CFTypeRef)kCFBooleanTrue : (CFTypeRef)kCFNull);
}
#endif
Requirement::Interpreter::Match::Match(Interpreter &interp)
{
switch (mOp = interp.get<MatchOperation>()) {
+ case matchAbsent:
case matchExists:
break;
case matchEqual:
case matchGreaterEqual:
mValue.take(makeCFString(interp.getString()));
break;
+ case matchOn:
+ case matchBefore:
+ case matchAfter:
+ case matchOnOrBefore:
+ case matchOnOrAfter: {
+ mValue.take(CFDateCreate(NULL, interp.getAbsoluteTime()));
+ break;
+ }
default:
// Assume this (unknown) match type has a single data argument.
// This gives us a chance to keep the instruction stream aligned.
if (!candidate)
return false;
+ if (candidate == kCFNull) {
+ return mOp == matchAbsent; // only 'absent' matches
+ }
+
// interpret an array as matching alternatives (any one succeeds)
if (CFGetTypeID(candidate) == CFArrayGetTypeID()) {
CFArrayRef array = CFArrayRef(candidate);
}
switch (mOp) {
+ case matchAbsent:
+ return false; // it exists, so it cannot be absent
case matchExists: // anything but NULL and boolean false "exists"
return !CFEqual(candidate, kCFBooleanFalse);
case matchEqual: // equality works for all CF types
return CFEqual(candidate, mValue);
case matchContains:
- if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+ if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
CFStringRef value = CFStringRef(candidate);
- if (CFStringFindWithOptions(value, mValue, CFRangeMake(0, CFStringGetLength(value)), 0, NULL))
+ if (CFStringFindWithOptions(value, cfStringValue(), CFRangeMake(0, CFStringGetLength(value)), 0, NULL))
return true;
}
return false;
case matchBeginsWith:
- if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+ if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
CFStringRef value = CFStringRef(candidate);
- if (CFStringFindWithOptions(value, mValue, CFRangeMake(0, CFStringGetLength(mValue)), 0, NULL))
+ if (CFStringFindWithOptions(value, cfStringValue(), CFRangeMake(0, CFStringGetLength(cfStringValue())), 0, NULL))
return true;
}
return false;
case matchEndsWith:
- if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+ if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
CFStringRef value = CFStringRef(candidate);
- CFIndex matchLength = CFStringGetLength(mValue);
+ CFIndex matchLength = CFStringGetLength(cfStringValue());
CFIndex start = CFStringGetLength(value) - matchLength;
if (start >= 0)
- if (CFStringFindWithOptions(value, mValue, CFRangeMake(start, matchLength), 0, NULL))
+ if (CFStringFindWithOptions(value, cfStringValue(), CFRangeMake(start, matchLength), 0, NULL))
return true;
}
return false;
return inequality(candidate, kCFCompareNumerically, kCFCompareGreaterThan, false);
case matchGreaterEqual:
return inequality(candidate, kCFCompareNumerically, kCFCompareLessThan, false);
+ case matchOn:
+ case matchBefore:
+ case matchAfter:
+ case matchOnOrBefore:
+ case matchOnOrAfter: {
+ if (!isDateValue() || CFGetTypeID(candidate) != CFDateGetTypeID()) {
+ return false;
+ }
+
+ CFComparisonResult res = CFDateCompare((CFDateRef)candidate, cfDateValue(), NULL);
+
+ switch (mOp) {
+ case matchOn: return res == 0;
+ case matchBefore: return res < 0;
+ case matchAfter: return res > 0;
+ case matchOnOrBefore: return res <= 0;
+ case matchOnOrAfter: return res >= 0;
+ default: abort();
+ }
+ }
default:
// unrecognized match types can never match
return false;
bool Requirement::Interpreter::Match::inequality(CFTypeRef candidate, CFStringCompareFlags flags,
CFComparisonResult outcome, bool negate) const
{
- if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+ if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
CFStringRef value = CFStringRef(candidate);
- if ((CFStringCompare(value, mValue, flags) == outcome) == negate)
+ if ((CFStringCompare(value, cfStringValue(), flags) == outcome) == negate)
return true;
}
return false;