2  * Copyright (c) 2006-2014 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 // StaticCode - SecStaticCode API objects 
  31 #include "csutilities.h" 
  32 #include "Requirements.h" 
  33 #include "requirement.h" 
  35 #include "codedirectory.h" 
  36 #include <Security/SecTrust.h> 
  37 #include <CoreFoundation/CFData.h> 
  38 #include <security_utilities/dispatch.h> 
  41 namespace CodeSigning 
{ 
  48 // A SecStaticCode object represents the file system version of some code. 
  49 // There's a lot of pieces to this, and we'll bring them all into 
  50 // memory here (lazily) and let you fondle them with ease. 
  52 // Note that concrete knowledge of where stuff is stored resides in the DiskRep 
  53 // object we hold. DiskReps allocate, retrieve, and return data to us. We are 
  54 // responsible for interpreting, caching, and validating them. (In other words, 
  55 // DiskReps know where stuff is and how it is stored, but we know what it means.) 
  57 // Data accessors (returning CFDataRef, CFDictionaryRef, various pointers, etc.) 
  58 // cache those values internally and return unretained(!) references ("Get" style) 
  59 // that are valid as long as the SecStaticCode object's lifetime, or until 
  60 // resetValidity() is called, whichever is sooner. If you need to keep them longer, 
  61 // retain or copy them as needed. 
  63 class SecStaticCode 
: public SecCFObject 
{ 
  68         // A context for resource validation operations, to tailor error response. 
  69         // The base class throws an exception immediately and ignores detail data. 
  71         class ValidationContext 
{ 
  73                 ValidationContext(SecStaticCode 
&c
) : code(c
) { } 
  74                 virtual ~ValidationContext(); 
  75                 virtual void reportProblem(OSStatus rc
, CFStringRef type
, CFTypeRef value
); 
  77                 virtual OSStatus 
osStatus()     { return noErr
; } 
  78                 virtual void throwMe()          { } 
  84         // A CollectingContext collects all error details and throws an annotated final error. 
  86         class CollectingContext 
: public ValidationContext 
{ 
  88                 CollectingContext(SecStaticCode 
&c
) : ValidationContext(c
), mStatus(errSecSuccess
) { } 
  89                 void reportProblem(OSStatus rc
, CFStringRef type
, CFTypeRef value
); 
  91                 OSStatus 
osStatus()             { return mStatus
; } 
  92                 operator OSStatus () const              { return mStatus
; } 
  93                 void throwMe() __attribute__((noreturn
)); 
  96                 CFRef
<CFMutableDictionaryRef
> mCollection
; 
 102         SECCFFUNCTIONS(SecStaticCode
, SecStaticCodeRef
, 
 103                 errSecCSInvalidObjectRef
, gCFObjects().StaticCode
) 
 105         // implicitly convert SecCodeRefs to their SecStaticCodeRefs 
 106         static SecStaticCode 
*requiredStatic(SecStaticCodeRef ref
);     // convert SecCodeRef 
 107         static SecCode 
*optionalDynamic(SecStaticCodeRef ref
); // extract SecCodeRef or NULL if static 
 109         SecStaticCode(DiskRep 
*rep
); 
 110     virtual ~SecStaticCode() throw(); 
 112     void initializeFromParent(const SecStaticCode
& parent
); 
 114     bool equal(SecCFObject 
&other
); 
 117         void detachedSignature(CFDataRef sig
);          // attach an explicitly given detached signature 
 118         void checkForSystemSignature();                         // check for and attach system-supplied detached signature 
 120         typedef std::map
<CodeDirectory::HashAlgorithm
, CFCopyRef
<CFDataRef
> > CodeDirectoryMap
; 
 122         const CodeDirectory 
*codeDirectory(bool check 
= true) const; 
 123         const CodeDirectoryMap 
*codeDirectories(bool check 
= true) const; 
 124         CodeDirectory::HashAlgorithm 
hashAlgorithm() const { return codeDirectory()->hashType
; } 
 125         CodeDirectory::HashAlgorithms 
hashAlgorithms() const { return mHashAlgorithms
; } 
 127         CFArrayRef 
cdHashes(); 
 128         CFDataRef 
signature(); 
 129         CFAbsoluteTime 
signingTime(); 
 130         CFAbsoluteTime 
signingTimestamp(); 
 131         bool isSigned() { return codeDirectory(false) != NULL
; } 
 132         DiskRep 
*diskRep() const { return mRep
; } 
 133         bool isDetached() const { return mRep
->base() != mRep
; } 
 134         std::string 
mainExecutablePath() { return mRep
->mainExecutablePath(); } 
 135         CFURLRef 
copyCanonicalPath() const { return mRep
->copyCanonicalPath(); } 
 136         std::string 
identifier() { return codeDirectory()->identifier(); } 
 137         const char *teamID() { return codeDirectory()->teamID(); } 
 138         std::string 
format() const { return mRep
->format(); } 
 139         std::string 
signatureSource(); 
 140         virtual CFDataRef 
component(CodeDirectory::SpecialSlot slot
, OSStatus fail 
= errSecCSSignatureFailed
); 
 141         virtual CFDictionaryRef 
infoDictionary(); 
 142         CFDictionaryRef 
diskRepInformation(); 
 144         CFDictionaryRef 
entitlements(); 
 145         CFDataRef 
copyComponent(CodeDirectory::SpecialSlot slot
, CFDataRef hash
); 
 147         CFDictionaryRef 
resourceDictionary(bool check 
= true); 
 148         CFURLRef 
resourceBase(); 
 149         void validateResource(CFDictionaryRef files
, std::string path
, bool isSymlink
, ValidationContext 
&ctx
, SecCSFlags flags
, uint32_t version
); 
 150         void validateSymlinkResource(std::string fullpath
, std::string seal
, ValidationContext 
&ctx
, SecCSFlags flags
); 
 152         bool flag(uint32_t tested
); 
 154         SecCodeCallback 
monitor() const { return mMonitor
; } 
 155         void setMonitor(SecCodeCallback monitor
) { mMonitor 
= monitor
; } 
 156         CFTypeRef 
reportEvent(CFStringRef stage
, CFDictionaryRef info
); 
 157         void reportProgress(unsigned amount 
= 1); 
 159         void setValidationFlags(SecCSFlags flags
) { mValidationFlags 
= flags
; } 
 160         void setValidationModifiers(CFDictionaryRef modifiers
); 
 162         void resetValidity();                                           // clear validation caches (if something may have changed) 
 164         bool validated() const  { return mValidated
; } 
 165         bool revocationChecked() const { return mRevocationChecked
; } 
 167                 { assert(validated()); return mValidated 
&& (mValidationResult 
== errSecSuccess
); } 
 168         bool validatedExecutable() const        { return mExecutableValidated
; } 
 169         bool validatedResources() const { return mResourcesValidated
; } 
 171         void prepareProgress(unsigned workload
); 
 172         void cancelValidation(); 
 174         void validateDirectory(); 
 175         virtual void validateComponent(CodeDirectory::SpecialSlot slot
, OSStatus fail 
= errSecCSSignatureFailed
); 
 176         void validateNonResourceComponents(); 
 177         void validateTopDirectory(); 
 178         unsigned estimateResourceWorkload(); 
 179         void validateResources(SecCSFlags flags
); 
 180         void validateExecutable(); 
 181         void validateNestedCode(CFURLRef path
, const ResourceSeal 
&seal
, SecCSFlags flags
, bool isFramework
); 
 183         void validatePlainMemoryResource(string path
, CFDataRef fileData
, SecCSFlags flags
); 
 185         const Requirements 
*internalRequirements(); 
 186         const Requirement 
*internalRequirement(SecRequirementType type
); 
 187         const Requirement 
*designatedRequirement(); 
 188         const Requirement 
*defaultDesignatedRequirement();              // newly allocated (caller owns) 
 190         void validateRequirements(SecRequirementType type
, SecStaticCode 
*target
, 
 191                 OSStatus nullError 
= errSecSuccess
);                                                                            // target against my [type], throws 
 192         void validateRequirement(const Requirement 
*req
, OSStatus failure
);             // me against [req], throws 
 193         bool satisfiesRequirement(const Requirement 
*req
, OSStatus failure
);    // me against [req], returns on clean miss 
 195         // certificates are available after signature validation (they are stored in the CMS signature) 
 196         SecCertificateRef 
cert(int ix
);         // get a cert from the cert chain 
 197         CFArrayRef 
certificates();                      // get the entire certificate chain 
 199         CFDictionaryRef 
signingInformation(SecCSFlags flags
); // omnibus information-gathering API (creates new dictionary) 
 201         static bool isAppleDeveloperCert(CFArrayRef certs
); // determines if this is an apple developer certificate for library validation 
 203     bool trustedSigningCertChain() { return mTrustedSigningCertChain
; } 
 206         void handleOtherArchitectures(void (^handle
)(SecStaticCode
* other
)); 
 209         void staticValidate(SecCSFlags flags
, const SecRequirement 
*req
); 
 210         void staticValidateCore(SecCSFlags flags
, const SecRequirement 
*req
); 
 213         bool loadCodeDirectories(CodeDirectoryMap
& cdMap
) const; 
 216         CFDictionaryRef 
getDictionary(CodeDirectory::SpecialSlot slot
, bool check 
= true); // component value as a dictionary 
 217         bool verifySignature(); 
 218         CFArrayRef 
createVerificationPolicies(); 
 219         CFArrayRef 
createTimeStampingAndRevocationPolicies(); 
 221         // load preferred rules/files dictionaries (cached therein) 
 222         bool loadResources(CFDictionaryRef
& rules
, CFDictionaryRef
& files
, uint32_t& version
); 
 224         static void checkOptionalResource(CFTypeRef key
, CFTypeRef value
, void *context
); 
 225         bool hasWeakResourceRules(CFDictionaryRef rulesDict
, uint32_t version
, CFArrayRef allowedOmissions
); 
 228         void validateOtherVersions(CFURLRef path
, SecCSFlags flags
, SecRequirementRef req
, SecStaticCode 
*code
); 
 229         bool checkfix30814861(string path
, bool addition
); 
 231         ResourceBuilder 
*mCheckfix30814861builder1
; 
 232         dispatch_once_t mCheckfix30814861builder1_once
; 
 235         RefPointer
<DiskRep
> mRep
;                       // on-disk representation 
 236         mutable CodeDirectoryMap mCodeDirectories
; // available CodeDirectory blobs by digest type 
 237         mutable CFRef
<CFDataRef
> mBaseDir
;      // the primary CodeDirectory blob (whether it's chosen or not) 
 238         CFRef
<CFDataRef
> mDetachedSig
;          // currently applied explicit detached signature 
 240         // private validation modifiers (only used by Gatekeeper checkfixes) 
 241         MacOSErrorSet mTolerateErrors
;          // soft error conditions to ignore 
 242         CFRef
<CFArrayRef
> mAllowOmissions
;      // additionally allowed resource omissions 
 244         // master validation state 
 245         bool mValidated
;                                        // core validation was attempted 
 246         bool mRevocationChecked
;                        // the signature was checked for revocation 
 247         OSStatus mValidationResult
;                     // outcome of core validation 
 248         bool mValidationExpired
;                        // outcome had expired certificates 
 250         // static executable validation state (nested within mValidated/mValid) 
 251         bool mExecutableValidated
;                      // tried to validate executable file 
 252         OSStatus mExecutableValidResult
;                // outcome if mExecutableValidated 
 254         // static resource validation state (nested within mValidated/mValid) 
 255         bool mResourcesValidated
;                       // tried to validate resources 
 256         bool mResourcesDeep
;                            // cached validation was deep 
 257         OSStatus mResourcesValidResult
;                 // outcome if mResourceValidated or... 
 258         ValidationContext 
*mResourcesValidContext
; // resource error reporting funnel 
 260         // validation progress state (set when static validation starts) 
 261         SecCSFlags mValidationFlags
;            // API flags passed to static validation 
 262         unsigned mTotalWork
;                            // total expected work (arbitrary units) 
 263         unsigned mCurrentWork
;                          // currently completed work 
 264         bool mCancelPending
;                            // cancellation was requested 
 265         Dispatch::Queue mProgressQueue
;         // progress reporting queue 
 267         // nested validation support 
 268         const SecStaticCode 
*mOuterScope
;       // containing code (if this is a nested validation; weak) 
 269         ResourceBuilder 
*mResourceScope
;        // current Resource validation stack (while validating; weak) 
 272         mutable CFRef
<CFDataRef
> mDir
;          // code directory data 
 273         mutable CodeDirectory::HashAlgorithms mHashAlgorithms
; // available hash algorithms 
 274         CFRef
<CFDataRef
> mSignature
;            // CMS signature data 
 275         CFAbsoluteTime mSigningTime
;            // (signed) signing time 
 276         CFAbsoluteTime mSigningTimestamp
;               // Timestamp time (from timestamping authority) 
 277         CFRef
<CFDataRef
> mCache
[cdSlotCount
]; // NULL => not tried, kCFNull => absent, other => present 
 279         // alternative cache forms (storage may depend on cached contents above) 
 280         CFRef
<CFDictionaryRef
> mInfoDict
;       // derived from mCache slot 
 281         CFRef
<CFDictionaryRef
> mEntitlements
; // derived from mCache slot 
 282         CFRef
<CFDictionaryRef
> mResourceDict
; // derived from mCache slot 
 283         const Requirement 
*mDesignatedReq
;      // cached designated req if we made one up 
 284         CFRef
<CFDataRef
> mCDHash
;                       // hash of chosen CodeDirectory 
 285         CFRef
<CFArrayRef
> mCDHashes
;            // hashes of all CodeDirectories (in digest type code order) 
 287         bool mGotResourceBase
;                          // asked mRep for resourceBasePath 
 288         CFRef
<CFURLRef
> mResourceBase
;          // URL form of resource base directory 
 290         SecCodeCallback mMonitor
;                       // registered monitor callback 
 292         LimitedAsync 
*mLimitedAsync
;            // limited async workers for verification 
 294         // signature verification outcome (mTrust == NULL => not done yet) 
 295         CFRef
<SecTrustRef
> mTrust
;                      // outcome of crypto validation (valid or not) 
 296         CFRef
<CFArrayRef
> mCertChain
; 
 298     CSSM_TP_APPLE_EVIDENCE_INFO 
*mEvalDetails
; 
 300     bool mTrustedSigningCertChain
; 
 306 } // end namespace CodeSigning 
 307 } // end namespace Security 
 309 #endif // !_H_STATICCODE