2 * Copyright (c) 2006,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 // reqinterp - Requirement language (exprOp) interpreter
28 #include "reqinterp.h"
29 #include "codesigning_dtrace.h"
30 #include <Security/SecTrustSettingsPriv.h>
31 #include <Security/SecCertificatePriv.h>
32 #include <security_utilities/memutils.h>
33 #include <security_utilities/logging.h>
35 #include <IOKit/IOKitLib.h>
36 #include <IOKit/IOCFUnserialize.h>
37 #include <libDER/oids.h>
38 #include "csutilities.h"
39 #include "notarization.h"
40 #include "legacydevid.h"
42 #define WAITING_FOR_LIB_AMFI_INTERFACE 1
44 #if WAITING_FOR_LIB_AMFI_INTERFACE
45 #define __mac_syscall __sandbox_ms
46 #include <security/mac.h>
48 #define AMFI_INTF_CD_HASH_LEN 20
52 namespace CodeSigning
{
56 // Fragment fetching, caching, and evaluation.
58 // Several language elements allow "calling" of separate requirement programs
59 // stored on disk as (binary) requirement blobs. The Fragments class takes care
60 // of finding, loading, caching, and evaluating them.
62 // This is a singleton for (process global) caching. It works fine as multiple instances,
63 // at a loss of caching effectiveness.
69 bool named(const std::string
&name
, const Requirement::Context
&ctx
)
70 { return evalNamed("subreq", name
, ctx
); }
71 bool namedAnchor(const std::string
&name
, const Requirement::Context
&ctx
)
72 { return evalNamed("anchorreq", name
, ctx
); }
75 bool evalNamed(const char *type
, const std::string
&name
, const Requirement::Context
&ctx
);
76 CFDataRef
fragment(const char *type
, const std::string
&name
);
78 typedef std::map
<std::string
, CFRef
<CFDataRef
> > FragMap
;
81 CFBundleRef mMyBundle
; // Security.framework bundle
82 Mutex mLock
; // lock for all of the below...
83 FragMap mFragments
; // cached fragments
86 static ModuleNexus
<Fragments
> fragments
;
90 // Magic certificate features
92 static CFStringRef appleIntermediateCN
= CFSTR("Apple Code Signing Certification Authority");
93 static CFStringRef appleIntermediateO
= CFSTR("Apple Inc.");
97 // Main interpreter function.
99 // ExprOp code is in Polish Notation (operator followed by operands),
100 // and this engine uses opportunistic evaluation.
102 bool Requirement::Interpreter::evaluate()
103 { return eval(stackLimit
); }
105 bool Requirement::Interpreter::eval(int depth
)
107 if (--depth
<= 0) // nested too deeply - protect the stack
108 MacOSError::throwMe(errSecCSReqInvalid
);
110 ExprOp op
= ExprOp(get
<uint32_t>());
111 CODESIGN_EVAL_REQINT_OP(op
, this->pc() - sizeof(uint32_t));
112 switch (op
& ~opFlagMask
) {
118 return mContext
->directory
&& getString() == mContext
->directory
->identifier();
120 return appleSigned();
121 case opAppleGenericAnchor
:
122 return appleAnchored();
125 SecCertificateRef cert
= mContext
->cert(get
<int32_t>());
126 return verifyAnchor(cert
, getSHA1());
128 case opInfoKeyValue
: // [legacy; use opInfoKeyField]
130 string key
= getString();
131 return infoKeyValue(key
, Match(CFTempString(getString()), matchEqual
));
134 return eval(depth
) & eval(depth
);
136 return eval(depth
) | eval(depth
);
138 if (mContext
->directory
) {
139 CFRef
<CFDataRef
> cdhash
= mContext
->directory
->cdhash();
140 CFRef
<CFDataRef
> required
= getHash();
141 return CFEqual(cdhash
, required
);
148 string key
= getString();
150 return infoKeyValue(key
, match
);
152 case opEntitlementField
:
154 string key
= getString();
156 return entitlementValue(key
, match
);
160 SecCertificateRef cert
= mContext
->cert(get
<int32_t>());
161 string key
= getString();
163 return certFieldValue(key
, match
, cert
);
168 SecCertificateRef cert
= mContext
->cert(get
<int32_t>());
169 string key
= getString();
171 return certFieldGeneric(key
, match
, cert
);
173 case opCertFieldDate
:
175 SecCertificateRef cert
= mContext
->cert(get
<int32_t>());
176 string key
= getString();
178 return certFieldDate(key
, match
, cert
);
182 SecCertificateRef cert
= mContext
->cert(get
<int32_t>());
183 string key
= getString();
185 return certFieldPolicy(key
, match
, cert
);
189 return trustedCert(get
<int32_t>());
191 return trustedCerts();
193 return fragments().namedAnchor(getString(), *mContext
);
195 return fragments().named(getString(), *mContext
);
198 int32_t targetPlatform
= get
<int32_t>();
199 return mContext
->directory
&& mContext
->directory
->platform
== targetPlatform
;
203 return isNotarized(mContext
);
207 return meetsDeveloperIDLegacyAllowedPolicy(mContext
);
210 // opcode not recognized - handle generically if possible, fail otherwise
211 if (op
& (opGenericFalse
| opGenericSkip
)) {
212 // unknown opcode, but it has a size field and can be safely bypassed
213 skip(get
<uint32_t>());
214 if (op
& opGenericFalse
) {
215 CODESIGN_EVAL_REQINT_UNKNOWN_FALSE(op
);
218 CODESIGN_EVAL_REQINT_UNKNOWN_SKIPPED(op
);
222 // unrecognized opcode and no way to interpret it
223 secinfo("csinterp", "opcode 0x%x cannot be handled; aborting", op
);
224 MacOSError::throwMe(errSecCSUnimplemented
);
230 // Evaluate an Info.plist key condition
232 bool Requirement::Interpreter::infoKeyValue(const string
&key
, const Match
&match
)
234 if (mContext
->info
) // we have an Info.plist
235 if (CFTypeRef value
= CFDictionaryGetValue(mContext
->info
, CFTempString(key
)))
237 return match(kCFNull
);
242 // Evaluate an entitlement condition
244 bool Requirement::Interpreter::entitlementValue(const string
&key
, const Match
&match
)
246 if (mContext
->entitlements
) // we have an Info.plist
247 if (CFTypeRef value
= CFDictionaryGetValue(mContext
->entitlements
, CFTempString(key
)))
249 return match(kCFNull
);
253 bool Requirement::Interpreter::certFieldValue(const string
&key
, const Match
&match
, SecCertificateRef cert
)
256 // no cert, no chance
260 // a table of recognized keys for the "certificate[foo]" syntax
261 static const struct CertField
{
265 { "subject.C", &oidCountryName
},
266 { "subject.CN", &oidCommonName
},
267 { "subject.D", &oidDescription
},
268 { "subject.L", &oidLocalityName
},
269 // { "subject.C-L", &CSSMOID_CollectiveLocalityName }, // missing from Security.framework headers
270 { "subject.O", &oidOrganizationName
},
271 { "subject.C-O", &oidCollectiveOrganizationName
},
272 { "subject.OU", &oidOrganizationalUnitName
},
273 { "subject.C-OU", &oidCollectiveOrganizationalUnitName
},
274 { "subject.ST", &oidStateOrProvinceName
},
275 { "subject.C-ST", &oidCollectiveStateOrProvinceName
},
276 { "subject.STREET", &oidStreetAddress
},
277 { "subject.C-STREET", &oidCollectiveStreetAddress
},
278 { "subject.UID", &oidUserId
},
282 // DN-component single-value match
283 for (const CertField
*cf
= certFields
; cf
->name
; cf
++)
284 if (cf
->name
== key
) {
285 CFRef
<CFStringRef
> value(SecCertificateCopySubjectAttributeValue(cert
, (DERItem
*)cf
->oid
));
287 secinfo("csinterp", "cert %p lookup for DN.%s failed", cert
, key
.c_str());
293 // email multi-valued match (any of...)
294 if (key
== "email") {
295 CFRef
<CFArrayRef
> value
;
296 OSStatus rc
= SecCertificateCopyEmailAddresses(cert
, &value
.aref());
298 secinfo("csinterp", "cert %p lookup for email failed rc=%d", cert
, (int)rc
);
304 // unrecognized key. Fail but do not abort to promote backward compatibility down the road
305 secinfo("csinterp", "cert field notation \"%s\" not understood", key
.c_str());
311 bool Requirement::Interpreter::certFieldGeneric(const string
&key
, const Match
&match
, SecCertificateRef cert
)
313 // the key is actually a (binary) OID value
314 CssmOid
oid((char *)key
.data(), key
.length());
315 return certFieldGeneric(oid
, match
, cert
);
318 bool Requirement::Interpreter::certFieldGeneric(const CssmOid
&oid
, const Match
&match
, SecCertificateRef cert
)
320 return cert
&& match(certificateHasField(cert
, oid
) ? (CFTypeRef
)kCFBooleanTrue
: (CFTypeRef
)kCFNull
);
323 bool Requirement::Interpreter::certFieldDate(const string
&key
, const Match
&match
, SecCertificateRef cert
)
325 // the key is actually a (binary) OID value
326 CssmOid
oid((char *)key
.data(), key
.length());
327 return certFieldDate(oid
, match
, cert
);
330 bool Requirement::Interpreter::certFieldDate(const CssmOid
&oid
, const Match
&match
, SecCertificateRef cert
)
332 CFTypeRef value
= cert
!= NULL
? certificateCopyFieldDate(cert
, oid
) : NULL
;
333 bool matching
= match(value
!= NULL
? value
: kCFNull
);
342 bool Requirement::Interpreter::certFieldPolicy(const string
&key
, const Match
&match
, SecCertificateRef cert
)
344 // the key is actually a (binary) OID value
345 CssmOid
oid((char *)key
.data(), key
.length());
346 return certFieldPolicy(oid
, match
, cert
);
349 bool Requirement::Interpreter::certFieldPolicy(const CssmOid
&oid
, const Match
&match
, SecCertificateRef cert
)
351 return cert
&& match(certificateHasPolicy(cert
, oid
) ? (CFTypeRef
)kCFBooleanTrue
: (CFTypeRef
)kCFNull
);
356 // Check the Apple-signed condition
358 bool Requirement::Interpreter::appleAnchored()
360 if (SecCertificateRef cert
= mContext
->cert(anchorCert
))
366 static CFStringRef kAMFINVRAMTrustedKeys
= CFSTR("AMFITrustedKeys");
368 CFArrayRef
Requirement::Interpreter::getAdditionalTrustedAnchors()
370 __block CFRef
<CFMutableArrayRef
> keys
= makeCFMutableArray(0);
373 io_registry_entry_t entry
= IORegistryEntryFromPath(kIOMasterPortDefault
, "IODeviceTree:/options");
374 if (entry
== IO_OBJECT_NULL
)
377 CFRef
<CFDataRef
> configData
= (CFDataRef
)IORegistryEntryCreateCFProperty(entry
, kAMFINVRAMTrustedKeys
, kCFAllocatorDefault
, 0);
378 IOObjectRelease(entry
);
382 CFRef
<CFDictionaryRef
> configDict
= CFDictionaryRef(IOCFUnserializeWithSize((const char *)CFDataGetBytePtr(configData
),
383 (size_t)CFDataGetLength(configData
),
384 kCFAllocatorDefault
, 0, NULL
));
388 CFArrayRef trustedKeys
= CFArrayRef(CFDictionaryGetValue(configDict
, CFSTR("trustedKeys")));
389 if (!trustedKeys
&& CFGetTypeID(trustedKeys
) != CFArrayGetTypeID())
392 cfArrayApplyBlock(trustedKeys
, ^(const void *value
) {
393 CFDictionaryRef key
= CFDictionaryRef(value
);
394 if (!key
&& CFGetTypeID(key
) != CFDictionaryGetTypeID())
397 CFDataRef hash
= CFDataRef(CFDictionaryGetValue(key
, CFSTR("certDigest")));
398 if (!hash
&& CFGetTypeID(hash
) != CFDataGetTypeID())
400 CFArrayAppendValue(keys
, hash
);
406 if (CFArrayGetCount(keys
) == 0)
412 bool Requirement::Interpreter::appleLocalAnchored()
414 static CFArrayRef additionalTrustedCertificates
= NULL
;
416 if (csr_check(CSR_ALLOW_APPLE_INTERNAL
)) {
420 if (mContext
->forcePlatform
) {
424 static dispatch_once_t onceToken
;
425 dispatch_once(&onceToken
, ^{
426 additionalTrustedCertificates
= getAdditionalTrustedAnchors();
429 if (additionalTrustedCertificates
== NULL
)
432 CFRef
<CFDataRef
> hash
= SecCertificateCopySHA256Digest(mContext
->cert(leafCert
));
436 if (CFArrayContainsValue(additionalTrustedCertificates
, CFRangeMake(0, CFArrayGetCount(additionalTrustedCertificates
)), hash
))
442 #if WAITING_FOR_LIB_AMFI_INTERFACE
443 // These bits are here until we get get a new build alias for libamfi-interface.
445 #define MAC_AMFI_POLICY_NAME "AMFI"
447 #define AMFI_SYSCALL_CDHASH_IN_TRUSTCACHE 95
449 typedef struct amfi_cdhash_in_trustcache_
{
452 } amfi_cdhash_in_trustcache_t
;
455 __amfi_interface_cdhash_in_trustcache(const uint8_t cdhash
[], uint64_t* trustcache_result
)
457 amfi_cdhash_in_trustcache_t args
;
458 static_assert(AMFI_INTF_CD_HASH_LEN
== sizeof(args
.cdhash
), "Error: cdhash length mismatch");
460 memcpy(args
.cdhash
, cdhash
, sizeof(args
.cdhash
));
462 err
= __mac_syscall(MAC_AMFI_POLICY_NAME
, AMFI_SYSCALL_CDHASH_IN_TRUSTCACHE
, &args
);
466 *trustcache_result
= args
.result
;
471 amfi_interface_cdhash_in_trustcache(const uint8_t cdhash
[], size_t cdhash_len
, uint64_t* trustcache_result
)
475 if (cdhash
== nullptr || cdhash_len
!= AMFI_INTF_CD_HASH_LEN
|| trustcache_result
== nullptr) {
478 *trustcache_result
= 0;
480 err
= __amfi_interface_cdhash_in_trustcache(cdhash
, trustcache_result
);
487 bool Requirement::Interpreter::inTrustCache()
490 CFRef
<CFDataRef
> cdhashRef
= mContext
->directory
->cdhash(true);
491 const uint8_t *cdhash
= CFDataGetBytePtr(cdhashRef
);
492 size_t cdhash_len
= CFDataGetLength(cdhashRef
);
493 int err
= amfi_interface_cdhash_in_trustcache(cdhash
, cdhash_len
, &result
);
494 return (err
== 0) && (result
!= 0);
497 bool Requirement::Interpreter::appleSigned()
499 if (inTrustCache()) {
502 else if (appleAnchored()) {
503 if (SecCertificateRef intermed
= mContext
->cert(-2)) // first intermediate
504 // first intermediate common name match (exact)
505 if (certFieldValue("subject.CN", Match(appleIntermediateCN
, matchEqual
), intermed
)
506 && certFieldValue("subject.O", Match(appleIntermediateO
, matchEqual
), intermed
))
508 } else if (appleLocalAnchored()) {
516 // Verify an anchor requirement against the context
518 bool Requirement::Interpreter::verifyAnchor(SecCertificateRef cert
, const unsigned char *digest
)
520 // get certificate bytes
523 hasher(SecCertificateGetBytePtr(cert
), SecCertificateGetLength(cert
));
524 return hasher
.verify(digest
);
531 // Check one or all certificate(s) in the cert chain against the Trust Settings database.
533 bool Requirement::Interpreter::trustedCerts()
535 int anchor
= mContext
->certCount() - 1;
536 for (int slot
= 0; slot
<= anchor
; slot
++)
537 if (SecCertificateRef cert
= mContext
->cert(slot
))
538 switch (trustSetting(cert
, slot
== anchor
)) {
539 case kSecTrustSettingsResultTrustRoot
:
540 case kSecTrustSettingsResultTrustAsRoot
:
542 case kSecTrustSettingsResultDeny
:
544 case kSecTrustSettingsResultUnspecified
:
555 bool Requirement::Interpreter::trustedCert(int slot
)
557 if (SecCertificateRef cert
= mContext
->cert(slot
)) {
558 int anchorSlot
= mContext
->certCount() - 1;
559 switch (trustSetting(cert
, slot
== anchorCert
|| slot
== anchorSlot
)) {
560 case kSecTrustSettingsResultTrustRoot
:
561 case kSecTrustSettingsResultTrustAsRoot
:
563 case kSecTrustSettingsResultDeny
:
564 case kSecTrustSettingsResultUnspecified
:
576 // Explicitly check one certificate against the Trust Settings database and report
577 // the findings. This is a helper for the various Trust Settings evaluators.
579 SecTrustSettingsResult
Requirement::Interpreter::trustSetting(SecCertificateRef cert
, bool isAnchor
)
581 // XXX: Not supported on embedded yet due to lack of supporting API
583 // the SPI input is the uppercase hex form of the SHA-1 of the certificate...
586 hashOfCertificate(cert
, digest
);
587 string Certhex
= CssmData(digest
, sizeof(digest
)).toHex();
588 for (string::iterator it
= Certhex
.begin(); it
!= Certhex
.end(); ++it
)
592 // call Trust Settings and see what it finds
593 SecTrustSettingsDomain domain
;
594 SecTrustSettingsResult result
;
595 CSSM_RETURN
*errors
= NULL
;
596 uint32 errorCount
= 0;
597 bool foundMatch
, foundAny
;
598 switch (OSStatus rc
= SecTrustSettingsEvaluateCert(
599 CFTempString(Certhex
), // settings index
600 &CSSMOID_APPLE_TP_CODE_SIGNING
, // standard code signing policy
601 NULL
, 0, // policy string (unused)
602 kSecTrustSettingsKeyUseAny
, // no restriction on key usage @@@
603 isAnchor
, // consult system default anchor set
605 &domain
, // domain of found setting
606 &errors
, &errorCount
, // error set and maximum count
607 &result
, // the actual setting
608 &foundMatch
, &foundAny
// optimization hints (not used)
615 return kSecTrustSettingsResultUnspecified
;
618 MacOSError::throwMe(rc
);
621 return kSecTrustSettingsResultUnspecified
;
627 // Create a Match object from the interpreter stream
629 Requirement::Interpreter::Match::Match(Interpreter
&interp
)
631 switch (mOp
= interp
.get
<MatchOperation
>()) {
637 case matchBeginsWith
:
640 case matchGreaterThan
:
642 case matchGreaterEqual
:
643 mValue
.take(makeCFString(interp
.getString()));
648 case matchOnOrBefore
:
649 case matchOnOrAfter
: {
650 mValue
.take(CFDateCreate(NULL
, interp
.getAbsoluteTime()));
654 // Assume this (unknown) match type has a single data argument.
655 // This gives us a chance to keep the instruction stream aligned.
656 interp
.getString(); // discard
663 // Execute a match against a candidate value
665 bool Requirement::Interpreter::Match::operator () (CFTypeRef candidate
) const
667 // null candidates always fail
671 if (candidate
== kCFNull
) {
672 return mOp
== matchAbsent
; // only 'absent' matches
675 // interpret an array as matching alternatives (any one succeeds)
676 if (CFGetTypeID(candidate
) == CFArrayGetTypeID()) {
677 CFArrayRef array
= CFArrayRef(candidate
);
678 CFIndex count
= CFArrayGetCount(array
);
679 for (CFIndex n
= 0; n
< count
; n
++)
680 if ((*this)(CFArrayGetValueAtIndex(array
, n
))) // yes, it's recursive
686 return false; // it exists, so it cannot be absent
687 case matchExists
: // anything but NULL and boolean false "exists"
688 return !CFEqual(candidate
, kCFBooleanFalse
);
689 case matchEqual
: // equality works for all CF types
690 return CFEqual(candidate
, mValue
);
692 if (isStringValue() && CFGetTypeID(candidate
) == CFStringGetTypeID()) {
693 CFStringRef value
= CFStringRef(candidate
);
694 if (CFStringFindWithOptions(value
, cfStringValue(), CFRangeMake(0, CFStringGetLength(value
)), 0, NULL
))
698 case matchBeginsWith
:
699 if (isStringValue() && CFGetTypeID(candidate
) == CFStringGetTypeID()) {
700 CFStringRef value
= CFStringRef(candidate
);
701 if (CFStringFindWithOptions(value
, cfStringValue(), CFRangeMake(0, CFStringGetLength(cfStringValue())), 0, NULL
))
706 if (isStringValue() && CFGetTypeID(candidate
) == CFStringGetTypeID()) {
707 CFStringRef value
= CFStringRef(candidate
);
708 CFIndex matchLength
= CFStringGetLength(cfStringValue());
709 CFIndex start
= CFStringGetLength(value
) - matchLength
;
711 if (CFStringFindWithOptions(value
, cfStringValue(), CFRangeMake(start
, matchLength
), 0, NULL
))
716 return inequality(candidate
, kCFCompareNumerically
, kCFCompareLessThan
, true);
717 case matchGreaterThan
:
718 return inequality(candidate
, kCFCompareNumerically
, kCFCompareGreaterThan
, true);
720 return inequality(candidate
, kCFCompareNumerically
, kCFCompareGreaterThan
, false);
721 case matchGreaterEqual
:
722 return inequality(candidate
, kCFCompareNumerically
, kCFCompareLessThan
, false);
726 case matchOnOrBefore
:
727 case matchOnOrAfter
: {
728 if (!isDateValue() || CFGetTypeID(candidate
) != CFDateGetTypeID()) {
732 CFComparisonResult res
= CFDateCompare((CFDateRef
)candidate
, cfDateValue(), NULL
);
735 case matchOn
: return res
== 0;
736 case matchBefore
: return res
< 0;
737 case matchAfter
: return res
> 0;
738 case matchOnOrBefore
: return res
<= 0;
739 case matchOnOrAfter
: return res
>= 0;
744 // unrecognized match types can never match
750 bool Requirement::Interpreter::Match::inequality(CFTypeRef candidate
, CFStringCompareFlags flags
,
751 CFComparisonResult outcome
, bool negate
) const
753 if (isStringValue() && CFGetTypeID(candidate
) == CFStringGetTypeID()) {
754 CFStringRef value
= CFStringRef(candidate
);
755 if ((CFStringCompare(value
, cfStringValue(), flags
) == outcome
) == negate
)
763 // External fragments
765 Fragments::Fragments()
767 mMyBundle
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
771 bool Fragments::evalNamed(const char *type
, const std::string
&name
, const Requirement::Context
&ctx
)
773 if (CFDataRef fragData
= fragment(type
, name
)) {
774 const Requirement
*req
= (const Requirement
*)CFDataGetBytePtr(fragData
); // was prevalidated as Requirement
775 return req
->validates(ctx
);
781 CFDataRef
Fragments::fragment(const char *type
, const std::string
&name
)
783 string key
= name
+ "!!" + type
; // compound key
784 StLock
<Mutex
> _(mLock
); // lock for cache access
785 FragMap::const_iterator it
= mFragments
.find(key
);
786 if (it
== mFragments
.end()) {
787 CFRef
<CFDataRef
> fragData
; // will always be set (NULL on any errors)
788 if (CFRef
<CFURLRef
> fragURL
= CFBundleCopyResourceURL(mMyBundle
, CFTempString(name
), CFSTR("csreq"), CFTempString(type
)))
789 if (CFRef
<CFDataRef
> data
= cfLoadFile(fragURL
)) { // got data
790 const Requirement
*req
= (const Requirement
*)CFDataGetBytePtr(data
);
791 if (req
->validateBlob(CFDataGetLength(data
))) // looks like a Requirement...
792 fragData
= data
; // ... so accept it
794 Syslog::warning("Invalid sub-requirement at %s", cfString(fragURL
).c_str());
796 if (CODESIGN_EVAL_REQINT_FRAGMENT_LOAD_ENABLED())
797 CODESIGN_EVAL_REQINT_FRAGMENT_LOAD(type
, name
.c_str(), fragData
? CFDataGetBytePtr(fragData
) : NULL
);
798 mFragments
[key
] = fragData
; // cache it, success or failure
801 CODESIGN_EVAL_REQINT_FRAGMENT_HIT(type
, name
.c_str());