]> git.saurik.com Git - apple/libsecurity_codesigning.git/blobdiff - lib/reqinterp.cpp
libsecurity_codesigning-36885.tar.gz
[apple/libsecurity_codesigning.git] / lib / reqinterp.cpp
index b661b178ba9910af053f99be03cb020354236f10..207efd88fdc26ade29f88a3786188f5085f4f9af 100644 (file)
 // reqinterp - Requirement language (exprOp) interpreter
 //
 #include "reqinterp.h"
 // reqinterp - Requirement language (exprOp) interpreter
 //
 #include "reqinterp.h"
+#include "codesigning_dtrace.h"
 #include <Security/SecTrustSettingsPriv.h>
 #include <Security/SecCertificatePriv.h>
 #include <security_utilities/memutils.h>
 #include <Security/SecTrustSettingsPriv.h>
 #include <Security/SecCertificatePriv.h>
 #include <security_utilities/memutils.h>
-#include <security_cdsa_utilities/cssmdata.h>  // for hex encoding
 #include "csutilities.h"
 
 namespace Security {
 #include "csutilities.h"
 
 namespace Security {
@@ -57,6 +57,7 @@ Requirement::Interpreter::Interpreter(const Requirement *req, const Context *ctx
 bool Requirement::Interpreter::evaluate()
 {
        ExprOp op = ExprOp(get<uint32_t>());
 bool Requirement::Interpreter::evaluate()
 {
        ExprOp op = ExprOp(get<uint32_t>());
+       CODESIGN_EVAL_REQINT_OP(op, this->pc() - sizeof(uint32_t));
        switch (op & ~opFlagMask) {
        case opFalse:
                return false;
        switch (op & ~opFlagMask) {
        case opFalse:
                return false;
@@ -66,6 +67,8 @@ bool Requirement::Interpreter::evaluate()
                return getString() == mContext->directory->identifier();
        case opAppleAnchor:
                return appleSigned();
                return getString() == mContext->directory->identifier();
        case opAppleAnchor:
                return appleSigned();
+       case opAppleGenericAnchor:
+               return appleAnchored();
        case opAnchorHash:
                {
                        SecCertificateRef cert = mContext->cert(get<int32_t>());
        case opAnchorHash:
                {
                        SecCertificateRef cert = mContext->cert(get<int32_t>());
@@ -77,9 +80,9 @@ bool Requirement::Interpreter::evaluate()
                        return infoKeyValue(key, Match(CFTempString(getString()), matchEqual));
                }
        case opAnd:
                        return infoKeyValue(key, Match(CFTempString(getString()), matchEqual));
                }
        case opAnd:
-               return evaluate() && evaluate();
+               return evaluate() & evaluate();
        case opOr:
        case opOr:
-               return evaluate() || evaluate();
+               return evaluate() | evaluate();
        case opCDHash:
                {
                        SHA1 hash;
        case opCDHash:
                {
                        SHA1 hash;
@@ -94,6 +97,12 @@ bool Requirement::Interpreter::evaluate()
                        Match match(*this);
                        return infoKeyValue(key, match);
                }
                        Match match(*this);
                        return infoKeyValue(key, match);
                }
+       case opEntitlementField:
+               {
+                       string key = getString();
+                       Match match(*this);
+                       return entitlementValue(key, match);
+               }
        case opCertField:
                {
                        SecCertificateRef cert = mContext->cert(get<int32_t>());
        case opCertField:
                {
                        SecCertificateRef cert = mContext->cert(get<int32_t>());
@@ -101,6 +110,13 @@ bool Requirement::Interpreter::evaluate()
                        Match match(*this);
                        return certFieldValue(key, match, cert);
                }
                        Match match(*this);
                        return certFieldValue(key, match, cert);
                }
+       case opCertGeneric:
+               {
+                       SecCertificateRef cert = mContext->cert(get<int32_t>());
+                       string key = getString();
+                       Match match(*this);
+                       return certFieldGeneric(key, match, cert);
+               }
        case opTrustedCert:
                return trustedCert(get<int32_t>());
        case opTrustedCerts:
        case opTrustedCert:
                return trustedCert(get<int32_t>());
        case opTrustedCerts:
@@ -111,10 +127,10 @@ bool Requirement::Interpreter::evaluate()
                        // unknown opcode, but it has a size field and can be safely bypassed
                        skip(get<uint32_t>());
                        if (op & opGenericFalse) {
                        // unknown opcode, but it has a size field and can be safely bypassed
                        skip(get<uint32_t>());
                        if (op & opGenericFalse) {
-                               secdebug("csinterp", "opcode 0x%x interpreted as false", op);
+                               CODESIGN_EVAL_REQINT_UNKNOWN_FALSE(op);
                                return false;
                        } else {
                                return false;
                        } else {
-                               secdebug("csinterp", "opcode 0x%x ignored; continuing", op);
+                               CODESIGN_EVAL_REQINT_UNKNOWN_SKIPPED(op);
                                return evaluate();
                        }
                }
                                return evaluate();
                        }
                }
@@ -137,6 +153,18 @@ bool Requirement::Interpreter::infoKeyValue(const string &key, const Match &matc
 }
 
 
 }
 
 
+//
+// Evaluate an entitlement condition
+//
+bool Requirement::Interpreter::entitlementValue(const string &key, const Match &match)
+{
+       if (mContext->entitlements)             // we have an Info.plist
+               if (CFTypeRef value = CFDictionaryGetValue(mContext->entitlements, CFTempString(key)))
+                       return match(value);
+       return false;
+}
+
+
 bool Requirement::Interpreter::certFieldValue(const string &key, const Match &match, SecCertificateRef cert)
 {
        // no cert, no chance
 bool Requirement::Interpreter::certFieldValue(const string &key, const Match &match, SecCertificateRef cert)
 {
        // no cert, no chance
@@ -158,38 +186,51 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
                { "subject.STREET", &CSSMOID_StreetAddress },
                { NULL, NULL }
        };
                { "subject.STREET", &CSSMOID_StreetAddress },
                { NULL, NULL }
        };
-
-       // email multi-valued match (any of...)
-       if (key == "email") {
-               CFRef<CFArrayRef> value;
-               if (IFDEBUG(OSStatus rc =) SecCertificateCopyEmailAddresses(cert, &value.aref())) {
-                       secdebug("csinterp", "cert %p lookup for email failed rc=%ld", cert, rc);
-                       return false;
-               }
-               return match(value);
-       }
        
        // DN-component single-value match
        for (const CertField *cf = certFields; cf->name; cf++)
                if (cf->name == key) {
                        CFRef<CFStringRef> value;
        
        // DN-component single-value match
        for (const CertField *cf = certFields; cf->name; cf++)
                if (cf->name == key) {
                        CFRef<CFStringRef> value;
-                       if (IFDEBUG(OSStatus rc =) SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
+                       if (OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
                                secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%ld", cert, key.c_str(), rc);
                                return false;
                        }
                        return match(value);
                }
 
                                secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%ld", cert, key.c_str(), rc);
                                return false;
                        }
                        return match(value);
                }
 
+       // email multi-valued match (any of...)
+       if (key == "email") {
+               CFRef<CFArrayRef> value;
+               if (OSStatus rc = SecCertificateCopyEmailAddresses(cert, &value.aref())) {
+                       secdebug("csinterp", "cert %p lookup for email failed rc=%ld", cert, rc);
+                       return false;
+               }
+               return match(value);
+       }
+
        // unrecognized key. Fail but do not abort to promote backward compatibility down the road
        secdebug("csinterp", "cert field notation \"%s\" not understood", key.c_str());
        return false;
 }
 
 
        // unrecognized key. Fail but do not abort to promote backward compatibility down the road
        secdebug("csinterp", "cert field notation \"%s\" not understood", key.c_str());
        return false;
 }
 
 
+bool Requirement::Interpreter::certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert)
+{
+       // the key is actually a (binary) OID value
+       CssmOid oid((char *)key.data(), key.length());
+       return certFieldGeneric(oid, match, cert);
+}
+
+bool Requirement::Interpreter::certFieldGeneric(const CssmOid &oid, const Match &match, SecCertificateRef cert)
+{
+       return cert && certificateHasField(cert, oid) && match(kCFBooleanTrue);
+}
+
+
 //
 // Check the Apple-signed condition
 //
 //
 // Check the Apple-signed condition
 //
-bool Requirement::Interpreter::appleSigned()
+bool Requirement::Interpreter::appleAnchored()
 {
        if (SecCertificateRef cert = mContext->cert(anchorCert))
                if (verifyAnchor(cert, appleAnchorHash())
 {
        if (SecCertificateRef cert = mContext->cert(anchorCert))
                if (verifyAnchor(cert, appleAnchorHash())
@@ -197,11 +238,18 @@ bool Requirement::Interpreter::appleSigned()
                        || verifyAnchor(cert, testAppleAnchorHash())
 #endif
                )
                        || verifyAnchor(cert, testAppleAnchorHash())
 #endif
                )
-                       if (SecCertificateRef intermed = mContext->cert(-2))    // first intermediate
-                               // first intermediate common name match (exact)
-                               if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
+               return true;
+       return false;
+}
+
+bool Requirement::Interpreter::appleSigned()
+{
+       if (appleAnchored())
+               if (SecCertificateRef intermed = mContext->cert(-2))    // first intermediate
+                       // first intermediate common name match (exact)
+                       if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
                                        && certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
                                        && certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
-                                       return true;
+                               return true;
        return false;
 }
 
        return false;
 }
 
@@ -327,10 +375,18 @@ Requirement::Interpreter::Match::Match(Interpreter &interp)
                break;
        case matchEqual:
        case matchContains:
                break;
        case matchEqual:
        case matchContains:
+       case matchBeginsWith:
+       case matchEndsWith:
+       case matchLessThan:
+       case matchGreaterThan:
+       case matchLessEqual:
+       case matchGreaterEqual:
                mValue = makeCFString(interp.getString());
                break;
        default:
                mValue = makeCFString(interp.getString());
                break;
        default:
-               assert(false);
+               // Assume this (unknown) match type has a single data argument.
+               // This gives us a chance to keep the instruction stream aligned.
+               interp.getString();                     // discard
                break;
        }
 }
                break;
        }
 }
@@ -366,12 +422,49 @@ bool Requirement::Interpreter::Match::operator () (CFTypeRef candidate) const
                                return true;
                }
                return false;
                                return true;
                }
                return false;
+       case matchBeginsWith:
+               if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+                       CFStringRef value = CFStringRef(candidate);
+                       if (CFStringFindWithOptions(value, mValue, CFRangeMake(0, CFStringGetLength(mValue)), 0, NULL))
+                               return true;
+               }
+               return false;
+       case matchEndsWith:
+               if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+                       CFStringRef value = CFStringRef(candidate);
+                       CFIndex matchLength = CFStringGetLength(mValue);
+                       CFIndex start = CFStringGetLength(value) - matchLength;
+                       if (start >= 0)
+                               if (CFStringFindWithOptions(value, mValue, CFRangeMake(start, matchLength), 0, NULL))
+                                       return true;
+               }
+               return false;
+       case matchLessThan:
+               return inequality(candidate, kCFCompareNumerically, kCFCompareLessThan, true);
+       case matchGreaterThan:
+               return inequality(candidate, kCFCompareNumerically, kCFCompareGreaterThan, true);
+       case matchLessEqual:
+               return inequality(candidate, kCFCompareNumerically, kCFCompareGreaterThan, false);
+       case matchGreaterEqual:
+               return inequality(candidate, kCFCompareNumerically, kCFCompareLessThan, false);
        default:
        default:
-               assert(false);
+               // unrecognized match types can never match
                return false;
        }
 }
 
 
                return false;
        }
 }
 
 
+bool Requirement::Interpreter::Match::inequality(CFTypeRef candidate, CFStringCompareFlags flags,
+       CFComparisonResult outcome, bool negate) const
+{
+       if (CFGetTypeID(candidate) == CFStringGetTypeID()) {
+               CFStringRef value = CFStringRef(candidate);
+               if ((CFStringCompare(value, mValue, flags) == outcome) == negate)
+                       return true;
+       }
+       return false;
+}
+
+
 }      // CodeSigning
 }      // Security
 }      // CodeSigning
 }      // Security