2 * Copyright (c) 2006-2012 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 "Requirements.h"
32 #include "requirement.h"
34 #include "codedirectory.h"
35 #include <Security/SecTrust.h>
36 #include <CoreFoundation/CFData.h>
39 namespace CodeSigning
{
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.
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.)
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.
61 class SecStaticCode
: public SecCFObject
{
66 // A context for resource validation operations, to tailor error response.
67 // The base class throws an exception immediately and ignores detail data.
69 class ValidationContext
{
71 virtual ~ValidationContext();
72 virtual void reportProblem(OSStatus rc
, CFStringRef type
, CFTypeRef value
);
76 // A CollectingContext collects all error details and throws an annotated final error.
78 class CollectingContext
: public ValidationContext
{
80 CollectingContext(SecStaticCode
&c
) : code(c
), mStatus(errSecSuccess
) { }
81 void reportProblem(OSStatus rc
, CFStringRef type
, CFTypeRef value
);
83 OSStatus
osStatus() { return mStatus
; }
84 operator OSStatus () const { return mStatus
; }
85 void throwMe() __attribute__((noreturn
));
90 CFRef
<CFMutableDictionaryRef
> mCollection
;
95 SECCFFUNCTIONS(SecStaticCode
, SecStaticCodeRef
,
96 errSecCSInvalidObjectRef
, gCFObjects().StaticCode
)
98 // implicitly convert SecCodeRefs to their SecStaticCodeRefs
99 static SecStaticCode
*requiredStatic(SecStaticCodeRef ref
); // convert SecCodeRef
100 static SecCode
*optionalDynamic(SecStaticCodeRef ref
); // extract SecCodeRef or NULL if static
102 SecStaticCode(DiskRep
*rep
);
103 virtual ~SecStaticCode() throw();
105 bool equal(SecCFObject
&other
);
108 void detachedSignature(CFDataRef sig
); // attach an explicitly given detached signature
109 void checkForSystemSignature(); // check for and attach system-supplied detached signature
111 const CodeDirectory
*codeDirectory(bool check
= true);
113 CFDataRef
signature();
114 CFAbsoluteTime
signingTime();
115 CFAbsoluteTime
signingTimestamp();
116 bool isSigned() { return codeDirectory(false) != NULL
; }
117 DiskRep
*diskRep() { return mRep
; }
118 bool isDetached() const { return mRep
->base() != mRep
; }
119 std::string
mainExecutablePath() { return mRep
->mainExecutablePath(); }
120 CFURLRef
copyCanonicalPath() const { return mRep
->copyCanonicalPath(); }
121 std::string
identifier() { return codeDirectory()->identifier(); }
122 const char *teamID() { return codeDirectory()->teamID(); }
123 std::string
format() const { return mRep
->format(); }
124 std::string
signatureSource();
125 virtual CFDataRef
component(CodeDirectory::SpecialSlot slot
, OSStatus fail
= errSecCSSignatureFailed
);
126 virtual CFDictionaryRef
infoDictionary();
128 CFDictionaryRef
entitlements();
130 CFDictionaryRef
resourceDictionary(bool check
= true);
131 CFURLRef
resourceBase();
132 CFDataRef
resource(std::string path
);
133 CFDataRef
resource(std::string path
, ValidationContext
&ctx
);
134 void validateResource(CFDictionaryRef files
, std::string path
, bool isSymlink
, ValidationContext
&ctx
, SecCSFlags flags
, uint32_t version
);
136 bool flag(uint32_t tested
);
138 SecCodeCallback
monitor() const { return mMonitor
; }
139 void setMonitor(SecCodeCallback monitor
) { mMonitor
= monitor
; }
140 CFTypeRef
reportEvent(CFStringRef stage
, CFDictionaryRef info
);
142 void setValidationModifiers(CFDictionaryRef modifiers
);
144 void resetValidity(); // clear validation caches (if something may have changed)
146 bool validated() const { return mValidated
; }
148 { assert(validated()); return mValidated
&& (mValidationResult
== errSecSuccess
); }
149 bool validatedExecutable() const { return mExecutableValidated
; }
150 bool validatedResources() const { return mResourcesValidated
; }
152 void validateDirectory();
153 virtual void validateComponent(CodeDirectory::SpecialSlot slot
, OSStatus fail
= errSecCSSignatureFailed
);
154 void validateNonResourceComponents();
155 void validateResources(SecCSFlags flags
);
156 void validateExecutable();
157 void validateNestedCode(CFURLRef path
, const ResourceSeal
&seal
, SecCSFlags flags
, bool isFramework
);
159 const Requirements
*internalRequirements();
160 const Requirement
*internalRequirement(SecRequirementType type
);
161 const Requirement
*designatedRequirement();
162 const Requirement
*defaultDesignatedRequirement(); // newly allocated (caller owns)
164 void validateRequirements(SecRequirementType type
, SecStaticCode
*target
,
165 OSStatus nullError
= errSecSuccess
); // target against my [type], throws
166 void validateRequirement(const Requirement
*req
, OSStatus failure
); // me against [req], throws
167 bool satisfiesRequirement(const Requirement
*req
, OSStatus failure
); // me against [req], returns on clean miss
169 // certificates are available after signature validation (they are stored in the CMS signature)
170 SecCertificateRef
cert(int ix
); // get a cert from the cert chain
171 CFArrayRef
certificates(); // get the entire certificate chain
173 CFDictionaryRef
signingInformation(SecCSFlags flags
); // omnibus information-gathering API (creates new dictionary)
175 static bool isAppleDeveloperCert(CFArrayRef certs
); // determines if this is an apple developer certificate for libraray validation
178 void staticValidate(SecCSFlags flags
, const SecRequirement
*req
);
179 void staticValidateCore(SecCSFlags flags
, const SecRequirement
*req
);
182 CFDictionaryRef
getDictionary(CodeDirectory::SpecialSlot slot
, bool check
= true); // component value as a dictionary
183 bool verifySignature();
184 CFTypeRef
verificationPolicy(SecCSFlags flags
);
186 static void checkOptionalResource(CFTypeRef key
, CFTypeRef value
, void *context
);
187 bool hasWeakResourceRules(CFDictionaryRef rulesDict
, CFArrayRef allowedOmissions
);
189 void handleOtherArchitectures(void (^handle
)(SecStaticCode
* other
));
192 void validateOtherVersions(CFURLRef path
, SecCSFlags flags
, SecRequirementRef req
, SecStaticCode
*code
);
195 RefPointer
<DiskRep
> mRep
; // on-disk representation
196 CFRef
<CFDataRef
> mDetachedSig
; // currently applied explicit detached signature
198 // private validation modifiers (only used by Gatekeeper checkfixes)
199 MacOSErrorSet mTolerateErrors
; // soft error conditions to ignore
200 CFRef
<CFArrayRef
> mAllowOmissions
; // additionally allowed resource omissions
202 // master validation state
203 bool mValidated
; // core validation was attempted
204 OSStatus mValidationResult
; // outcome of core validation
205 bool mValidationExpired
; // outcome had expired certificates
207 // static executable validation state (nested within mValidated/mValid)
208 bool mExecutableValidated
; // tried to validate executable file
209 OSStatus mExecutableValidResult
; // outcome if mExecutableValidated
211 // static resource validation state (nested within mValidated/mValid)
212 bool mResourcesValidated
; // tried to validate resources
213 bool mResourcesDeep
; // cached validation was deep
214 OSStatus mResourcesValidResult
; // outcome if mResourceValidated or...
215 CollectingContext
*mResourcesValidContext
; //
218 CFRef
<CFDataRef
> mDir
; // code directory data
219 CFRef
<CFDataRef
> mSignature
; // CMS signature data
220 CFAbsoluteTime mSigningTime
; // (signed) signing time
221 CFAbsoluteTime mSigningTimestamp
; // Timestamp time (from timestamping authority)
222 CFRef
<CFDataRef
> mCache
[cdSlotCount
]; // NULL => not tried, kCFNull => absent, other => present
224 // alternative cache forms (storage may depend on cached contents above)
225 CFRef
<CFDictionaryRef
> mInfoDict
; // derived from mCache slot
226 CFRef
<CFDictionaryRef
> mEntitlements
; // derived from mCache slot
227 CFRef
<CFDictionaryRef
> mResourceDict
; // derived from mCache slot
228 const Requirement
*mDesignatedReq
; // cached designated req if we made one up
229 CFRef
<CFDataRef
> mCDHash
; // hash of CodeDirectory
231 bool mGotResourceBase
; // asked mRep for resourceBasePath
232 CFRef
<CFURLRef
> mResourceBase
; // URL form of resource base directory
234 SecCodeCallback mMonitor
; // registered monitor callback
236 // signature verification outcome (mTrust == NULL => not done yet)
237 CFRef
<SecTrustRef
> mTrust
; // outcome of crypto validation (valid or not)
238 CFRef
<CFArrayRef
> mCertChain
;
239 CSSM_TP_APPLE_EVIDENCE_INFO
*mEvalDetails
;
243 } // end namespace CodeSigning
244 } // end namespace Security
246 #endif // !_H_STATICCODE