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         const CodeDirectory 
*codeDirectory(bool check 
= true) const; 
 121         CodeDirectory::HashAlgorithm 
hashAlgorithm() const { return codeDirectory()->hashType
; } 
 122         CodeDirectory::HashAlgorithms 
hashAlgorithms() const { return mHashAlgorithms
; } 
 124         CFArrayRef 
cdHashes(); 
 125         CFDataRef 
signature(); 
 126         CFAbsoluteTime 
signingTime(); 
 127         CFAbsoluteTime 
signingTimestamp(); 
 128         bool isSigned() { return codeDirectory(false) != NULL
; } 
 129         DiskRep 
*diskRep() const { return mRep
; } 
 130         bool isDetached() const { return mRep
->base() != mRep
; } 
 131         std::string 
mainExecutablePath() { return mRep
->mainExecutablePath(); } 
 132         CFURLRef 
copyCanonicalPath() const { return mRep
->copyCanonicalPath(); } 
 133         std::string 
identifier() { return codeDirectory()->identifier(); } 
 134         const char *teamID() { return codeDirectory()->teamID(); } 
 135         std::string 
format() const { return mRep
->format(); } 
 136         std::string 
signatureSource(); 
 137         virtual CFDataRef 
component(CodeDirectory::SpecialSlot slot
, OSStatus fail 
= errSecCSSignatureFailed
); 
 138         virtual CFDictionaryRef 
infoDictionary(); 
 140         CFDictionaryRef 
entitlements(); 
 142         CFDictionaryRef 
resourceDictionary(bool check 
= true); 
 143         CFURLRef 
resourceBase(); 
 144         CFDataRef 
resource(std::string path
); 
 145         CFDataRef 
resource(std::string path
, ValidationContext 
&ctx
); 
 146         void validateResource(CFDictionaryRef files
, std::string path
, bool isSymlink
, ValidationContext 
&ctx
, SecCSFlags flags
, uint32_t version
); 
 147         void validateSymlinkResource(std::string fullpath
, std::string seal
, ValidationContext 
&ctx
, SecCSFlags flags
); 
 149         bool flag(uint32_t tested
); 
 151         SecCodeCallback 
monitor() const { return mMonitor
; } 
 152         void setMonitor(SecCodeCallback monitor
) { mMonitor 
= monitor
; } 
 153         CFTypeRef 
reportEvent(CFStringRef stage
, CFDictionaryRef info
); 
 154         void reportProgress(unsigned amount 
= 1); 
 156         void setValidationFlags(SecCSFlags flags
) { mValidationFlags 
= flags
; } 
 157         void setValidationModifiers(CFDictionaryRef modifiers
); 
 159         void resetValidity();                                           // clear validation caches (if something may have changed) 
 161         bool validated() const  { return mValidated
; } 
 162         bool revocationChecked() const { return mRevocationChecked
; } 
 164                 { assert(validated()); return mValidated 
&& (mValidationResult 
== errSecSuccess
); } 
 165         bool validatedExecutable() const        { return mExecutableValidated
; } 
 166         bool validatedResources() const { return mResourcesValidated
; } 
 168         void prepareProgress(unsigned workload
); 
 169         void cancelValidation(); 
 171         void validateDirectory(); 
 172         virtual void validateComponent(CodeDirectory::SpecialSlot slot
, OSStatus fail 
= errSecCSSignatureFailed
); 
 173         void validateNonResourceComponents(); 
 174         void validateTopDirectory(); 
 175         unsigned estimateResourceWorkload(); 
 176         void validateResources(SecCSFlags flags
); 
 177         void validateExecutable(); 
 178         void validateNestedCode(CFURLRef path
, const ResourceSeal 
&seal
, SecCSFlags flags
, bool isFramework
); 
 180         const Requirements 
*internalRequirements(); 
 181         const Requirement 
*internalRequirement(SecRequirementType type
); 
 182         const Requirement 
*designatedRequirement(); 
 183         const Requirement 
*defaultDesignatedRequirement();              // newly allocated (caller owns) 
 185         void validateRequirements(SecRequirementType type
, SecStaticCode 
*target
, 
 186                 OSStatus nullError 
= errSecSuccess
);                                                                            // target against my [type], throws 
 187         void validateRequirement(const Requirement 
*req
, OSStatus failure
);             // me against [req], throws 
 188         bool satisfiesRequirement(const Requirement 
*req
, OSStatus failure
);    // me against [req], returns on clean miss 
 190         // certificates are available after signature validation (they are stored in the CMS signature) 
 191         SecCertificateRef 
cert(int ix
);         // get a cert from the cert chain 
 192         CFArrayRef 
certificates();                      // get the entire certificate chain 
 194         CFDictionaryRef 
signingInformation(SecCSFlags flags
); // omnibus information-gathering API (creates new dictionary) 
 196         static bool isAppleDeveloperCert(CFArrayRef certs
); // determines if this is an apple developer certificate for libraray validation 
 199         void staticValidate(SecCSFlags flags
, const SecRequirement 
*req
); 
 200         void staticValidateCore(SecCSFlags flags
, const SecRequirement 
*req
); 
 203         typedef std::map
<CodeDirectory::HashAlgorithm
, CFCopyRef
<CFDataRef
> > CodeDirectoryMap
; 
 204         bool loadCodeDirectories(CodeDirectoryMap
& cdMap
) const; 
 207         CFDictionaryRef 
getDictionary(CodeDirectory::SpecialSlot slot
, bool check 
= true); // component value as a dictionary 
 208         bool verifySignature(); 
 209         CFArrayRef 
verificationPolicies(); 
 211         static void checkOptionalResource(CFTypeRef key
, CFTypeRef value
, void *context
); 
 212         bool hasWeakResourceRules(CFDictionaryRef rulesDict
, uint32_t version
, CFArrayRef allowedOmissions
); 
 214         void handleOtherArchitectures(void (^handle
)(SecStaticCode
* other
)); 
 217         void validateOtherVersions(CFURLRef path
, SecCSFlags flags
, SecRequirementRef req
, SecStaticCode 
*code
); 
 220         RefPointer
<DiskRep
> mRep
;                       // on-disk representation 
 221         mutable CodeDirectoryMap mCodeDirectories
; // available CodeDirectory blobs by digest type 
 222         mutable CFRef
<CFDataRef
> mBaseDir
;      // the primary CodeDirectory blob (whether it's chosen or not) 
 223         CFRef
<CFDataRef
> mDetachedSig
;          // currently applied explicit detached signature 
 225         // private validation modifiers (only used by Gatekeeper checkfixes) 
 226         MacOSErrorSet mTolerateErrors
;          // soft error conditions to ignore 
 227         CFRef
<CFArrayRef
> mAllowOmissions
;      // additionally allowed resource omissions 
 229         // master validation state 
 230         bool mValidated
;                                        // core validation was attempted 
 231         bool mRevocationChecked
;                        // the signature was checked for revocation 
 232         OSStatus mValidationResult
;                     // outcome of core validation 
 233         bool mValidationExpired
;                        // outcome had expired certificates 
 235         // static executable validation state (nested within mValidated/mValid) 
 236         bool mExecutableValidated
;                      // tried to validate executable file 
 237         OSStatus mExecutableValidResult
;                // outcome if mExecutableValidated 
 239         // static resource validation state (nested within mValidated/mValid) 
 240         bool mResourcesValidated
;                       // tried to validate resources 
 241         bool mResourcesDeep
;                            // cached validation was deep 
 242         OSStatus mResourcesValidResult
;                 // outcome if mResourceValidated or... 
 243         ValidationContext 
*mResourcesValidContext
; // resource error reporting funnel 
 245         // validation progress state (set when static validation starts) 
 246         SecCSFlags mValidationFlags
;            // API flags passed to static validation 
 247         unsigned mTotalWork
;                            // total expected work (arbitrary units) 
 248         unsigned mCurrentWork
;                          // currently completed work 
 249         bool mCancelPending
;                            // cancellation was requested 
 250         Dispatch::Queue mProgressQueue
;         // progress reporting queue 
 252         // nested validation support 
 253         const SecStaticCode 
*mOuterScope
;       // containing code (if this is a nested validation; weak) 
 254         ResourceBuilder 
*mResourceScope
;        // current Resource validation stack (while validating; weak) 
 257         mutable CFRef
<CFDataRef
> mDir
;          // code directory data 
 258         mutable CodeDirectory::HashAlgorithms mHashAlgorithms
; // available hash algorithms 
 259         CFRef
<CFDataRef
> mSignature
;            // CMS signature data 
 260         CFAbsoluteTime mSigningTime
;            // (signed) signing time 
 261         CFAbsoluteTime mSigningTimestamp
;               // Timestamp time (from timestamping authority) 
 262         CFRef
<CFDataRef
> mCache
[cdSlotCount
]; // NULL => not tried, kCFNull => absent, other => present 
 264         // alternative cache forms (storage may depend on cached contents above) 
 265         CFRef
<CFDictionaryRef
> mInfoDict
;       // derived from mCache slot 
 266         CFRef
<CFDictionaryRef
> mEntitlements
; // derived from mCache slot 
 267         CFRef
<CFDictionaryRef
> mResourceDict
; // derived from mCache slot 
 268         const Requirement 
*mDesignatedReq
;      // cached designated req if we made one up 
 269         CFRef
<CFDataRef
> mCDHash
;                       // hash of chosen CodeDirectory 
 270         CFRef
<CFArrayRef
> mCDHashes
;            // hashes of all CodeDirectories (in digest type code order) 
 272         bool mGotResourceBase
;                          // asked mRep for resourceBasePath 
 273         CFRef
<CFURLRef
> mResourceBase
;          // URL form of resource base directory 
 275         SecCodeCallback mMonitor
;                       // registered monitor callback 
 277         LimitedAsync 
*mLimitedAsync
;            // limited async workers for verification 
 279         // signature verification outcome (mTrust == NULL => not done yet) 
 280         CFRef
<SecTrustRef
> mTrust
;                      // outcome of crypto validation (valid or not) 
 281         CFRef
<CFArrayRef
> mCertChain
; 
 282         CSSM_TP_APPLE_EVIDENCE_INFO 
*mEvalDetails
; 
 286 } // end namespace CodeSigning 
 287 } // end namespace Security 
 289 #endif // !_H_STATICCODE