]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
11 | * file. | |
12 | * | |
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. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | // | |
25 | // StaticCode - SecStaticCode API objects | |
26 | // | |
27 | #ifndef _H_STATICCODE | |
28 | #define _H_STATICCODE | |
29 | ||
30 | #include "cs.h" | |
d87e1158 | 31 | #include "csutilities.h" |
b1ab9ed8 A |
32 | #include "Requirements.h" |
33 | #include "requirement.h" | |
34 | #include "diskrep.h" | |
35 | #include "codedirectory.h" | |
36 | #include <Security/SecTrust.h> | |
37 | #include <CoreFoundation/CFData.h> | |
d87e1158 | 38 | #include <security_utilities/dispatch.h> |
b1ab9ed8 A |
39 | |
40 | namespace Security { | |
41 | namespace CodeSigning { | |
42 | ||
43 | ||
44 | class SecCode; | |
45 | ||
46 | ||
47 | // | |
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. | |
51 | // | |
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.) | |
56 | // | |
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 | |
427c49bc | 60 | // resetValidity() is called, whichever is sooner. If you need to keep them longer, |
b1ab9ed8 A |
61 | // retain or copy them as needed. |
62 | // | |
63 | class SecStaticCode : public SecCFObject { | |
64 | NOCOPY(SecStaticCode) | |
65 | ||
66 | protected: | |
67 | // | |
68 | // A context for resource validation operations, to tailor error response. | |
69 | // The base class throws an exception immediately and ignores detail data. | |
70 | // | |
71 | class ValidationContext { | |
72 | public: | |
d8f41ccd | 73 | ValidationContext(SecStaticCode &c) : code(c) { } |
b1ab9ed8 A |
74 | virtual ~ValidationContext(); |
75 | virtual void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value); | |
d8f41ccd A |
76 | |
77 | virtual OSStatus osStatus() { return noErr; } | |
78 | virtual void throwMe() { } | |
79 | ||
80 | SecStaticCode &code; | |
b1ab9ed8 A |
81 | }; |
82 | ||
83 | // | |
84 | // A CollectingContext collects all error details and throws an annotated final error. | |
85 | // | |
86 | class CollectingContext : public ValidationContext { | |
87 | public: | |
d8f41ccd | 88 | CollectingContext(SecStaticCode &c) : ValidationContext(c), mStatus(errSecSuccess) { } |
b1ab9ed8 A |
89 | void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value); |
90 | ||
91 | OSStatus osStatus() { return mStatus; } | |
92 | operator OSStatus () const { return mStatus; } | |
93 | void throwMe() __attribute__((noreturn)); | |
b1ab9ed8 A |
94 | |
95 | private: | |
96 | CFRef<CFMutableDictionaryRef> mCollection; | |
97 | OSStatus mStatus; | |
d87e1158 | 98 | Mutex mLock; |
b1ab9ed8 | 99 | }; |
d87e1158 | 100 | |
b1ab9ed8 A |
101 | public: |
102 | SECCFFUNCTIONS(SecStaticCode, SecStaticCodeRef, | |
103 | errSecCSInvalidObjectRef, gCFObjects().StaticCode) | |
104 | ||
105 | // implicitly convert SecCodeRefs to their SecStaticCodeRefs | |
106 | static SecStaticCode *requiredStatic(SecStaticCodeRef ref); // convert SecCodeRef | |
427c49bc | 107 | static SecCode *optionalDynamic(SecStaticCodeRef ref); // extract SecCodeRef or NULL if static |
b1ab9ed8 | 108 | |
79b9da22 | 109 | SecStaticCode(DiskRep *rep, uint32_t flags = 0); |
b1ab9ed8 | 110 | virtual ~SecStaticCode() throw(); |
d87e1158 A |
111 | |
112 | void initializeFromParent(const SecStaticCode& parent); | |
113 | ||
b1ab9ed8 A |
114 | bool equal(SecCFObject &other); |
115 | CFHashCode hash(); | |
116 | ||
117 | void detachedSignature(CFDataRef sig); // attach an explicitly given detached signature | |
118 | void checkForSystemSignature(); // check for and attach system-supplied detached signature | |
119 | ||
90dc47c2 A |
120 | typedef std::map<CodeDirectory::HashAlgorithm, CFCopyRef<CFDataRef> > CodeDirectoryMap; |
121 | ||
e3d460c9 | 122 | const CodeDirectory *codeDirectory(bool check = true) const; |
90dc47c2 | 123 | const CodeDirectoryMap *codeDirectories(bool check = true) const; |
e3d460c9 A |
124 | CodeDirectory::HashAlgorithm hashAlgorithm() const { return codeDirectory()->hashType; } |
125 | CodeDirectory::HashAlgorithms hashAlgorithms() const { return mHashAlgorithms; } | |
b1ab9ed8 | 126 | CFDataRef cdHash(); |
e3d460c9 | 127 | CFArrayRef cdHashes(); |
b1ab9ed8 A |
128 | CFDataRef signature(); |
129 | CFAbsoluteTime signingTime(); | |
130 | CFAbsoluteTime signingTimestamp(); | |
131 | bool isSigned() { return codeDirectory(false) != NULL; } | |
e3d460c9 | 132 | DiskRep *diskRep() const { return mRep; } |
427c49bc | 133 | bool isDetached() const { return mRep->base() != mRep; } |
b1ab9ed8 | 134 | std::string mainExecutablePath() { return mRep->mainExecutablePath(); } |
80e23899 | 135 | CFURLRef copyCanonicalPath() const { return mRep->copyCanonicalPath(); } |
b1ab9ed8 | 136 | std::string identifier() { return codeDirectory()->identifier(); } |
420ff9d9 | 137 | const char *teamID() { return codeDirectory()->teamID(); } |
b1ab9ed8 A |
138 | std::string format() const { return mRep->format(); } |
139 | std::string signatureSource(); | |
427c49bc A |
140 | virtual CFDataRef component(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed); |
141 | virtual CFDictionaryRef infoDictionary(); | |
fa7225c8 | 142 | CFDictionaryRef diskRepInformation(); |
427c49bc | 143 | |
b1ab9ed8 | 144 | CFDictionaryRef entitlements(); |
fa7225c8 | 145 | CFDataRef copyComponent(CodeDirectory::SpecialSlot slot, CFDataRef hash); |
b1ab9ed8 | 146 | |
427c49bc | 147 | CFDictionaryRef resourceDictionary(bool check = true); |
b1ab9ed8 | 148 | CFURLRef resourceBase(); |
80e23899 | 149 | void validateResource(CFDictionaryRef files, std::string path, bool isSymlink, ValidationContext &ctx, SecCSFlags flags, uint32_t version); |
5c19dc3a | 150 | void validateSymlinkResource(std::string fullpath, std::string seal, ValidationContext &ctx, SecCSFlags flags); |
e3d460c9 | 151 | |
b1ab9ed8 | 152 | bool flag(uint32_t tested); |
427c49bc A |
153 | |
154 | SecCodeCallback monitor() const { return mMonitor; } | |
155 | void setMonitor(SecCodeCallback monitor) { mMonitor = monitor; } | |
156 | CFTypeRef reportEvent(CFStringRef stage, CFDictionaryRef info); | |
d8f41ccd | 157 | void reportProgress(unsigned amount = 1); |
b1ab9ed8 | 158 | |
d8f41ccd | 159 | void setValidationFlags(SecCSFlags flags) { mValidationFlags = flags; } |
80e23899 A |
160 | void setValidationModifiers(CFDictionaryRef modifiers); |
161 | ||
b1ab9ed8 A |
162 | void resetValidity(); // clear validation caches (if something may have changed) |
163 | ||
164 | bool validated() const { return mValidated; } | |
949d2ff0 | 165 | bool revocationChecked() const { return mRevocationChecked; } |
b1ab9ed8 | 166 | bool valid() const |
427c49bc | 167 | { assert(validated()); return mValidated && (mValidationResult == errSecSuccess); } |
b1ab9ed8 A |
168 | bool validatedExecutable() const { return mExecutableValidated; } |
169 | bool validatedResources() const { return mResourcesValidated; } | |
e3d460c9 | 170 | |
d8f41ccd A |
171 | void prepareProgress(unsigned workload); |
172 | void cancelValidation(); | |
b1ab9ed8 A |
173 | |
174 | void validateDirectory(); | |
427c49bc | 175 | virtual void validateComponent(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed); |
b1ab9ed8 | 176 | void validateNonResourceComponents(); |
e3d460c9 | 177 | void validateTopDirectory(); |
d8f41ccd | 178 | unsigned estimateResourceWorkload(); |
427c49bc | 179 | void validateResources(SecCSFlags flags); |
b1ab9ed8 | 180 | void validateExecutable(); |
80e23899 | 181 | void validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags, bool isFramework); |
b1ab9ed8 | 182 | |
fa7225c8 A |
183 | void validatePlainMemoryResource(string path, CFDataRef fileData, SecCSFlags flags); |
184 | ||
b1ab9ed8 A |
185 | const Requirements *internalRequirements(); |
186 | const Requirement *internalRequirement(SecRequirementType type); | |
187 | const Requirement *designatedRequirement(); | |
188 | const Requirement *defaultDesignatedRequirement(); // newly allocated (caller owns) | |
189 | ||
190 | void validateRequirements(SecRequirementType type, SecStaticCode *target, | |
427c49bc | 191 | OSStatus nullError = errSecSuccess); // target against my [type], throws |
b1ab9ed8 A |
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 | |
194 | ||
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 | |
198 | ||
199 | CFDictionaryRef signingInformation(SecCSFlags flags); // omnibus information-gathering API (creates new dictionary) | |
427c49bc | 200 | |
fa7225c8 | 201 | static bool isAppleDeveloperCert(CFArrayRef certs); // determines if this is an apple developer certificate for library validation |
866f8763 A |
202 | #if !TARGET_OS_OSX |
203 | bool trustedSigningCertChain() { return mTrustedSigningCertChain; } | |
204 | #endif | |
420ff9d9 | 205 | |
90dc47c2 A |
206 | void handleOtherArchitectures(void (^handle)(SecStaticCode* other)); |
207 | ||
b1ab9ed8 | 208 | public: |
427c49bc A |
209 | void staticValidate(SecCSFlags flags, const SecRequirement *req); |
210 | void staticValidateCore(SecCSFlags flags, const SecRequirement *req); | |
d8f41ccd | 211 | |
e3d460c9 | 212 | protected: |
e3d460c9 A |
213 | bool loadCodeDirectories(CodeDirectoryMap& cdMap) const; |
214 | ||
b1ab9ed8 | 215 | protected: |
427c49bc | 216 | CFDictionaryRef getDictionary(CodeDirectory::SpecialSlot slot, bool check = true); // component value as a dictionary |
b1ab9ed8 | 217 | bool verifySignature(); |
866f8763 A |
218 | CFArrayRef createVerificationPolicies(); |
219 | CFArrayRef createTimeStampingAndRevocationPolicies(); | |
fa7225c8 A |
220 | |
221 | // load preferred rules/files dictionaries (cached therein) | |
222 | bool loadResources(CFDictionaryRef& rules, CFDictionaryRef& files, uint32_t& version); | |
b1ab9ed8 A |
223 | |
224 | static void checkOptionalResource(CFTypeRef key, CFTypeRef value, void *context); | |
d8f41ccd | 225 | bool hasWeakResourceRules(CFDictionaryRef rulesDict, uint32_t version, CFArrayRef allowedOmissions); |
b1ab9ed8 | 226 | |
80e23899 A |
227 | private: |
228 | void validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code); | |
866f8763 | 229 | bool checkfix30814861(string path, bool addition); |
79b9da22 | 230 | bool checkfix41082220(OSStatus result); |
80e23899 | 231 | |
866f8763 A |
232 | ResourceBuilder *mCheckfix30814861builder1; |
233 | dispatch_once_t mCheckfix30814861builder1_once; | |
234 | ||
b1ab9ed8 A |
235 | private: |
236 | RefPointer<DiskRep> mRep; // on-disk representation | |
e3d460c9 A |
237 | mutable CodeDirectoryMap mCodeDirectories; // available CodeDirectory blobs by digest type |
238 | mutable CFRef<CFDataRef> mBaseDir; // the primary CodeDirectory blob (whether it's chosen or not) | |
427c49bc | 239 | CFRef<CFDataRef> mDetachedSig; // currently applied explicit detached signature |
b1ab9ed8 | 240 | |
80e23899 A |
241 | // private validation modifiers (only used by Gatekeeper checkfixes) |
242 | MacOSErrorSet mTolerateErrors; // soft error conditions to ignore | |
243 | CFRef<CFArrayRef> mAllowOmissions; // additionally allowed resource omissions | |
244 | ||
b1ab9ed8 A |
245 | // master validation state |
246 | bool mValidated; // core validation was attempted | |
949d2ff0 | 247 | bool mRevocationChecked; // the signature was checked for revocation |
b1ab9ed8 A |
248 | OSStatus mValidationResult; // outcome of core validation |
249 | bool mValidationExpired; // outcome had expired certificates | |
250 | ||
251 | // static executable validation state (nested within mValidated/mValid) | |
252 | bool mExecutableValidated; // tried to validate executable file | |
253 | OSStatus mExecutableValidResult; // outcome if mExecutableValidated | |
254 | ||
255 | // static resource validation state (nested within mValidated/mValid) | |
256 | bool mResourcesValidated; // tried to validate resources | |
427c49bc A |
257 | bool mResourcesDeep; // cached validation was deep |
258 | OSStatus mResourcesValidResult; // outcome if mResourceValidated or... | |
d8f41ccd A |
259 | ValidationContext *mResourcesValidContext; // resource error reporting funnel |
260 | ||
261 | // validation progress state (set when static validation starts) | |
262 | SecCSFlags mValidationFlags; // API flags passed to static validation | |
263 | unsigned mTotalWork; // total expected work (arbitrary units) | |
264 | unsigned mCurrentWork; // currently completed work | |
265 | bool mCancelPending; // cancellation was requested | |
d87e1158 | 266 | Dispatch::Queue mProgressQueue; // progress reporting queue |
b1ab9ed8 | 267 | |
5c19dc3a A |
268 | // nested validation support |
269 | const SecStaticCode *mOuterScope; // containing code (if this is a nested validation; weak) | |
270 | ResourceBuilder *mResourceScope; // current Resource validation stack (while validating; weak) | |
271 | ||
b1ab9ed8 | 272 | // cached contents |
e3d460c9 A |
273 | mutable CFRef<CFDataRef> mDir; // code directory data |
274 | mutable CodeDirectory::HashAlgorithms mHashAlgorithms; // available hash algorithms | |
b1ab9ed8 A |
275 | CFRef<CFDataRef> mSignature; // CMS signature data |
276 | CFAbsoluteTime mSigningTime; // (signed) signing time | |
277 | CFAbsoluteTime mSigningTimestamp; // Timestamp time (from timestamping authority) | |
278 | CFRef<CFDataRef> mCache[cdSlotCount]; // NULL => not tried, kCFNull => absent, other => present | |
279 | ||
280 | // alternative cache forms (storage may depend on cached contents above) | |
281 | CFRef<CFDictionaryRef> mInfoDict; // derived from mCache slot | |
282 | CFRef<CFDictionaryRef> mEntitlements; // derived from mCache slot | |
283 | CFRef<CFDictionaryRef> mResourceDict; // derived from mCache slot | |
284 | const Requirement *mDesignatedReq; // cached designated req if we made one up | |
e3d460c9 A |
285 | CFRef<CFDataRef> mCDHash; // hash of chosen CodeDirectory |
286 | CFRef<CFArrayRef> mCDHashes; // hashes of all CodeDirectories (in digest type code order) | |
b1ab9ed8 A |
287 | |
288 | bool mGotResourceBase; // asked mRep for resourceBasePath | |
289 | CFRef<CFURLRef> mResourceBase; // URL form of resource base directory | |
427c49bc A |
290 | |
291 | SecCodeCallback mMonitor; // registered monitor callback | |
d87e1158 A |
292 | |
293 | LimitedAsync *mLimitedAsync; // limited async workers for verification | |
294 | ||
79b9da22 A |
295 | uint32_t mFlags; // flags from creation |
296 | bool mNotarizationChecked; // ensure notarization check only performed once | |
297 | bool mStaplingChecked; // ensure stapling check only performed once | |
298 | double mNotarizationDate; // the notarization ticket's date, if online check failed | |
299 | ||
b1ab9ed8 A |
300 | // signature verification outcome (mTrust == NULL => not done yet) |
301 | CFRef<SecTrustRef> mTrust; // outcome of crypto validation (valid or not) | |
302 | CFRef<CFArrayRef> mCertChain; | |
866f8763 A |
303 | #if TARGET_OS_OSX |
304 | CSSM_TP_APPLE_EVIDENCE_INFO *mEvalDetails; | |
305 | #else | |
306 | bool mTrustedSigningCertChain; | |
307 | #endif | |
308 | ||
b1ab9ed8 A |
309 | }; |
310 | ||
311 | ||
b1ab9ed8 A |
312 | } // end namespace CodeSigning |
313 | } // end namespace Security | |
314 | ||
315 | #endif // !_H_STATICCODE |