diskrep.h
1 /* 2 * Copyright (c) 2006-2007,2011-2012,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 // diskrep - disk representations of code 26 // 27 #ifndef _H_DISKREP 28 #define _H_DISKREP 29 30 #include "cs.h" 31 #include "codedirectory.h" 32 #include "cdbuilder.h" 33 #include "requirement.h" 34 #include "resources.h" 35 #include <security_utilities/macho++.h> // for class Architecture 36 #include <security_utilities/refcount.h> 37 #include <security_utilities/superblob.h> 38 #include <CoreFoundation/CFData.h> 39 40 namespace Security { 41 namespace CodeSigning { 42 43 class ResourceBuilder; 44 class SecCodeSigner; 45 46 47 // 48 // DiskRep is an abstract interface to code somewhere located by 49 // a file system path. It presents the ability to read and write 50 // Code Signing-related information about such code without exposing 51 // the details of the storage locations or formats. 52 // 53 class DiskRep : public RefCount { 54 public: 55 class SigningContext; 56 57 typedef std::set<OSStatus> ToleratedErrors; 58 59 public: 60 DiskRep(); 61 virtual ~DiskRep(); 62 virtual DiskRep *base(); 63 virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component 64 virtual CFDataRef identification() = 0; // binary lookup identifier 65 virtual std::string mainExecutablePath() = 0; // path to main executable 66 virtual CFURLRef copyCanonicalPath() = 0; // path to whole code 67 virtual std::string resourcesRootPath(); // resource directory if any [none] 68 virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set [no change] 69 virtual void prepareForSigning(SigningContext& context); // pre-adjust signing defaults before argument preparation [none] 70 virtual Universal *mainExecutableImage(); // Mach-O image if Mach-O based [null] 71 virtual size_t signingBase(); // start offset of signed area in main executable [zero] 72 virtual size_t signingLimit() = 0; // size of signed area in main executable 73 74 // The executable segment, if present, denotes which part of the image can be mapped 75 // into a virtual address space as executable. Not all platforms check this. 76 virtual size_t execSegBase(const Architecture *arch); // start offset of executable segment in main executable [zero] 77 virtual size_t execSegLimit(const Architecture *arch) = 0; // size of executable segment in main executable 78 79 virtual std::string format() = 0; // human-readable type string 80 virtual CFArrayRef modifiedFiles(); // list of files modified by signing [main execcutable only] 81 virtual UnixPlusPlus::FileDesc &fd() = 0; // a cached file descriptor for main executable file 82 virtual void flush(); // flush caches (refetch as needed) 83 virtual CFDictionaryRef copyDiskRepInformation(); // information from diskrep 84 85 virtual void registerStapledTicket(); 86 87 // default values for signing operations 88 virtual std::string recommendedIdentifier(const SigningContext &ctx) = 0; // default identifier 89 virtual CFDictionaryRef defaultResourceRules(const SigningContext &ctx); // default resource rules [none] 90 virtual const Requirements *defaultRequirements(const Architecture *arch, 91 const SigningContext &ctx); // default internal requirements [none] 92 virtual size_t pageSize(const SigningContext &ctx); // default main executable page size [infinite, i.e. no paging] 93 94 virtual void strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags); // perform strict validation 95 virtual void strictValidateStructure(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { }; // perform structural strict validation 96 virtual CFArrayRef allowedResourceOmissions(); // allowed (default) resource omission rules 97 98 virtual bool appleInternalForcePlatform() const {return false;}; 99 100 bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; } 101 102 // shorthands 103 CFDataRef signature() { return component(cdSignatureSlot); } 104 105 public: 106 class Writer; 107 virtual Writer *writer(); // Writer factory 108 109 public: 110 // optional information that might be used to create a suitable DiskRep. All optional 111 struct Context { 112 Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL), size(0) { } 113 Architecture arch; // explicit architecture (choose amongst universal variants) 114 const char *version; // bundle version (string) 115 off_t offset; // explicit file offset 116 bool fileOnly; // only consider single-file representations (no bundles etc.) 117 const void *inMemory; // consider using in-memory copy at this address 118 size_t size; // size of this mach-o slice 119 }; 120 121 static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path 122 static DiskRep *bestFileGuess(const char *path, const Context *ctx = NULL); // ctx (if any) + fileOnly 123 static DiskRep *bestGuess(const char *path, size_t archOffset); // Mach-O at given file offset only 124 125 // versions using std::string paths (merely a convenience) 126 static DiskRep *bestGuess(const std::string &path, const Context *ctx = NULL) 127 { return bestGuess(path.c_str(), ctx); } 128 static DiskRep *bestGuess(const std::string &path, size_t archOffset) { return bestGuess(path.c_str(), archOffset); } 129 static DiskRep *bestFileGuess(const std::string &path, const Context *ctx = NULL) { return bestFileGuess(path.c_str(), ctx); } 130 131 public: 132 // see DiskRep::Writer docs for why this is here 133 class SigningContext { 134 protected: 135 SigningContext() { } 136 137 public: 138 virtual std::string sdkPath(const std::string &path) const = 0; 139 virtual bool isAdhoc() const = 0; 140 virtual SecCSFlags signingFlags() const = 0; 141 142 virtual const CodeDirectory::HashAlgorithms &digestAlgorithms() const = 0; 143 virtual void setDigestAlgorithms(CodeDirectory::HashAlgorithms types) = 0; 144 145 void setDigestAlgorithm(CodeDirectory::HashAlgorithm type) 146 { 147 CodeDirectory::HashAlgorithms types; 148 types.insert(type); 149 setDigestAlgorithms(types); 150 } 151 }; 152 153 protected: 154 // canonically derive a suggested signing identifier from some string 155 static std::string canonicalIdentifier(const std::string &name); 156 157 public: 158 static const size_t segmentedPageSize = 4096; // default page size for system-paged signatures 159 static const size_t monolithicPageSize = 0; // default page size for non-Mach-O executables 160 }; 161 162 /* 163 * Editable Disk Reps allow editing of their existing code signature. 164 * Specifically, they allow for individual components to be replaced, 165 * while preserving all other components. 166 * Lots of restrictions apply, e.g. machO signatures' superblobs may 167 * not change in size, and components covered by the code directory 168 * cannot be replaced without adjusting the code directory. 169 * Replacing or adding CMS blobs (having reserved enough size in the 170 * superblob beforehand) is the original reason this trait exists. 171 */ 172 class EditableDiskRep { 173 public: 174 typedef std::map<CodeDirectory::Slot, CFCopyRef<CFDataRef>> RawComponentMap; 175 176 /* Return all components in raw form. 177 * Signature editing will add all the components obtained hereby 178 * back to their specific slots, though some of them may have 179 * been replaced in the map. 180 */ 181 virtual RawComponentMap createRawComponents() = 0; 182 }; 183 184 // 185 // Write-access objects. 186 // At this layer they are quite abstract, carrying just the functionality needed 187 // for the signing machinery to place data wherever it should go. Each DiskRep subclass 188 // that supports writing signing data to a place inside the code needs to implement 189 // a subclass of Writer and return an instance in the DiskRep::writer() method when asked. 190 // 191 // The Writer class is subclassed interestingly by the Mach-O multi-architecture signing code, 192 // which is handled as a special case. This means that not all Writer subclass objects were made 193 // by DiskRep::writer, and it is unwise to assume so. 194 // 195 // Note that the methods that provide defaults for signing operations are in DiskRep rather 196 // than here. That's because writers abstract data *sending*, and are virtual on management 197 // of stored data, while DiskRep is virtual on the existing code object, which is where 198 // we get our defaults from. 199 // 200 class DiskRep::Writer : public RefCount { 201 public: 202 Writer(uint32_t attrs = 0); 203 virtual ~Writer(); 204 virtual void component(CodeDirectory::SpecialSlot slot, CFDataRef data) = 0; 205 virtual uint32_t attributes() const; 206 virtual void addDiscretionary(CodeDirectory::Builder &builder); 207 virtual void remove(); 208 virtual void flush(); 209 210 bool attribute(uint32_t attr) const { return mAttributes & attr; } 211 212 void signature(CFDataRef data) { component(cdSignatureSlot, data); } 213 void codeDirectory(const CodeDirectory *cd, CodeDirectory::SpecialSlot slot) 214 { component(slot, CFTempData(cd->data(), cd->length())); } 215 216 #if TARGET_OS_OSX 217 bool getPreserveAFSC() { return mPreserveAFSC; } 218 void setPreserveAFSC(bool flag) { mPreserveAFSC = flag; } 219 #endif 220 221 private: 222 Architecture mArch; 223 uint32_t mAttributes; 224 #if TARGET_OS_OSX 225 bool mPreserveAFSC = false; // preserve AFSC compression 226 #endif 227 }; 228 229 // 230 // Writer attributes. Defaults should be off-bits. 231 // 232 enum { 233 writerLastResort = 0x0001, // prefers not to store attributes itself 234 writerNoGlobal = 0x0002, // has only per-architecture storage 235 }; 236 237 238 // 239 // A prefix DiskRep that filters (only) signature-dependent behavior and passes 240 // all code-dependent behavior off to an underlying (different) DiskRep. 241 // FilterRep subclasses are typically "stacked" on top of their base DiskRep, and 242 // then used in their place. 243 // 244 class FilterRep : public DiskRep { 245 public: 246 FilterRep(DiskRep *orig) : mOriginal(orig) { } 247 248 DiskRep *base() { return mOriginal; } 249 250 // things that look at signature components are filtered 251 CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; 252 253 // the rest of the virtual behavior devolves on the original DiskRep 254 CFDataRef identification() { return mOriginal->identification(); } 255 std::string mainExecutablePath() { return mOriginal->mainExecutablePath(); } 256 CFURLRef copyCanonicalPath() { return mOriginal->copyCanonicalPath(); } 257 std::string resourcesRootPath() { return mOriginal->resourcesRootPath(); } 258 void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); } 259 Universal *mainExecutableImage() { return mOriginal->mainExecutableImage(); } 260 size_t signingBase() { return mOriginal->signingBase(); } 261 size_t signingLimit() { return mOriginal->signingLimit(); } 262 size_t execSegBase(const Architecture *arch) { return mOriginal->execSegBase(arch); } 263 size_t execSegLimit(const Architecture *arch) { return mOriginal->execSegLimit(arch); } 264 std::string format() { return mOriginal->format(); } 265 CFArrayRef modifiedFiles() { return mOriginal->modifiedFiles(); } 266 UnixPlusPlus::FileDesc &fd() { return mOriginal->fd(); } 267 void flush() { return mOriginal->flush(); } 268 269 std::string recommendedIdentifier(const SigningContext &ctx) 270 { return mOriginal->recommendedIdentifier(ctx); } 271 CFDictionaryRef defaultResourceRules(const SigningContext &ctx) 272 { return mOriginal->defaultResourceRules(ctx); } 273 const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx) 274 { return mOriginal->defaultRequirements(arch, ctx); } 275 size_t pageSize(const SigningContext &ctx) { return mOriginal->pageSize(ctx); } 276 277 void strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { mOriginal->strictValidate(cd, tolerated, flags); } 278 void strictValidateStructure(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { mOriginal->strictValidateStructure(cd, tolerated, flags); } 279 CFArrayRef allowedResourceOmissions() { return mOriginal->allowedResourceOmissions(); } 280 281 private: 282 RefPointer<DiskRep> mOriginal; // underlying representation 283 }; 284 285 286 } // end namespace CodeSigning 287 } // end namespace Security 288 289 #endif // !_H_DISKREP