2  * Copyright (c) 2006-2007,2011,2013 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 // Code - SecCode API objects 
  28 #include "StaticCode.h" 
  29 #include <Security/SecCodeHost.h> 
  31 #include <security_utilities/cfmunge.h> 
  32 #include <security_utilities/debugging.h> 
  35 namespace CodeSigning 
{ 
  41 SecCode::SecCode(SecCode 
*host
) 
  42         : mHost(host
), mIdentified(false) 
  44         CODESIGN_DYNAMIC_CREATE(this, host
); 
  49 // Clean up a SecCode object 
  51 SecCode::~SecCode() throw() 
  59 // CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed, 
  60 // and falls back on comparing canonical paths if (both are) not. 
  62 bool SecCode::equal(SecCFObject 
&secOther
) 
  64         SecCode 
*other 
= static_cast<SecCode 
*>(&secOther
); 
  65         CFDataRef mine 
= this->cdHash(); 
  66         CFDataRef his 
= other
->cdHash(); 
  68                 return mine 
&& his 
&& CFEqual(mine
, his
); 
  70                 return this->staticCode()->equal(*other
->staticCode()); 
  73 CFHashCode 
SecCode::hash() 
  75         if (CFDataRef h 
= this->cdHash()) 
  78                 return this->staticCode()->hash(); 
  83 // Yield the host Code 
  85 SecCode 
*SecCode::host() const 
  92 // Yield the static code. This is cached. 
  93 // The caller does not own the object returned; it lives (at least) as long 
  94 // as the SecCode it was derived from. 
  96 SecStaticCode 
*SecCode::staticCode() 
 108 // Yield the CodeDirectory hash as presented by our host. 
 109 // This usually is the same as the hash of staticCode().codeDirectory(), but might not 
 110 // if files are changing on disk while code is running. 
 112 CFDataRef 
SecCode::cdHash() 
 118         return mCDHash
;         // can be NULL (host has no dynamic identity for guest) 
 123 // Retrieve current dynamic status. 
 125 SecCodeStatus 
SecCode::status() 
 128                 return kSecCodeStatusValid
;                     // root of trust, presumed valid 
 130                 return this->host()->getGuestStatus(this); 
 133 void SecCode::status(SecCodeStatusOperation operation
, CFDictionaryRef arguments
) 
 136                 MacOSError::throwMe(errSecCSHostProtocolStateError
); 
 138                 this->host()->changeGuestStatus(this, operation
, arguments
); 
 143 // By default, we have no guests 
 145 SecCode 
*SecCode::locateGuest(CFDictionaryRef
) 
 152 // By default, we self-identify by asking our host to identify us. 
 153 // (This is currently only overridden in the root-of-trust (kernel) implementation.) 
 155 void SecCode::identify() 
 157         mStaticCode
.take(host()->identifyGuest(this, &mCDHash
.aref())); 
 162 // The default implementation cannot map guests to disk 
 164 SecStaticCode 
*SecCode::identifyGuest(SecCode 
*, CFDataRef 
*) 
 166         MacOSError::throwMe(errSecCSNoSuchCode
); 
 171 // Master validation function. 
 173 // This is the most important function in all of Code Signing. It performs 
 174 // dynamic validation on running code. Despite its simple structure, it does 
 175 // everything that's needed to establish whether a Code is currently valid... 
 176 // with a little help from StaticCode, format drivers, type drivers, and so on. 
 178 // This function validates internal requirements in the hosting chain. It does 
 179 // not validate external requirements - the caller needs to do that with a separate call. 
 181 void SecCode::checkValidity(SecCSFlags flags
) 
 183         if (this->isRoot()) { 
 184                 // the root-of-trust is valid by definition 
 185                 CODESIGN_EVAL_DYNAMIC_ROOT(this); 
 188         DTRACK(CODESIGN_EVAL_DYNAMIC
, this, (char*)this->staticCode()->mainExecutablePath().c_str()); 
 191         // Do not reorder the operations below without thorough cogitation. There are 
 192         // interesting dependencies and significant performance issues. There is also 
 193         // client code that relies on errors being noticed in a particular order. 
 195         // For the most part, failure of (reliable) identity will cause exceptions to be 
 196         // thrown, and success is indicated by survival. If you make it to the end, 
 197         // you have won the validity race. (Good rat.) 
 200         // check my host first, recursively 
 201         this->host()->checkValidity(flags
); 
 203         SecStaticCode 
*myDisk 
= this->staticCode(); 
 204         myDisk
->setValidationFlags(flags
); 
 205         SecStaticCode 
*hostDisk 
= this->host()->staticCode(); 
 207         // check my static state 
 208         myDisk
->validateDirectory(); 
 210         // check my own dynamic state 
 211         if (!(this->host()->getGuestStatus(this) & kSecCodeStatusValid
)) 
 212                 MacOSError::throwMe(errSecCSGuestInvalid
); 
 214         // check that static and dynamic views are consistent 
 215         if (this->cdHash() && !CFEqual(this->cdHash(), myDisk
->cdHash())) 
 216                 MacOSError::throwMe(errSecCSStaticCodeChanged
); 
 218         // check host/guest constraints 
 219         if (!this->host()->isRoot()) {  // not hosted by root of trust 
 220                 myDisk
->validateRequirements(kSecHostRequirementType
, hostDisk
, errSecCSHostReject
); 
 221                 hostDisk
->validateRequirements(kSecGuestRequirementType
, myDisk
); 
 227 // By default, we track no validity for guests (we don't have any) 
 229 uint32_t SecCode::getGuestStatus(SecCode 
*guest
) 
 231         MacOSError::throwMe(errSecCSNoSuchCode
); 
 234 void SecCode::changeGuestStatus(SecCode 
*guest
, SecCodeStatusOperation operation
, CFDictionaryRef arguments
) 
 236         MacOSError::throwMe(errSecCSNoSuchCode
); 
 241 // Given a bag of attribute values, automagically come up with a SecCode 
 242 // without any other information. 
 243 // This is meant to be the "just do what makes sense" generic call, for callers 
 244 // who don't want to engage in the fascinating dance of manual guest enumeration. 
 246 // Note that we expect the logic embedded here to change over time (in backward 
 247 // compatible fashion, one hopes), and that it's all right to use heuristics here 
 248 // as long as it's done sensibly. 
 250 // Be warned that the present logic is quite a bit ad-hoc, and will likely not 
 251 // handle arbitrary combinations of proxy hosting, dynamic hosting, and dedicated 
 252 // hosting all that well. 
 254 SecCode 
*SecCode::autoLocateGuest(CFDictionaryRef attributes
, SecCSFlags flags
) 
 256         // special case: with no attributes at all, return the root of trust 
 257         if (CFDictionaryGetCount(attributes
) == 0) 
 258                 return KernelCode::active()->retain(); 
 260         // main logic: we need a pid, and we'll take a canonical guest id as an option 
 262         if (!cfscan(attributes
, "{%O=%d}", kSecGuestAttributePid
, &pid
)) 
 263                 CSError::throwMe(errSecCSUnsupportedGuestAttributes
, kSecCFErrorGuestAttributes
, attributes
); 
 264         if (SecCode 
*process 
= 
 265                         KernelCode::active()->locateGuest(attributes
)) { 
 266                 SecPointer
<SecCode
> code
; 
 267                 code
.take(process
);             // locateGuest gave us a retained object 
 268                 if (code
->staticCode()->flag(kSecCodeSignatureHost
)) { 
 269                         // might be a code host. Let's find out 
 270                         CFRef
<CFMutableDictionaryRef
> rest 
= makeCFMutableDictionary(attributes
); 
 271                         CFDictionaryRemoveValue(rest
, kSecGuestAttributePid
); 
 272                         if (SecCode 
*guest 
= code
->locateGuest(rest
)) 
 275                 if (!CFDictionaryGetValue(attributes
, kSecGuestAttributeCanonical
)) { 
 276                         // only "soft" attributes, and no hosting is happening. Return the (non-)host itself 
 280         MacOSError::throwMe(errSecCSNoSuchCode
); 
 284 } // end namespace CodeSigning 
 285 } // end namespace Security