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 <security_codesigning/reqdumper.h> 38#endif 39 40namespace Security { 41namespace CodeSigning { 42 43 44// 45// Canonical names for requirement types 46// 47const 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// 60void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const 61{ 62 if (!this->validates(ctx, failure)) 63 MacOSError::throwMe(failure); 64} 65 66bool 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// 92SecCertificateRef 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 105unsigned 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 119const char Requirement::testAppleAnchorEnv[] = "TEST_APPLE_ANCHOR"; 120 121const 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// 146// Debug dump support 147// 148#ifdef DEBUGDUMP 149 150void Requirement::dump() const 151{ 152 Debug::dump("%s\n", Dumper::dump(this).c_str()); 153} 154 155#endif //DEBUGDUMP 156 157 158} // CodeSigning 159} // Security 160