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