requirement.cpp
1 /* 2 * Copyright (c) 2006-2012 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 // requirement - Code Requirement Blob description 26 // 27 #include "requirement.h" 28 #include "reqinterp.h" 29 #include "codesigning_dtrace.h" 30 #include <security_utilities/errors.h> 31 #include <security_utilities/unix++.h> 32 #include <security_utilities/logging.h> 33 #include <security_utilities/cfutilities.h> 34 #include <security_utilities/hashing.h> 35 36 #ifdef DEBUGDUMP 37 #include "reqdumper.h" 38 #endif 39 40 namespace Security { 41 namespace CodeSigning { 42 43 44 // 45 // Canonical names for requirement types 46 // 47 const char *const Requirement::typeNames[] = { 48 "invalid", 49 "host", 50 "guest", 51 "designated", 52 "library", 53 "plugin", 54 }; 55 56 57 // 58 // validate a requirement against a code context 59 // 60 void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const 61 { 62 if (!this->validates(ctx, failure)) 63 MacOSError::throwMe(failure); 64 } 65 66 bool Requirement::validates(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const 67 { 68 CODESIGN_EVAL_REQINT_START((void*)this, (int)this->length()); 69 switch (kind()) { 70 case exprForm: 71 if (Requirement::Interpreter(this, &ctx).evaluate()) { 72 CODESIGN_EVAL_REQINT_END(this, 0); 73 return true; 74 } else { 75 CODESIGN_EVAL_REQINT_END(this, failure); 76 return false; 77 } 78 default: 79 CODESIGN_EVAL_REQINT_END(this, errSecCSReqUnsupported); 80 MacOSError::throwMe(errSecCSReqUnsupported); 81 } 82 } 83 84 85 // 86 // Retrieve one certificate from the cert chain. 87 // Positive and negative indices can be used: 88 // [ leaf, intermed-1, ..., intermed-n, anchor ] 89 // 0 1 ... -2 -1 90 // Returns NULL if unavailable for any reason. 91 // 92 SecCertificateRef Requirement::Context::cert(int ix) const 93 { 94 if (certs) { 95 if (ix < 0) 96 ix += certCount(); 97 if (ix >= CFArrayGetCount(certs)) 98 return NULL; 99 if (CFTypeRef element = CFArrayGetValueAtIndex(certs, ix)) 100 return SecCertificateRef(element); 101 } 102 return NULL; 103 } 104 105 unsigned int Requirement::Context::certCount() const 106 { 107 if (certs) 108 return (unsigned int)CFArrayGetCount(certs); 109 else 110 return 0; 111 } 112 113 114 // 115 // Produce the hash of a fake Apple root (only if compiled for internal testing) 116 // 117 #if defined(TEST_APPLE_ANCHOR) 118 119 const char Requirement::testAppleAnchorEnv[] = "TEST_APPLE_ANCHOR"; 120 121 const SHA1::Digest &Requirement::testAppleAnchorHash() 122 { 123 static bool tried = false; 124 static SHA1::Digest testHash; 125 if (!tried) { 126 // see if we have one configured 127 if (const char *path = getenv(testAppleAnchorEnv)) 128 try { 129 UnixPlusPlus::FileDesc fd(path); 130 char buffer[2048]; // arbitrary limit 131 size_t size = fd.read(buffer, sizeof(buffer)); 132 SHA1 hash; 133 hash(buffer, size); 134 hash.finish(testHash); 135 Syslog::alert("ACCEPTING TEST AUTHORITY %s FOR APPLE CODE IDENTITY", path); 136 } catch (...) { } 137 tried = true; 138 } 139 return testHash; // will be zeroes (no match) if not configured 140 } 141 142 #endif //TEST_APPLE_ANCHOR 143 144 // 145 // Debug dump support 146 // 147 #if TARGET_OS_OSX 148 #ifdef DEBUGDUMP 149 150 void Requirement::dump() const 151 { 152 Debug::dump("%s\n", Dumper::dump(this).c_str()); 153 } 154 155 #endif //DEBUGDUMP 156 #endif 157 158 159 } // CodeSigning 160 } // Security