/ OSX / libsecurity_codesigning / lib / StaticCode.h
StaticCode.h
  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 "csutilities.h"
 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>
 38  #include <security_utilities/dispatch.h>
 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
 60  // resetValidity() is called, whichever is sooner. If you need to keep them longer,
 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:
 73  		ValidationContext(SecStaticCode &c) : code(c) { }
 74  		virtual ~ValidationContext();
 75  		virtual void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value);
 76  		
 77  		virtual OSStatus osStatus()	{ return noErr; }
 78  		virtual void throwMe()		{ }
 79  		
 80  		SecStaticCode &code;
 81  	};
 82  	
 83  	//
 84  	// A CollectingContext collects all error details and throws an annotated final error.
 85  	//
 86  	class CollectingContext : public ValidationContext {
 87  	public:
 88  		CollectingContext(SecStaticCode &c) : ValidationContext(c), mStatus(errSecSuccess) { }
 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));
 94  
 95  	private:
 96  		CFRef<CFMutableDictionaryRef> mCollection;
 97  		OSStatus mStatus;
 98  		Mutex mLock;
 99  	};
100  
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
107  	static SecCode *optionalDynamic(SecStaticCodeRef ref); // extract SecCodeRef or NULL if static
108  
109  	SecStaticCode(DiskRep *rep, uint32_t flags = 0);
110      virtual ~SecStaticCode() _NOEXCEPT;
111  
112      void initializeFromParent(const SecStaticCode& parent);
113  
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  
120  	typedef std::map<CodeDirectory::HashAlgorithm, CFCopyRef<CFDataRef> > CodeDirectoryMap;
121  
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; }
126  	CFDataRef cdHash();
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 copyDiskRepInformation();
144  
145  	CFDictionaryRef entitlements();
146  	CFDataRef copyComponent(CodeDirectory::SpecialSlot slot, CFDataRef hash);
147  
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);
152  
153  	bool flag(uint32_t tested);
154  
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);
159  
160  	SecCSFlags getFlags() { return mFlags; }
161  	void setFlags(SecCSFlags flags) { mFlags = flags; }
162  	void setValidationFlags(SecCSFlags flags) { mValidationFlags = flags; }
163  	void setValidationModifiers(CFDictionaryRef modifiers);
164  	
165  	void resetValidity();						// clear validation caches (if something may have changed)
166  	
167  	bool validated() const	{ return mValidated; }
168  	bool revocationChecked() const { return mRevocationChecked; }
169  	bool valid() const
170  		{ assert(validated()); return mValidated && (mValidationResult == errSecSuccess); }
171  	bool validatedExecutable() const	{ return mExecutableValidated; }
172  	bool validatedResources() const	{ return mResourcesValidated; }
173  
174  	void prepareProgress(unsigned workload);
175  	void cancelValidation();
176  
177  	void validateDirectory();
178  	virtual void validateComponent(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
179  	void validateNonResourceComponents();
180  	void validateTopDirectory();
181  	unsigned estimateResourceWorkload();
182  	void validateResources(SecCSFlags flags);
183  	void validateExecutable();
184  	void validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags, bool isFramework);
185  	void checkRevocationOnNestedBinary(UnixPlusPlus::FileDesc &fd, CFURLRef url, SecCSFlags flags);
186  	bool validationCannotUseNetwork();
187  	
188  	void validatePlainMemoryResource(string path, CFDataRef fileData, SecCSFlags flags);
189  	
190  	const Requirements *internalRequirements();
191  	const Requirement *internalRequirement(SecRequirementType type);
192  	const Requirement *designatedRequirement();
193  	const Requirement *defaultDesignatedRequirement();		// newly allocated (caller owns)
194  	
195  	void validateRequirements(SecRequirementType type, SecStaticCode *target,
196  		OSStatus nullError = errSecSuccess);										// target against my [type], throws
197  	void validateRequirement(const Requirement *req, OSStatus failure);		// me against [req], throws
198  	bool satisfiesRequirement(const Requirement *req, OSStatus failure);	// me against [req], returns on clean miss
199  	
200  	// certificates are available after signature validation (they are stored in the CMS signature)
201  	SecCertificateRef cert(int ix);		// get a cert from the cert chain
202  	CFArrayRef certificates();			// get the entire certificate chain
203  	
204  	CFDictionaryRef signingInformation(SecCSFlags flags); // omnibus information-gathering API (creates new dictionary)
205  
206  	static bool isAppleDeveloperCert(CFArrayRef certs); // determines if this is an apple developer certificate for library validation
207      bool trustedSigningCertChain() { return mTrustedSigningCertChain; }
208  
209  	void handleOtherArchitectures(void (^handle)(SecStaticCode* other));
210  
211  	uint8_t cmsDigestHashType() const { return mCMSDigestHashType; };
212  	CFDataRef createCmsDigest();
213  public:
214  	void staticValidate(SecCSFlags flags, const SecRequirement *req);
215  	void staticValidateCore(SecCSFlags flags, const SecRequirement *req);
216  	void staticValidateResource(string resourcePath, SecCSFlags flags, const SecRequirement *req);
217  	
218  protected:
219  	bool loadCodeDirectories(CodeDirectoryMap& cdMap) const;
220  	
221  protected:
222  	CFDictionaryRef getDictionary(CodeDirectory::SpecialSlot slot, bool check = true); // component value as a dictionary
223  	bool verifySignature();
224  	CFArrayRef createVerificationPolicies();
225  	CFArrayRef createTimeStampingAndRevocationPolicies();
226  	
227  	// load preferred rules/files dictionaries (cached therein)
228  	bool loadResources(CFDictionaryRef& rules, CFDictionaryRef& files, uint32_t& version);
229  
230  	static void checkOptionalResource(CFTypeRef key, CFTypeRef value, void *context);
231  	bool hasWeakResourceRules(CFDictionaryRef rulesDict, uint32_t version, CFArrayRef allowedOmissions);
232  
233  private:
234  	void validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code);
235  	bool checkfix30814861(string path, bool addition);
236  	bool checkfix41082220(OSStatus result);
237  	CFArrayRef copyCertChain(SecTrustRef trust);
238  
239  	ResourceBuilder *mCheckfix30814861builder1;
240  	dispatch_once_t mCheckfix30814861builder1_once;
241  	
242  private:
243  	static const uint8_t mCMSDigestHashType = kSecCodeSignatureHashSHA256;
244  										// hash of CMS digest (kSecCodeSignatureHash* constant)
245  	RefPointer<DiskRep> mRep;			// on-disk representation
246  	mutable CodeDirectoryMap mCodeDirectories; // available CodeDirectory blobs by digest type
247  	mutable CFRef<CFDataRef> mBaseDir;	// the primary CodeDirectory blob (whether it's chosen or not)
248  	CFRef<CFDataRef> mDetachedSig;		// currently applied explicit detached signature
249  	
250  	// private validation modifiers (only used by Gatekeeper checkfixes)
251  	MacOSErrorSet mTolerateErrors;		// soft error conditions to ignore
252  	CFRef<CFArrayRef> mAllowOmissions;	// additionally allowed resource omissions
253  	
254  	// master validation state
255  	bool mValidated;					// core validation was attempted
256  	bool mRevocationChecked;			// the signature was checked for revocation
257  	OSStatus mValidationResult;			// outcome of core validation
258  	bool mValidationExpired;			// outcome had expired certificates
259  	
260  	// static executable validation state (nested within mValidated/mValid)
261  	bool mExecutableValidated;			// tried to validate executable file
262  	OSStatus mExecutableValidResult;		// outcome if mExecutableValidated
263  
264  	// static resource validation state (nested within mValidated/mValid)
265  	bool mResourcesValidated;			// tried to validate resources
266  	bool mResourcesDeep;				// cached validation was deep
267  	OSStatus mResourcesValidResult;			// outcome if mResourceValidated or...
268  	ValidationContext *mResourcesValidContext; // resource error reporting funnel
269  	
270  	// validation progress state (set when static validation starts)
271  	SecCSFlags mValidationFlags;		// API flags passed to static validation
272  	unsigned mTotalWork;				// total expected work (arbitrary units)
273  	unsigned mCurrentWork;				// currently completed work
274  	bool mCancelPending;				// cancellation was requested
275  	Dispatch::Queue mProgressQueue;		// progress reporting queue
276  
277  	// nested validation support
278  	const SecStaticCode *mOuterScope;	// containing code (if this is a nested validation; weak)
279  	ResourceBuilder *mResourceScope;	// current Resource validation stack (while validating; weak)
280  
281  	// cached contents
282  	mutable CFRef<CFDataRef> mDir;		// code directory data
283  	mutable CodeDirectory::HashAlgorithms mHashAlgorithms; // available hash algorithms
284  	CFRef<CFDataRef> mSignature;		// CMS signature data
285  	CFAbsoluteTime mSigningTime;		// (signed) signing time
286  	CFAbsoluteTime mSigningTimestamp;		// Timestamp time (from timestamping authority)
287  	CFRef<CFDataRef> mCache[cdSlotCount]; // NULL => not tried, kCFNull => absent, other => present
288  	
289  	// alternative cache forms (storage may depend on cached contents above)
290  	CFRef<CFDictionaryRef> mInfoDict;	// derived from mCache slot
291  	CFRef<CFDictionaryRef> mEntitlements; // derived from mCache slot
292  	CFRef<CFDictionaryRef> mResourceDict; // derived from mCache slot
293  	const Requirement *mDesignatedReq;	// cached designated req if we made one up
294  	CFRef<CFDataRef> mCDHash;			// hash of chosen CodeDirectory
295  	CFRef<CFArrayRef> mCDHashes;		// hashes of all CodeDirectories (in digest type code order)
296  	CFRef<CFDictionaryRef> mCDHashFullDict;	// untruncated hashes of CodeDirectories (as dictionary)
297  
298  	bool mGotResourceBase;				// asked mRep for resourceBasePath
299  	CFRef<CFURLRef> mResourceBase;		// URL form of resource base directory
300  
301  	SecCodeCallback mMonitor;			// registered monitor callback
302  
303  	LimitedAsync *mLimitedAsync;		// limited async workers for verification
304  
305  	SecCSFlags mFlags;					// flags from creation
306  	bool mNotarizationChecked;			// ensure notarization check only performed once
307  	bool mStaplingChecked;				// ensure stapling check only performed once
308  	double mNotarizationDate;			// the notarization ticket's date, if online check failed
309  	bool mNetworkEnabledByDefault;		// whether this code object uses the network by default
310  
311  	// signature verification outcome (mTrust == NULL => not done yet)
312  	CFRef<SecTrustRef> mTrust;			// outcome of crypto validation (valid or not)
313  	CFRef<CFArrayRef> mCertChain;
314      bool mTrustedSigningCertChain;
315  };
316  
317  
318  } // end namespace CodeSigning
319  } // end namespace Security
320  
321  #endif // !_H_STATICCODE