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" 
  30 #include <security_utilities/cfmunge.h> 
  31 #include <security_utilities/debugging.h> 
  32 #include "SecInternalReleasePriv.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
->validateNonResourceComponents();        // also validates the CodeDirectory 
 209         if (flags 
& kSecCSStrictValidate
) { 
 210                 myDisk
->diskRep()->strictValidate(myDisk
->codeDirectory(), DiskRep::ToleratedErrors(), flags
); 
 211         } else if (flags 
& kSecCSStrictValidateStructure
) { 
 212                 myDisk
->diskRep()->strictValidateStructure(myDisk
->codeDirectory(), DiskRep::ToleratedErrors(), flags
); 
 215         // check my own dynamic state 
 216         SecCodeStatus dynamic_status 
= this->host()->getGuestStatus(this); 
 217         bool isValid 
= (dynamic_status 
& kSecCodeStatusValid
) != 0; 
 219                 bool isDebugged 
= (dynamic_status 
& kSecCodeStatusDebugged
) != 0; 
 220                 bool isPlatform 
= (dynamic_status 
& kSecCodeStatusPlatform
) != 0; 
 221                 bool isInternal 
= SecIsInternalRelease(); 
 223                 if (!isDebugged 
|| (isPlatform 
&& !isInternal
)) { 
 224                         // fatal if the code is invalid and not being debugged, but 
 225                         // never let platform code be debugged except on internal systems. 
 226                         MacOSError::throwMe(errSecCSGuestInvalid
); 
 230         // check that static and dynamic views are consistent 
 231         if (this->cdHash() && !CFEqual(this->cdHash(), myDisk
->cdHash())) 
 232                 MacOSError::throwMe(errSecCSStaticCodeChanged
); 
 234         // check host/guest constraints 
 235         if (!this->host()->isRoot()) {  // not hosted by root of trust 
 236                 myDisk
->validateRequirements(kSecHostRequirementType
, hostDisk
, errSecCSHostReject
); 
 237                 hostDisk
->validateRequirements(kSecGuestRequirementType
, myDisk
); 
 243 // By default, we track no validity for guests (we don't have any) 
 245 uint32_t SecCode::getGuestStatus(SecCode 
*guest
) 
 247         MacOSError::throwMe(errSecCSNoSuchCode
); 
 250 void SecCode::changeGuestStatus(SecCode 
*guest
, SecCodeStatusOperation operation
, CFDictionaryRef arguments
) 
 252         MacOSError::throwMe(errSecCSNoSuchCode
); 
 257 // Given a bag of attribute values, automagically come up with a SecCode 
 258 // without any other information. 
 259 // This is meant to be the "just do what makes sense" generic call, for callers 
 260 // who don't want to engage in the fascinating dance of manual guest enumeration. 
 262 // Note that we expect the logic embedded here to change over time (in backward 
 263 // compatible fashion, one hopes), and that it's all right to use heuristics here 
 264 // as long as it's done sensibly. 
 266 // Be warned that the present logic is quite a bit ad-hoc, and will likely not 
 267 // handle arbitrary combinations of proxy hosting, dynamic hosting, and dedicated 
 268 // hosting all that well. 
 270 SecCode 
*SecCode::autoLocateGuest(CFDictionaryRef attributes
, SecCSFlags flags
) 
 273         // special case: with no attributes at all, return the root of trust 
 274         if (CFDictionaryGetCount(attributes
) == 0) 
 275                 return KernelCode::active()->retain(); 
 277         // main logic: we need a pid or audit trailer; everything else goes to the guests 
 278         if (CFDictionaryGetValue(attributes
, kSecGuestAttributePid
) == NULL
 
 279                 && CFDictionaryGetValue(attributes
, kSecGuestAttributeAudit
) == NULL
) 
 280                 CSError::throwMe(errSecCSUnsupportedGuestAttributes
, kSecCFErrorGuestAttributes
, attributes
); 
 281         if (SecCode 
*process 
= 
 282                         KernelCode::active()->locateGuest(attributes
)) { 
 283                 SecPointer
<SecCode
> code
; 
 284                 code
.take(process
);             // locateGuest gave us a retained object 
 285                 if (code
->staticCode()->flag(kSecCodeSignatureHost
)) { 
 286                         // might be a code host. Let's find out 
 287                         CFRef
<CFMutableDictionaryRef
> rest 
= makeCFMutableDictionary(attributes
); 
 288                         CFDictionaryRemoveValue(rest
, kSecGuestAttributePid
); 
 289                         CFDictionaryRemoveValue(rest
, kSecGuestAttributeAudit
); 
 290                         if (SecCode 
*guest 
= code
->locateGuest(rest
)) 
 293                 if (!CFDictionaryGetValue(attributes
, kSecGuestAttributeCanonical
)) { 
 294                         // only "soft" attributes, and no hosting is happening. Return the (non-)host itself 
 298 #endif // TARGET_OS_OSX 
 299         MacOSError::throwMe(errSecCSNoSuchCode
); 
 303 } // end namespace CodeSigning 
 304 } // end namespace Security