1/* 2 * Copyright (c) 2006-2007 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 40namespace Security { 41namespace CodeSigning { 42 43class ResourceBuilder; 44 45 46// 47// DiskRep is an abstract interface to code somewhere located by 48// a file system path. It presents the ability to read and write 49// Code Signing-related information about such code without exposing 50// the details of the storage locations or formats. 51// 52class DiskRep : public RefCount { 53public: 54 class SigningContext; 55 56 typedef std::set<OSStatus> ToleratedErrors; 57 58public: 59 DiskRep(); 60 virtual ~DiskRep(); 61 virtual DiskRep *base(); 62 virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component 63 virtual CFDataRef identification() = 0; // binary lookup identifier 64 virtual std::string mainExecutablePath() = 0; // path to main executable 65 virtual CFURLRef copyCanonicalPath() = 0; // path to whole code 66 virtual std::string resourcesRootPath(); // resource directory if any [none] 67 virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set [no change] 68 virtual Universal *mainExecutableImage(); // Mach-O image if Mach-O based [null] 69 virtual size_t signingBase(); // start offset of signed area in main executable [zero] 70 virtual size_t signingLimit() = 0; // size of signed area in main executable 71 virtual std::string format() = 0; // human-readable type string 72 virtual CFArrayRef modifiedFiles(); // list of files modified by signing [main execcutable only] 73 virtual UnixPlusPlus::FileDesc &fd() = 0; // a cached file descriptor for main executable file 74 virtual void flush(); // flush caches (refetch as needed) 75 76 // default values for signing operations 77 virtual std::string recommendedIdentifier(const SigningContext &ctx) = 0; // default identifier 78 virtual CFDictionaryRef defaultResourceRules(const SigningContext &ctx); // default resource rules [none] 79 virtual const Requirements *defaultRequirements(const Architecture *arch, 80 const SigningContext &ctx); // default internal requirements [none] 81 virtual size_t pageSize(const SigningContext &ctx); // default main executable page size [infinite, i.e. no paging] 82 83 virtual void strictValidate(const ToleratedErrors& tolerated); // perform strict validation 84 virtual CFArrayRef allowedResourceOmissions(); // allowed (default) resource omission rules 85 86 bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; } 87 88 // shorthands 89 CFDataRef codeDirectory() { return component(cdCodeDirectorySlot); } 90 CFDataRef signature() { return component(cdSignatureSlot); } 91 92public: 93 class Writer; 94 virtual Writer *writer(); // Writer factory 95 96public: 97 // optional information that might be used to create a suitable DiskRep. All optional 98 struct Context { 99 Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL), size(0) { } 100 Architecture arch; // explicit architecture (choose amongst universal variants) 101 const char *version; // bundle version (string) 102 off_t offset; // explicit file offset 103 bool fileOnly; // only consider single-file representations (no bundles etc.) 104 const void *inMemory; // consider using in-memory copy at this address 105 size_t size; // size of this mach-o slice 106 }; 107 108 static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path 109 static DiskRep *bestFileGuess(const char *path, const Context *ctx = NULL); // ctx (if any) + fileOnly 110 static DiskRep *bestGuess(const char *path, size_t archOffset); // Mach-O at given file offset only 111 112 // versions using std::string paths (merely a convenience) 113 static DiskRep *bestGuess(const std::string &path, const Context *ctx = NULL) 114 { return bestGuess(path.c_str(), ctx); } 115 static DiskRep *bestGuess(const std::string &path, size_t archOffset) { return bestGuess(path.c_str(), archOffset); } 116 static DiskRep *bestFileGuess(const std::string &path, const Context *ctx = NULL) { return bestFileGuess(path.c_str(), ctx); } 117 118public: 119 // see DiskRep::Writer docs for why this is here 120 class SigningContext { 121 protected: 122 SigningContext() { } 123 124 public: 125 virtual std::string sdkPath(const std::string &path) const = 0; 126 virtual bool isAdhoc() const = 0; 127 virtual SecCSFlags signingFlags() const = 0; 128 }; 129 130protected: 131 // canonically derive a suggested signing identifier from some string 132 static std::string canonicalIdentifier(const std::string &name); 133 134public: 135 static const size_t segmentedPageSize = 4096; // default page size for system-paged signatures 136 static const size_t monolithicPageSize = 0; // default page size for non-Mach-O executables 137}; 138 139 140// 141// Write-access objects. 142// At this layer they are quite abstract, carrying just the functionality needed 143// for the signing machinery to place data wherever it should go. Each DiskRep subclass 144// that supports writing signing data to a place inside the code needs to implement 145// a subclass of Writer and return an instance in the DiskRep::writer() method when asked. 146// 147// The Writer class is subclassed interestingly by the Mach-O multi-architecture signing code, 148// which is handled as a special case. This means that not all Writer subclass objects were made 149// by DiskRep::writer, and it is unwise to assume so. 150// 151// Note that the methods that provide defaults for signing operations are in DiskRep rather 152// than here. That's because writers abstract data *sending*, and are virtual on management 153// of stored data, while DiskRep is virtual on the existing code object, which is where 154// we get our defaults from. 155// 156class DiskRep::Writer : public RefCount { 157public: 158 Writer(uint32_t attrs = 0); 159 virtual ~Writer(); 160 virtual void component(CodeDirectory::SpecialSlot slot, CFDataRef data) = 0; 161 virtual uint32_t attributes() const; 162 virtual void addDiscretionary(CodeDirectory::Builder &builder); 163 virtual void remove(); 164 virtual void flush(); 165 166 bool attribute(uint32_t attr) const { return mAttributes & attr; } 167 168 void signature(CFDataRef data) { component(cdSignatureSlot, data); } 169 void codeDirectory(const CodeDirectory *cd) 170 { component(cdCodeDirectorySlot, CFTempData(cd->data(), cd->length())); } 171 172private: 173 Architecture mArch; 174 uint32_t mAttributes; 175}; 176 177// 178// Writer attributes. Defaults should be off-bits. 179// 180enum { 181 writerLastResort = 0x0001, // prefers not to store attributes itself 182 writerNoGlobal = 0x0002, // has only per-architecture storage 183}; 184 185 186// 187// A prefix DiskRep that filters (only) signature-dependent behavior and passes 188// all code-dependent behavior off to an underlying (different) DiskRep. 189// FilterRep subclasses are typically "stacked" on top of their base DiskRep, and 190// then used in their place. 191// 192class FilterRep : public DiskRep { 193public: 194 FilterRep(DiskRep *orig) : mOriginal(orig) { } 195 196 DiskRep *base() { return mOriginal; } 197 198 // things that look at signature components are filtered 199 CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; 200 201 // the rest of the virtual behavior devolves on the original DiskRep 202 CFDataRef identification() { return mOriginal->identification(); } 203 std::string mainExecutablePath() { return mOriginal->mainExecutablePath(); } 204 CFURLRef copyCanonicalPath() { return mOriginal->copyCanonicalPath(); } 205 std::string resourcesRootPath() { return mOriginal->resourcesRootPath(); } 206 void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); } 207 Universal *mainExecutableImage() { return mOriginal->mainExecutableImage(); } 208 size_t signingBase() { return mOriginal->signingBase(); } 209 size_t signingLimit() { return mOriginal->signingLimit(); } 210 std::string format() { return mOriginal->format(); } 211 CFArrayRef modifiedFiles() { return mOriginal->modifiedFiles(); } 212 UnixPlusPlus::FileDesc &fd() { return mOriginal->fd(); } 213 void flush() { return mOriginal->flush(); } 214 215 std::string recommendedIdentifier(const SigningContext &ctx) 216 { return mOriginal->recommendedIdentifier(ctx); } 217 CFDictionaryRef defaultResourceRules(const SigningContext &ctx) 218 { return mOriginal->defaultResourceRules(ctx); } 219 220private: 221 RefPointer<DiskRep> mOriginal; // underlying representation 222}; 223 224 225} // end namespace CodeSigning 226} // end namespace Security 227 228#endif // !_H_DISKREP 229