]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/reqinterp.cpp
Security-59306.61.1.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / reqinterp.cpp
1 /*
2 * Copyright (c) 2006,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // reqinterp - Requirement language (exprOp) interpreter
26 //
27
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>
34 #include <sys/csr.h>
35 #include <IOKit/IOKitLib.h>
36 #include <IOKit/IOCFUnserialize.h>
37 #include "csutilities.h"
38 #include "notarization.h"
39 #include "legacydevid.h"
40
41 namespace Security {
42 namespace CodeSigning {
43
44
45 //
46 // Fragment fetching, caching, and evaluation.
47 //
48 // Several language elements allow "calling" of separate requirement programs
49 // stored on disk as (binary) requirement blobs. The Fragments class takes care
50 // of finding, loading, caching, and evaluating them.
51 //
52 // This is a singleton for (process global) caching. It works fine as multiple instances,
53 // at a loss of caching effectiveness.
54 //
55 class Fragments {
56 public:
57 Fragments();
58
59 bool named(const std::string &name, const Requirement::Context &ctx)
60 { return evalNamed("subreq", name, ctx); }
61 bool namedAnchor(const std::string &name, const Requirement::Context &ctx)
62 { return evalNamed("anchorreq", name, ctx); }
63
64 private:
65 bool evalNamed(const char *type, const std::string &name, const Requirement::Context &ctx);
66 CFDataRef fragment(const char *type, const std::string &name);
67
68 typedef std::map<std::string, CFRef<CFDataRef> > FragMap;
69
70 private:
71 CFBundleRef mMyBundle; // Security.framework bundle
72 Mutex mLock; // lock for all of the below...
73 FragMap mFragments; // cached fragments
74 };
75
76 static ModuleNexus<Fragments> fragments;
77
78
79 //
80 // Magic certificate features
81 //
82 static CFStringRef appleIntermediateCN = CFSTR("Apple Code Signing Certification Authority");
83 static CFStringRef appleIntermediateO = CFSTR("Apple Inc.");
84
85
86 //
87 // Main interpreter function.
88 //
89 // ExprOp code is in Polish Notation (operator followed by operands),
90 // and this engine uses opportunistic evaluation.
91 //
92 bool Requirement::Interpreter::evaluate()
93 { return eval(stackLimit); }
94
95 bool Requirement::Interpreter::eval(int depth)
96 {
97 if (--depth <= 0) // nested too deeply - protect the stack
98 MacOSError::throwMe(errSecCSReqInvalid);
99
100 ExprOp op = ExprOp(get<uint32_t>());
101 CODESIGN_EVAL_REQINT_OP(op, this->pc() - sizeof(uint32_t));
102 switch (op & ~opFlagMask) {
103 case opFalse:
104 return false;
105 case opTrue:
106 return true;
107 case opIdent:
108 return mContext->directory && getString() == mContext->directory->identifier();
109 case opAppleAnchor:
110 return appleSigned();
111 case opAppleGenericAnchor:
112 return appleAnchored();
113 case opAnchorHash:
114 {
115 SecCertificateRef cert = mContext->cert(get<int32_t>());
116 return verifyAnchor(cert, getSHA1());
117 }
118 case opInfoKeyValue: // [legacy; use opInfoKeyField]
119 {
120 string key = getString();
121 return infoKeyValue(key, Match(CFTempString(getString()), matchEqual));
122 }
123 case opAnd:
124 return eval(depth) & eval(depth);
125 case opOr:
126 return eval(depth) | eval(depth);
127 case opCDHash:
128 if (mContext->directory) {
129 CFRef<CFDataRef> cdhash = mContext->directory->cdhash();
130 CFRef<CFDataRef> required = getHash();
131 return CFEqual(cdhash, required);
132 } else
133 return false;
134 case opNot:
135 return !eval(depth);
136 case opInfoKeyField:
137 {
138 string key = getString();
139 Match match(*this);
140 return infoKeyValue(key, match);
141 }
142 case opEntitlementField:
143 {
144 string key = getString();
145 Match match(*this);
146 return entitlementValue(key, match);
147 }
148 case opCertField:
149 {
150 SecCertificateRef cert = mContext->cert(get<int32_t>());
151 string key = getString();
152 Match match(*this);
153 return certFieldValue(key, match, cert);
154 }
155 #if TARGET_OS_OSX
156 case opCertGeneric:
157 {
158 SecCertificateRef cert = mContext->cert(get<int32_t>());
159 string key = getString();
160 Match match(*this);
161 return certFieldGeneric(key, match, cert);
162 }
163 case opCertFieldDate:
164 {
165 SecCertificateRef cert = mContext->cert(get<int32_t>());
166 string key = getString();
167 Match match(*this);
168 return certFieldDate(key, match, cert);
169 }
170 case opCertPolicy:
171 {
172 SecCertificateRef cert = mContext->cert(get<int32_t>());
173 string key = getString();
174 Match match(*this);
175 return certFieldPolicy(key, match, cert);
176 }
177 #endif
178 case opTrustedCert:
179 return trustedCert(get<int32_t>());
180 case opTrustedCerts:
181 return trustedCerts();
182 case opNamedAnchor:
183 return fragments().namedAnchor(getString(), *mContext);
184 case opNamedCode:
185 return fragments().named(getString(), *mContext);
186 case opPlatform:
187 {
188 int32_t targetPlatform = get<int32_t>();
189 return mContext->directory && mContext->directory->platform == targetPlatform;
190 }
191 case opNotarized:
192 {
193 return isNotarized(mContext);
194 }
195 case opLegacyDevID:
196 {
197 return meetsDeveloperIDLegacyAllowedPolicy(mContext);
198 }
199 default:
200 // opcode not recognized - handle generically if possible, fail otherwise
201 if (op & (opGenericFalse | opGenericSkip)) {
202 // unknown opcode, but it has a size field and can be safely bypassed
203 skip(get<uint32_t>());
204 if (op & opGenericFalse) {
205 CODESIGN_EVAL_REQINT_UNKNOWN_FALSE(op);
206 return false;
207 } else {
208 CODESIGN_EVAL_REQINT_UNKNOWN_SKIPPED(op);
209 return eval(depth);
210 }
211 }
212 // unrecognized opcode and no way to interpret it
213 secinfo("csinterp", "opcode 0x%x cannot be handled; aborting", op);
214 MacOSError::throwMe(errSecCSUnimplemented);
215 }
216 }
217
218
219 //
220 // Evaluate an Info.plist key condition
221 //
222 bool Requirement::Interpreter::infoKeyValue(const string &key, const Match &match)
223 {
224 if (mContext->info) // we have an Info.plist
225 if (CFTypeRef value = CFDictionaryGetValue(mContext->info, CFTempString(key)))
226 return match(value);
227 return match(kCFNull);
228 }
229
230
231 //
232 // Evaluate an entitlement condition
233 //
234 bool Requirement::Interpreter::entitlementValue(const string &key, const Match &match)
235 {
236 if (mContext->entitlements) // we have an Info.plist
237 if (CFTypeRef value = CFDictionaryGetValue(mContext->entitlements, CFTempString(key)))
238 return match(value);
239 return match(kCFNull);
240 }
241
242
243 bool Requirement::Interpreter::certFieldValue(const string &key, const Match &match, SecCertificateRef cert)
244 {
245 // XXX: Not supported on embedded yet due to lack of supporting API
246 #if TARGET_OS_OSX
247 // no cert, no chance
248 if (cert == NULL)
249 return false;
250
251 // a table of recognized keys for the "certificate[foo]" syntax
252 static const struct CertField {
253 const char *name;
254 const CSSM_OID *oid;
255 } certFields[] = {
256 { "subject.C", &CSSMOID_CountryName },
257 { "subject.CN", &CSSMOID_CommonName },
258 { "subject.D", &CSSMOID_Description },
259 { "subject.L", &CSSMOID_LocalityName },
260 // { "subject.C-L", &CSSMOID_CollectiveLocalityName }, // missing from Security.framework headers
261 { "subject.O", &CSSMOID_OrganizationName },
262 { "subject.C-O", &CSSMOID_CollectiveOrganizationName },
263 { "subject.OU", &CSSMOID_OrganizationalUnitName },
264 { "subject.C-OU", &CSSMOID_CollectiveOrganizationalUnitName },
265 { "subject.ST", &CSSMOID_StateProvinceName },
266 { "subject.C-ST", &CSSMOID_CollectiveStateProvinceName },
267 { "subject.STREET", &CSSMOID_StreetAddress },
268 { "subject.C-STREET", &CSSMOID_CollectiveStreetAddress },
269 { "subject.UID", &CSSMOID_UserID },
270 { NULL, NULL }
271 };
272
273 // DN-component single-value match
274 for (const CertField *cf = certFields; cf->name; cf++)
275 if (cf->name == key) {
276 CFRef<CFStringRef> value;
277 OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref());
278 if (rc) {
279 secinfo("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), (int)rc);
280 return false;
281 }
282 return match(value);
283 }
284
285 // email multi-valued match (any of...)
286 if (key == "email") {
287 CFRef<CFArrayRef> value;
288 OSStatus rc = SecCertificateCopyEmailAddresses(cert, &value.aref());
289 if (rc) {
290 secinfo("csinterp", "cert %p lookup for email failed rc=%d", cert, (int)rc);
291 return false;
292 }
293 return match(value);
294 }
295
296 // unrecognized key. Fail but do not abort to promote backward compatibility down the road
297 secinfo("csinterp", "cert field notation \"%s\" not understood", key.c_str());
298 #endif
299 return false;
300 }
301
302 #if TARGET_OS_OSX
303 bool Requirement::Interpreter::certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert)
304 {
305 // the key is actually a (binary) OID value
306 CssmOid oid((char *)key.data(), key.length());
307 return certFieldGeneric(oid, match, cert);
308 }
309
310 bool Requirement::Interpreter::certFieldGeneric(const CssmOid &oid, const Match &match, SecCertificateRef cert)
311 {
312 return cert && match(certificateHasField(cert, oid) ? (CFTypeRef)kCFBooleanTrue : (CFTypeRef)kCFNull);
313 }
314
315 bool Requirement::Interpreter::certFieldDate(const string &key, const Match &match, SecCertificateRef cert)
316 {
317 // the key is actually a (binary) OID value
318 CssmOid oid((char *)key.data(), key.length());
319 return certFieldDate(oid, match, cert);
320 }
321
322 bool Requirement::Interpreter::certFieldDate(const CssmOid &oid, const Match &match, SecCertificateRef cert)
323 {
324 CFTypeRef value = cert != NULL ? certificateCopyFieldDate(cert, oid) : NULL;
325 bool matching = match(value != NULL ? value : kCFNull);
326
327 if (value) {
328 CFRelease(value);
329 }
330
331 return matching;
332 }
333
334 bool Requirement::Interpreter::certFieldPolicy(const string &key, const Match &match, SecCertificateRef cert)
335 {
336 // the key is actually a (binary) OID value
337 CssmOid oid((char *)key.data(), key.length());
338 return certFieldPolicy(oid, match, cert);
339 }
340
341 bool Requirement::Interpreter::certFieldPolicy(const CssmOid &oid, const Match &match, SecCertificateRef cert)
342 {
343 return cert && match(certificateHasPolicy(cert, oid) ? (CFTypeRef)kCFBooleanTrue : (CFTypeRef)kCFNull);
344 }
345 #endif
346
347 //
348 // Check the Apple-signed condition
349 //
350 bool Requirement::Interpreter::appleAnchored()
351 {
352 if (SecCertificateRef cert = mContext->cert(anchorCert))
353 if (isAppleCA(cert))
354 return true;
355 return false;
356 }
357
358 static CFStringRef kAMFINVRAMTrustedKeys = CFSTR("AMFITrustedKeys");
359
360 CFArrayRef Requirement::Interpreter::getAdditionalTrustedAnchors()
361 {
362 __block CFRef<CFMutableArrayRef> keys = makeCFMutableArray(0);
363
364 try {
365 io_registry_entry_t entry = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
366 if (entry == IO_OBJECT_NULL)
367 return NULL;
368
369 CFRef<CFDataRef> configData = (CFDataRef)IORegistryEntryCreateCFProperty(entry, kAMFINVRAMTrustedKeys, kCFAllocatorDefault, 0);
370 IOObjectRelease(entry);
371 if (!configData)
372 return NULL;
373
374 CFRef<CFDictionaryRef> configDict = CFDictionaryRef(IOCFUnserializeWithSize((const char *)CFDataGetBytePtr(configData),
375 (size_t)CFDataGetLength(configData),
376 kCFAllocatorDefault, 0, NULL));
377 if (!configDict)
378 return NULL;
379
380 CFArrayRef trustedKeys = CFArrayRef(CFDictionaryGetValue(configDict, CFSTR("trustedKeys")));
381 if (!trustedKeys && CFGetTypeID(trustedKeys) != CFArrayGetTypeID())
382 return NULL;
383
384 cfArrayApplyBlock(trustedKeys, ^(const void *value) {
385 CFDictionaryRef key = CFDictionaryRef(value);
386 if (!key && CFGetTypeID(key) != CFDictionaryGetTypeID())
387 return;
388
389 CFDataRef hash = CFDataRef(CFDictionaryGetValue(key, CFSTR("certDigest")));
390 if (!hash && CFGetTypeID(hash) != CFDataGetTypeID())
391 return;
392 CFArrayAppendValue(keys, hash);
393 });
394
395 } catch (...) {
396 }
397
398 if (CFArrayGetCount(keys) == 0)
399 return NULL;
400
401 return keys.yield();
402 }
403
404 bool Requirement::Interpreter::appleLocalAnchored()
405 {
406 static CFArrayRef additionalTrustedCertificates = NULL;
407
408 if (csr_check(CSR_ALLOW_APPLE_INTERNAL))
409 return false;
410
411 if (mContext->forcePlatform) {
412 return true;
413 }
414
415 static dispatch_once_t onceToken;
416 dispatch_once(&onceToken, ^{
417 additionalTrustedCertificates = getAdditionalTrustedAnchors();
418 });
419
420 if (additionalTrustedCertificates == NULL)
421 return false;
422
423 CFRef<CFDataRef> hash = SecCertificateCopySHA256Digest(mContext->cert(leafCert));
424 if (!hash)
425 return false;
426
427 if (CFArrayContainsValue(additionalTrustedCertificates, CFRangeMake(0, CFArrayGetCount(additionalTrustedCertificates)), hash))
428 return true;
429
430 return false;
431 }
432
433 bool Requirement::Interpreter::appleSigned()
434 {
435 if (appleAnchored()) {
436 if (SecCertificateRef intermed = mContext->cert(-2)) // first intermediate
437 // first intermediate common name match (exact)
438 if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
439 && certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
440 return true;
441 } else if (appleLocalAnchored()) {
442 return true;
443 }
444 return false;
445 }
446
447
448 //
449 // Verify an anchor requirement against the context
450 //
451 bool Requirement::Interpreter::verifyAnchor(SecCertificateRef cert, const unsigned char *digest)
452 {
453 // get certificate bytes
454 if (cert) {
455 SHA1 hasher;
456 #if TARGET_OS_OSX
457 CSSM_DATA certData;
458 MacOSError::check(SecCertificateGetData(cert, &certData));
459
460 // verify hash
461 hasher(certData.Data, certData.Length);
462 #else
463 hasher(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert));
464 #endif
465 return hasher.verify(digest);
466 }
467 return false;
468 }
469
470
471 //
472 // Check one or all certificate(s) in the cert chain against the Trust Settings database.
473 //
474 bool Requirement::Interpreter::trustedCerts()
475 {
476 int anchor = mContext->certCount() - 1;
477 for (int slot = 0; slot <= anchor; slot++)
478 if (SecCertificateRef cert = mContext->cert(slot))
479 switch (trustSetting(cert, slot == anchor)) {
480 case kSecTrustSettingsResultTrustRoot:
481 case kSecTrustSettingsResultTrustAsRoot:
482 return true;
483 case kSecTrustSettingsResultDeny:
484 return false;
485 case kSecTrustSettingsResultUnspecified:
486 break;
487 default:
488 assert(false);
489 return false;
490 }
491 else
492 return false;
493 return false;
494 }
495
496 bool Requirement::Interpreter::trustedCert(int slot)
497 {
498 if (SecCertificateRef cert = mContext->cert(slot)) {
499 int anchorSlot = mContext->certCount() - 1;
500 switch (trustSetting(cert, slot == anchorCert || slot == anchorSlot)) {
501 case kSecTrustSettingsResultTrustRoot:
502 case kSecTrustSettingsResultTrustAsRoot:
503 return true;
504 case kSecTrustSettingsResultDeny:
505 case kSecTrustSettingsResultUnspecified:
506 return false;
507 default:
508 assert(false);
509 return false;
510 }
511 } else
512 return false;
513 }
514
515
516 //
517 // Explicitly check one certificate against the Trust Settings database and report
518 // the findings. This is a helper for the various Trust Settings evaluators.
519 //
520 SecTrustSettingsResult Requirement::Interpreter::trustSetting(SecCertificateRef cert, bool isAnchor)
521 {
522 // XXX: Not supported on embedded yet due to lack of supporting API
523 #if TARGET_OS_OSX
524 // the SPI input is the uppercase hex form of the SHA-1 of the certificate...
525 assert(cert);
526 SHA1::Digest digest;
527 hashOfCertificate(cert, digest);
528 string Certhex = CssmData(digest, sizeof(digest)).toHex();
529 for (string::iterator it = Certhex.begin(); it != Certhex.end(); ++it)
530 if (islower(*it))
531 *it = toupper(*it);
532
533 // call Trust Settings and see what it finds
534 SecTrustSettingsDomain domain;
535 SecTrustSettingsResult result;
536 CSSM_RETURN *errors = NULL;
537 uint32 errorCount = 0;
538 bool foundMatch, foundAny;
539 switch (OSStatus rc = SecTrustSettingsEvaluateCert(
540 CFTempString(Certhex), // settings index
541 &CSSMOID_APPLE_TP_CODE_SIGNING, // standard code signing policy
542 NULL, 0, // policy string (unused)
543 kSecTrustSettingsKeyUseAny, // no restriction on key usage @@@
544 isAnchor, // consult system default anchor set
545
546 &domain, // domain of found setting
547 &errors, &errorCount, // error set and maximum count
548 &result, // the actual setting
549 &foundMatch, &foundAny // optimization hints (not used)
550 )) {
551 case errSecSuccess:
552 ::free(errors);
553 if (foundMatch)
554 return result;
555 else
556 return kSecTrustSettingsResultUnspecified;
557 default:
558 ::free(errors);
559 MacOSError::throwMe(rc);
560 }
561 #else
562 return kSecTrustSettingsResultUnspecified;
563 #endif
564 }
565
566
567 //
568 // Create a Match object from the interpreter stream
569 //
570 Requirement::Interpreter::Match::Match(Interpreter &interp)
571 {
572 switch (mOp = interp.get<MatchOperation>()) {
573 case matchAbsent:
574 case matchExists:
575 break;
576 case matchEqual:
577 case matchContains:
578 case matchBeginsWith:
579 case matchEndsWith:
580 case matchLessThan:
581 case matchGreaterThan:
582 case matchLessEqual:
583 case matchGreaterEqual:
584 mValue.take(makeCFString(interp.getString()));
585 break;
586 case matchOn:
587 case matchBefore:
588 case matchAfter:
589 case matchOnOrBefore:
590 case matchOnOrAfter: {
591 mValue.take(CFDateCreate(NULL, interp.getAbsoluteTime()));
592 break;
593 }
594 default:
595 // Assume this (unknown) match type has a single data argument.
596 // This gives us a chance to keep the instruction stream aligned.
597 interp.getString(); // discard
598 break;
599 }
600 }
601
602
603 //
604 // Execute a match against a candidate value
605 //
606 bool Requirement::Interpreter::Match::operator () (CFTypeRef candidate) const
607 {
608 // null candidates always fail
609 if (!candidate)
610 return false;
611
612 if (candidate == kCFNull) {
613 return mOp == matchAbsent; // only 'absent' matches
614 }
615
616 // interpret an array as matching alternatives (any one succeeds)
617 if (CFGetTypeID(candidate) == CFArrayGetTypeID()) {
618 CFArrayRef array = CFArrayRef(candidate);
619 CFIndex count = CFArrayGetCount(array);
620 for (CFIndex n = 0; n < count; n++)
621 if ((*this)(CFArrayGetValueAtIndex(array, n))) // yes, it's recursive
622 return true;
623 }
624
625 switch (mOp) {
626 case matchAbsent:
627 return false; // it exists, so it cannot be absent
628 case matchExists: // anything but NULL and boolean false "exists"
629 return !CFEqual(candidate, kCFBooleanFalse);
630 case matchEqual: // equality works for all CF types
631 return CFEqual(candidate, mValue);
632 case matchContains:
633 if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
634 CFStringRef value = CFStringRef(candidate);
635 if (CFStringFindWithOptions(value, cfStringValue(), CFRangeMake(0, CFStringGetLength(value)), 0, NULL))
636 return true;
637 }
638 return false;
639 case matchBeginsWith:
640 if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
641 CFStringRef value = CFStringRef(candidate);
642 if (CFStringFindWithOptions(value, cfStringValue(), CFRangeMake(0, CFStringGetLength(cfStringValue())), 0, NULL))
643 return true;
644 }
645 return false;
646 case matchEndsWith:
647 if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
648 CFStringRef value = CFStringRef(candidate);
649 CFIndex matchLength = CFStringGetLength(cfStringValue());
650 CFIndex start = CFStringGetLength(value) - matchLength;
651 if (start >= 0)
652 if (CFStringFindWithOptions(value, cfStringValue(), CFRangeMake(start, matchLength), 0, NULL))
653 return true;
654 }
655 return false;
656 case matchLessThan:
657 return inequality(candidate, kCFCompareNumerically, kCFCompareLessThan, true);
658 case matchGreaterThan:
659 return inequality(candidate, kCFCompareNumerically, kCFCompareGreaterThan, true);
660 case matchLessEqual:
661 return inequality(candidate, kCFCompareNumerically, kCFCompareGreaterThan, false);
662 case matchGreaterEqual:
663 return inequality(candidate, kCFCompareNumerically, kCFCompareLessThan, false);
664 case matchOn:
665 case matchBefore:
666 case matchAfter:
667 case matchOnOrBefore:
668 case matchOnOrAfter: {
669 if (!isDateValue() || CFGetTypeID(candidate) != CFDateGetTypeID()) {
670 return false;
671 }
672
673 CFComparisonResult res = CFDateCompare((CFDateRef)candidate, cfDateValue(), NULL);
674
675 switch (mOp) {
676 case matchOn: return res == 0;
677 case matchBefore: return res < 0;
678 case matchAfter: return res > 0;
679 case matchOnOrBefore: return res <= 0;
680 case matchOnOrAfter: return res >= 0;
681 default: abort();
682 }
683 }
684 default:
685 // unrecognized match types can never match
686 return false;
687 }
688 }
689
690
691 bool Requirement::Interpreter::Match::inequality(CFTypeRef candidate, CFStringCompareFlags flags,
692 CFComparisonResult outcome, bool negate) const
693 {
694 if (isStringValue() && CFGetTypeID(candidate) == CFStringGetTypeID()) {
695 CFStringRef value = CFStringRef(candidate);
696 if ((CFStringCompare(value, cfStringValue(), flags) == outcome) == negate)
697 return true;
698 }
699 return false;
700 }
701
702
703 //
704 // External fragments
705 //
706 Fragments::Fragments()
707 {
708 mMyBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
709 }
710
711
712 bool Fragments::evalNamed(const char *type, const std::string &name, const Requirement::Context &ctx)
713 {
714 if (CFDataRef fragData = fragment(type, name)) {
715 const Requirement *req = (const Requirement *)CFDataGetBytePtr(fragData); // was prevalidated as Requirement
716 return req->validates(ctx);
717 }
718 return false;
719 }
720
721
722 CFDataRef Fragments::fragment(const char *type, const std::string &name)
723 {
724 string key = name + "!!" + type; // compound key
725 StLock<Mutex> _(mLock); // lock for cache access
726 FragMap::const_iterator it = mFragments.find(key);
727 if (it == mFragments.end()) {
728 CFRef<CFDataRef> fragData; // will always be set (NULL on any errors)
729 if (CFRef<CFURLRef> fragURL = CFBundleCopyResourceURL(mMyBundle, CFTempString(name), CFSTR("csreq"), CFTempString(type)))
730 if (CFRef<CFDataRef> data = cfLoadFile(fragURL)) { // got data
731 const Requirement *req = (const Requirement *)CFDataGetBytePtr(data);
732 if (req->validateBlob(CFDataGetLength(data))) // looks like a Requirement...
733 fragData = data; // ... so accept it
734 else
735 Syslog::warning("Invalid sub-requirement at %s", cfString(fragURL).c_str());
736 }
737 if (CODESIGN_EVAL_REQINT_FRAGMENT_LOAD_ENABLED())
738 CODESIGN_EVAL_REQINT_FRAGMENT_LOAD(type, name.c_str(), fragData ? CFDataGetBytePtr(fragData) : NULL);
739 mFragments[key] = fragData; // cache it, success or failure
740 return fragData;
741 }
742 CODESIGN_EVAL_REQINT_FRAGMENT_HIT(type, name.c_str());
743 return it->second;
744 }
745
746
747 } // CodeSigning
748 } // Security