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
, uint32_t flags
= 0);
110 virtual ~SecStaticCode() _NOEXCEPT
;
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 CFDictionaryRef
cdHashesFull();
129 CFDataRef
signature();
130 CFAbsoluteTime
signingTime();
131 CFAbsoluteTime
signingTimestamp();
132 bool isSigned() { return codeDirectory(false) != NULL
; }
133 DiskRep
*diskRep() const { return mRep
; }
134 bool isDetached() const { return mRep
->base() != mRep
; }
135 std::string
mainExecutablePath() { return mRep
->mainExecutablePath(); }
136 CFURLRef
copyCanonicalPath() const { return mRep
->copyCanonicalPath(); }
137 std::string
identifier() { return codeDirectory()->identifier(); }
138 const char *teamID() { return codeDirectory()->teamID(); }
139 std::string
format() const { return mRep
->format(); }
140 std::string
signatureSource();
141 virtual CFDataRef
component(CodeDirectory::SpecialSlot slot
, OSStatus fail
= errSecCSSignatureFailed
);
142 virtual CFDictionaryRef
infoDictionary();
143 CFDictionaryRef
diskRepInformation();
145 CFDictionaryRef
entitlements();
146 CFDataRef
copyComponent(CodeDirectory::SpecialSlot slot
, CFDataRef hash
);
148 CFDictionaryRef
resourceDictionary(bool check
= true);
149 CFURLRef
resourceBase();
150 void validateResource(CFDictionaryRef files
, std::string path
, bool isSymlink
, ValidationContext
&ctx
, SecCSFlags flags
, uint32_t version
);
151 void validateSymlinkResource(std::string fullpath
, std::string seal
, ValidationContext
&ctx
, SecCSFlags flags
);
153 bool flag(uint32_t tested
);
155 SecCodeCallback
monitor() const { return mMonitor
; }
156 void setMonitor(SecCodeCallback monitor
) { mMonitor
= monitor
; }
157 CFTypeRef
reportEvent(CFStringRef stage
, CFDictionaryRef info
);
158 void reportProgress(unsigned amount
= 1);
160 void setValidationFlags(SecCSFlags flags
) { mValidationFlags
= flags
; }
161 void setValidationModifiers(CFDictionaryRef modifiers
);
163 void resetValidity(); // clear validation caches (if something may have changed)
165 bool validated() const { return mValidated
; }
166 bool revocationChecked() const { return mRevocationChecked
; }
168 { assert(validated()); return mValidated
&& (mValidationResult
== errSecSuccess
); }
169 bool validatedExecutable() const { return mExecutableValidated
; }
170 bool validatedResources() const { return mResourcesValidated
; }
172 void prepareProgress(unsigned workload
);
173 void cancelValidation();
175 void validateDirectory();
176 virtual void validateComponent(CodeDirectory::SpecialSlot slot
, OSStatus fail
= errSecCSSignatureFailed
);
177 void validateNonResourceComponents();
178 void validateTopDirectory();
179 unsigned estimateResourceWorkload();
180 void validateResources(SecCSFlags flags
);
181 void validateExecutable();
182 void validateNestedCode(CFURLRef path
, const ResourceSeal
&seal
, SecCSFlags flags
, bool isFramework
);
184 void validatePlainMemoryResource(string path
, CFDataRef fileData
, SecCSFlags flags
);
186 const Requirements
*internalRequirements();
187 const Requirement
*internalRequirement(SecRequirementType type
);
188 const Requirement
*designatedRequirement();
189 const Requirement
*defaultDesignatedRequirement(); // newly allocated (caller owns)
191 void validateRequirements(SecRequirementType type
, SecStaticCode
*target
,
192 OSStatus nullError
= errSecSuccess
); // target against my [type], throws
193 void validateRequirement(const Requirement
*req
, OSStatus failure
); // me against [req], throws
194 bool satisfiesRequirement(const Requirement
*req
, OSStatus failure
); // me against [req], returns on clean miss
196 // certificates are available after signature validation (they are stored in the CMS signature)
197 SecCertificateRef
cert(int ix
); // get a cert from the cert chain
198 CFArrayRef
certificates(); // get the entire certificate chain
200 CFDictionaryRef
signingInformation(SecCSFlags flags
); // omnibus information-gathering API (creates new dictionary)
202 static bool isAppleDeveloperCert(CFArrayRef certs
); // determines if this is an apple developer certificate for library validation
203 bool trustedSigningCertChain() { return mTrustedSigningCertChain
; }
205 void handleOtherArchitectures(void (^handle
)(SecStaticCode
* other
));
207 uint8_t cmsDigestHashType() const { return mCMSDigestHashType
; };
208 CFDataRef
createCmsDigest();
210 void staticValidate(SecCSFlags flags
, const SecRequirement
*req
);
211 void staticValidateCore(SecCSFlags flags
, const SecRequirement
*req
);
214 bool loadCodeDirectories(CodeDirectoryMap
& cdMap
) const;
217 CFDictionaryRef
getDictionary(CodeDirectory::SpecialSlot slot
, bool check
= true); // component value as a dictionary
218 bool verifySignature();
219 CFArrayRef
createVerificationPolicies();
220 CFArrayRef
createTimeStampingAndRevocationPolicies();
222 // load preferred rules/files dictionaries (cached therein)
223 bool loadResources(CFDictionaryRef
& rules
, CFDictionaryRef
& files
, uint32_t& version
);
225 static void checkOptionalResource(CFTypeRef key
, CFTypeRef value
, void *context
);
226 bool hasWeakResourceRules(CFDictionaryRef rulesDict
, uint32_t version
, CFArrayRef allowedOmissions
);
229 void validateOtherVersions(CFURLRef path
, SecCSFlags flags
, SecRequirementRef req
, SecStaticCode
*code
);
230 bool checkfix30814861(string path
, bool addition
);
231 bool checkfix41082220(OSStatus result
);
232 CFArrayRef
copyCertChain(SecTrustRef trust
);
234 ResourceBuilder
*mCheckfix30814861builder1
;
235 dispatch_once_t mCheckfix30814861builder1_once
;
238 static const uint8_t mCMSDigestHashType
= kSecCodeSignatureHashSHA256
;
239 // hash of CMS digest (kSecCodeSignatureHash* constant)
240 RefPointer
<DiskRep
> mRep
; // on-disk representation
241 mutable CodeDirectoryMap mCodeDirectories
; // available CodeDirectory blobs by digest type
242 mutable CFRef
<CFDataRef
> mBaseDir
; // the primary CodeDirectory blob (whether it's chosen or not)
243 CFRef
<CFDataRef
> mDetachedSig
; // currently applied explicit detached signature
245 // private validation modifiers (only used by Gatekeeper checkfixes)
246 MacOSErrorSet mTolerateErrors
; // soft error conditions to ignore
247 CFRef
<CFArrayRef
> mAllowOmissions
; // additionally allowed resource omissions
249 // master validation state
250 bool mValidated
; // core validation was attempted
251 bool mRevocationChecked
; // the signature was checked for revocation
252 OSStatus mValidationResult
; // outcome of core validation
253 bool mValidationExpired
; // outcome had expired certificates
255 // static executable validation state (nested within mValidated/mValid)
256 bool mExecutableValidated
; // tried to validate executable file
257 OSStatus mExecutableValidResult
; // outcome if mExecutableValidated
259 // static resource validation state (nested within mValidated/mValid)
260 bool mResourcesValidated
; // tried to validate resources
261 bool mResourcesDeep
; // cached validation was deep
262 OSStatus mResourcesValidResult
; // outcome if mResourceValidated or...
263 ValidationContext
*mResourcesValidContext
; // resource error reporting funnel
265 // validation progress state (set when static validation starts)
266 SecCSFlags mValidationFlags
; // API flags passed to static validation
267 unsigned mTotalWork
; // total expected work (arbitrary units)
268 unsigned mCurrentWork
; // currently completed work
269 bool mCancelPending
; // cancellation was requested
270 Dispatch::Queue mProgressQueue
; // progress reporting queue
272 // nested validation support
273 const SecStaticCode
*mOuterScope
; // containing code (if this is a nested validation; weak)
274 ResourceBuilder
*mResourceScope
; // current Resource validation stack (while validating; weak)
277 mutable CFRef
<CFDataRef
> mDir
; // code directory data
278 mutable CodeDirectory::HashAlgorithms mHashAlgorithms
; // available hash algorithms
279 CFRef
<CFDataRef
> mSignature
; // CMS signature data
280 CFAbsoluteTime mSigningTime
; // (signed) signing time
281 CFAbsoluteTime mSigningTimestamp
; // Timestamp time (from timestamping authority)
282 CFRef
<CFDataRef
> mCache
[cdSlotCount
]; // NULL => not tried, kCFNull => absent, other => present
284 // alternative cache forms (storage may depend on cached contents above)
285 CFRef
<CFDictionaryRef
> mInfoDict
; // derived from mCache slot
286 CFRef
<CFDictionaryRef
> mEntitlements
; // derived from mCache slot
287 CFRef
<CFDictionaryRef
> mResourceDict
; // derived from mCache slot
288 const Requirement
*mDesignatedReq
; // cached designated req if we made one up
289 CFRef
<CFDataRef
> mCDHash
; // hash of chosen CodeDirectory
290 CFRef
<CFArrayRef
> mCDHashes
; // hashes of all CodeDirectories (in digest type code order)
291 CFRef
<CFDictionaryRef
> mCDHashFullDict
; // untruncated hashes of CodeDirectories (as dictionary)
293 bool mGotResourceBase
; // asked mRep for resourceBasePath
294 CFRef
<CFURLRef
> mResourceBase
; // URL form of resource base directory
296 SecCodeCallback mMonitor
; // registered monitor callback
298 LimitedAsync
*mLimitedAsync
; // limited async workers for verification
300 uint32_t mFlags
; // flags from creation
301 bool mNotarizationChecked
; // ensure notarization check only performed once
302 bool mStaplingChecked
; // ensure stapling check only performed once
303 double mNotarizationDate
; // the notarization ticket's date, if online check failed
305 // signature verification outcome (mTrust == NULL => not done yet)
306 CFRef
<SecTrustRef
> mTrust
; // outcome of crypto validation (valid or not)
307 CFRef
<CFArrayRef
> mCertChain
;
308 bool mTrustedSigningCertChain
;
313 } // end namespace CodeSigning
314 } // end namespace Security
316 #endif // !_H_STATICCODE