1/*
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
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"
31#include "Requirements.h"
32#include "requirement.h"
33#include "diskrep.h"
34#include "codedirectory.h"
35#include <Security/SecTrust.h>
36#include <CoreFoundation/CFData.h>
37
38namespace Security {
39namespace CodeSigning {
40
41
42class SecCode;
43
44
45//
46// A SecStaticCode object represents the file system version of some code.
47// There's a lot of pieces to this, and we'll bring them all into
48// memory here (lazily) and let you fondle them with ease.
49//
50// Note that concrete knowledge of where stuff is stored resides in the DiskRep
51// object we hold. DiskReps allocate, retrieve, and return data to us. We are
52// responsible for interpreting, caching, and validating them. (In other words,
53// DiskReps know where stuff is and how it is stored, but we know what it means.)
54//
55// Data accessors (returning CFDataRef, CFDictionaryRef, various pointers, etc.)
56// cache those values internally and return unretained(!) references ("Get" style)
57// that are valid as long as the SecStaticCode object's lifetime, or until
58// resetValidity() is called, whichever is sooner. If you need to keep them longer,
59// retain or copy them as needed.
60//
61class SecStaticCode : public SecCFObject {
62	NOCOPY(SecStaticCode)
63
64protected:
65	//
66	// A context for resource validation operations, to tailor error response.
67	// The base class throws an exception immediately and ignores detail data.
68	//
69	class ValidationContext {
70	public:
71		ValidationContext(SecStaticCode &c) : code(c) { }
72		virtual ~ValidationContext();
73		virtual void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value);
74
75		virtual OSStatus osStatus()	{ return noErr; }
76		virtual void throwMe()		{ }
77
78		SecStaticCode &code;
79	};
80
81	//
82	// A CollectingContext collects all error details and throws an annotated final error.
83	//
84	class CollectingContext : public ValidationContext {
85	public:
86		CollectingContext(SecStaticCode &c) : ValidationContext(c), mStatus(errSecSuccess) { }
87		void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value);
88
89		OSStatus osStatus()		{ return mStatus; }
90		operator OSStatus () const		{ return mStatus; }
91		void throwMe() __attribute__((noreturn));
92
93	private:
94		CFRef<CFMutableDictionaryRef> mCollection;
95		OSStatus mStatus;
96	};
97
98public:
99	SECCFFUNCTIONS(SecStaticCode, SecStaticCodeRef,
100		errSecCSInvalidObjectRef, gCFObjects().StaticCode)
101
102	// implicitly convert SecCodeRefs to their SecStaticCodeRefs
103	static SecStaticCode *requiredStatic(SecStaticCodeRef ref);	// convert SecCodeRef
104	static SecCode *optionalDynamic(SecStaticCodeRef ref); // extract SecCodeRef or NULL if static
105
106	SecStaticCode(DiskRep *rep);
107    virtual ~SecStaticCode() throw();
108
109    bool equal(SecCFObject &other);
110    CFHashCode hash();
111
112	void detachedSignature(CFDataRef sig);		// attach an explicitly given detached signature
113	void checkForSystemSignature();				// check for and attach system-supplied detached signature
114
115	const CodeDirectory *codeDirectory(bool check = true);
116	CFDataRef cdHash();
117	CFDataRef signature();
118	CFAbsoluteTime signingTime();
119	CFAbsoluteTime signingTimestamp();
120	bool isSigned() { return codeDirectory(false) != NULL; }
121	DiskRep *diskRep() { return mRep; }
122	bool isDetached() const { return mRep->base() != mRep; }
123	std::string mainExecutablePath() { return mRep->mainExecutablePath(); }
124	CFURLRef copyCanonicalPath() const { return mRep->copyCanonicalPath(); }
125	std::string identifier() { return codeDirectory()->identifier(); }
126	const char *teamID() { return codeDirectory()->teamID(); }
127	std::string format() const { return mRep->format(); }
128	std::string signatureSource();
129 	virtual CFDataRef component(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
130 	virtual CFDictionaryRef infoDictionary();
131
132	CFDictionaryRef entitlements();
133
134	CFDictionaryRef resourceDictionary(bool check = true);
135	CFURLRef resourceBase();
136	CFDataRef resource(std::string path);
137	CFDataRef resource(std::string path, ValidationContext &ctx);
138	void validateResource(CFDictionaryRef files, std::string path, bool isSymlink, ValidationContext &ctx, SecCSFlags flags, uint32_t version);
139
140	bool flag(uint32_t tested);
141
142	SecCodeCallback monitor() const { return mMonitor; }
143	void setMonitor(SecCodeCallback monitor) { mMonitor = monitor; }
144	CFTypeRef reportEvent(CFStringRef stage, CFDictionaryRef info);
145	void reportProgress(unsigned amount = 1);
146
147	void setValidationFlags(SecCSFlags flags) { mValidationFlags = flags; }
148	void setValidationModifiers(CFDictionaryRef modifiers);
149
150	void resetValidity();						// clear validation caches (if something may have changed)
151
152	bool validated() const	{ return mValidated; }
153	bool valid() const
154		{ assert(validated()); return mValidated && (mValidationResult == errSecSuccess); }
155	bool validatedExecutable() const	{ return mExecutableValidated; }
156	bool validatedResources() const	{ return mResourcesValidated; }
157
158	void prepareProgress(unsigned workload);
159	void cancelValidation();
160
161	void validateDirectory();
162	virtual void validateComponent(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
163	void validateNonResourceComponents();
164	unsigned estimateResourceWorkload();
165	void validateResources(SecCSFlags flags);
166	void validateExecutable();
167	void validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags, bool isFramework);
168
169	const Requirements *internalRequirements();
170	const Requirement *internalRequirement(SecRequirementType type);
171	const Requirement *designatedRequirement();
172	const Requirement *defaultDesignatedRequirement();		// newly allocated (caller owns)
173
174	void validateRequirements(SecRequirementType type, SecStaticCode *target,
175		OSStatus nullError = errSecSuccess);										// target against my [type], throws
176	void validateRequirement(const Requirement *req, OSStatus failure);		// me against [req], throws
177	bool satisfiesRequirement(const Requirement *req, OSStatus failure);	// me against [req], returns on clean miss
178
179	// certificates are available after signature validation (they are stored in the CMS signature)
180	SecCertificateRef cert(int ix);		// get a cert from the cert chain
181	CFArrayRef certificates();			// get the entire certificate chain
182
183	CFDictionaryRef signingInformation(SecCSFlags flags); // omnibus information-gathering API (creates new dictionary)
184
185	static bool isAppleDeveloperCert(CFArrayRef certs); // determines if this is an apple developer certificate for libraray validation
186
187public:
188	void staticValidate(SecCSFlags flags, const SecRequirement *req);
189	void staticValidateCore(SecCSFlags flags, const SecRequirement *req);
190
191protected:
192	CFDictionaryRef getDictionary(CodeDirectory::SpecialSlot slot, bool check = true); // component value as a dictionary
193	bool verifySignature();
194	CFArrayRef verificationPolicies();
195
196	static void checkOptionalResource(CFTypeRef key, CFTypeRef value, void *context);
197	bool hasWeakResourceRules(CFDictionaryRef rulesDict, uint32_t version, CFArrayRef allowedOmissions);
198
199	void handleOtherArchitectures(void (^handle)(SecStaticCode* other));
200
201private:
202	void validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code);
203
204private:
205	RefPointer<DiskRep> mRep;			// on-disk representation
206	CFRef<CFDataRef> mDetachedSig;		// currently applied explicit detached signature
207
208	// private validation modifiers (only used by Gatekeeper checkfixes)
209	MacOSErrorSet mTolerateErrors;		// soft error conditions to ignore
210	CFRef<CFArrayRef> mAllowOmissions;	// additionally allowed resource omissions
211
212	// master validation state
213	bool mValidated;					// core validation was attempted
214	OSStatus mValidationResult;			// outcome of core validation
215	bool mValidationExpired;			// outcome had expired certificates
216
217	// static executable validation state (nested within mValidated/mValid)
218	bool mExecutableValidated;			// tried to validate executable file
219	OSStatus mExecutableValidResult;		// outcome if mExecutableValidated
220
221	// static resource validation state (nested within mValidated/mValid)
222	bool mResourcesValidated;			// tried to validate resources
223	bool mResourcesDeep;				// cached validation was deep
224	OSStatus mResourcesValidResult;			// outcome if mResourceValidated or...
225	ValidationContext *mResourcesValidContext; // resource error reporting funnel
226
227	// validation progress state (set when static validation starts)
228	SecCSFlags mValidationFlags;		// API flags passed to static validation
229	unsigned mTotalWork;				// total expected work (arbitrary units)
230	unsigned mCurrentWork;				// currently completed work
231	bool mCancelPending;				// cancellation was requested
232	Mutex mCancelLock;					// protects mCancelPending
233
234	// cached contents
235	CFRef<CFDataRef> mDir;				// code directory data
236	CFRef<CFDataRef> mSignature;		// CMS signature data
237	CFAbsoluteTime mSigningTime;		// (signed) signing time
238	CFAbsoluteTime mSigningTimestamp;		// Timestamp time (from timestamping authority)
239	CFRef<CFDataRef> mCache[cdSlotCount]; // NULL => not tried, kCFNull => absent, other => present
240
241	// alternative cache forms (storage may depend on cached contents above)
242	CFRef<CFDictionaryRef> mInfoDict;	// derived from mCache slot
243	CFRef<CFDictionaryRef> mEntitlements; // derived from mCache slot
244	CFRef<CFDictionaryRef> mResourceDict; // derived from mCache slot
245	const Requirement *mDesignatedReq;	// cached designated req if we made one up
246	CFRef<CFDataRef> mCDHash;			// hash of CodeDirectory
247
248	bool mGotResourceBase;				// asked mRep for resourceBasePath
249	CFRef<CFURLRef> mResourceBase;		// URL form of resource base directory
250
251	SecCodeCallback mMonitor;			// registered monitor callback
252
253	// signature verification outcome (mTrust == NULL => not done yet)
254	CFRef<SecTrustRef> mTrust;			// outcome of crypto validation (valid or not)
255	CFRef<CFArrayRef> mCertChain;
256	CSSM_TP_APPLE_EVIDENCE_INFO *mEvalDetails;
257};
258
259
260} // end namespace CodeSigning
261} // end namespace Security
262
263#endif // !_H_STATICCODE
264