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