/ OSX / libsecurity_codesigning / lib / requirement.cpp
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