#include "cs.h"
#include "codedirectory.h"
+#include "cdbuilder.h"
#include "requirement.h"
#include "resources.h"
-#include "macho++.h" // for class Architecture
+#include <security_utilities/macho++.h> // for class Architecture
#include <security_utilities/refcount.h>
#include <security_utilities/superblob.h>
#include <CoreFoundation/CFData.h>
// the details of the storage locations or formats.
//
class DiskRep : public RefCount {
+public:
+ class SigningContext;
+
public:
DiskRep();
virtual ~DiskRep();
virtual DiskRep *base();
virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component
+ virtual CFDataRef identification() = 0; // binary lookup identifier
virtual std::string mainExecutablePath() = 0; // path to main executable
virtual CFURLRef canonicalPath() = 0; // path to whole code
- virtual std::string recommendedIdentifier() = 0; // default identifier
- virtual std::string resourcesRootPath(); // resource directory if any
- virtual CFDictionaryRef defaultResourceRules(); // default resource rules
- virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set
- virtual const Requirements *defaultRequirements(const Architecture *arch); // default internal requirements
- virtual Universal *mainExecutableImage(); // binary if Mach-O/Universal
- virtual size_t pageSize(); // default main executable page size
- virtual size_t signingBase(); // start offset of signed area in main executable
+ virtual std::string resourcesRootPath(); // resource directory if any [none]
+ virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set [no change]
+ virtual Universal *mainExecutableImage(); // Mach-O image if Mach-O based [null]
+ virtual size_t signingBase(); // start offset of signed area in main executable [zero]
virtual size_t signingLimit() = 0; // size of signed area in main executable
virtual std::string format() = 0; // human-readable type string
- virtual CFArrayRef modifiedFiles(); // list of files modified by signing
- virtual UnixPlusPlus::FileDesc &fd() = 0; // a cached fd for main executable file
+ virtual CFArrayRef modifiedFiles(); // list of files modified by signing [main execcutable only]
+ virtual UnixPlusPlus::FileDesc &fd() = 0; // a cached file descriptor for main executable file
virtual void flush(); // flush caches (refetch as needed)
+
+ // default values for signing operations
+ virtual std::string recommendedIdentifier(const SigningContext &ctx) = 0; // default identifier
+ virtual CFDictionaryRef defaultResourceRules(const SigningContext &ctx); // default resource rules [none]
+ virtual const Requirements *defaultRequirements(const Architecture *arch,
+ const SigningContext &ctx); // default internal requirements [none]
+ virtual size_t pageSize(const SigningContext &ctx); // default main executable page size [infinite, i.e. no paging]
bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; }
public:
class Writer;
- virtual Writer *writer();
+ virtual Writer *writer(); // Writer factory
public:
- static DiskRep *bestGuess(const char *path); // canonical heuristic, any path
- static DiskRep *bestFileGuess(const char *path); // canonical heuristic, single file only
-
- static DiskRep *bestGuess(const std::string &path) { return bestGuess(path.c_str()); }
- static DiskRep *bestFileGuess(const std::string &path) { return bestFileGuess(path.c_str()); }
-
+ // optional information that might be used to create a suitable DiskRep. All optional
+ struct Context {
+ Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL) { }
+ Architecture arch; // explicit architecture (choose amongst universal variants)
+ const char *version; // bundle version (string)
+ off_t offset; // explicit file offset
+ bool fileOnly; // only consider single-file representations (no bundles etc.)
+ const void *inMemory; // consider using in-memory copy at this address
+ };
+
+ static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path
+ static DiskRep *bestFileGuess(const char *path, const Context *ctx = NULL); // ctx (if any) + fileOnly
+ static DiskRep *bestGuess(const char *path, size_t archOffset); // Mach-O at given file offset only
+
+ // versions using std::string paths (merely a convenience)
+ static DiskRep *bestGuess(const std::string &path, const Context *ctx = NULL)
+ { return bestGuess(path.c_str(), ctx); }
+ static DiskRep *bestGuess(const std::string &path, size_t archOffset) { return bestGuess(path.c_str(), archOffset); }
+ static DiskRep *bestFileGuess(const std::string &path, const Context *ctx = NULL) { return bestFileGuess(path.c_str(), ctx); }
+
+public:
+ // see DiskRep::Writer docs for why this is here
+ class SigningContext {
+ protected:
+ SigningContext() { }
+
+ public:
+ virtual std::string sdkPath(const std::string &path) const = 0;
+ virtual bool isAdhoc() const = 0;
+ };
+
+protected:
+ // canonically derive a suggested signing identifier from some string
+ static std::string canonicalIdentifier(const std::string &name);
public:
static const size_t segmentedPageSize = 4096; // default page size for system-paged signatures
// that supports writing signing data to a place inside the code needs to implement
// a subclass of Writer and return an instance in the DiskRep::writer() method when asked.
//
+// The Writer class is subclassed interestingly by the Mach-O multi-architecture signing code,
+// which is handled as a special case. This means that not all Writer subclass objects were made
+// by DiskRep::writer, and it is unwise to assume so.
+//
+// Note that the methods that provide defaults for signing operations are in DiskRep rather
+// than here. That's because writers abstract data *sending*, and are virtual on management
+// of stored data, while DiskRep is virtual on the existing code object, which is where
+// we get our defaults from.
+//
class DiskRep::Writer : public RefCount {
public:
Writer(uint32_t attrs = 0);
virtual ~Writer();
virtual void component(CodeDirectory::SpecialSlot slot, CFDataRef data) = 0;
virtual uint32_t attributes() const;
+ virtual void addDiscretionary(CodeDirectory::Builder &builder);
+ virtual void remove();
virtual void flush();
bool attribute(uint32_t attr) const { return mAttributes & attr; }
};
+//
+// A prefix DiskRep that filters (only) signature-dependent behavior and passes
+// all code-dependent behavior off to an underlying (different) DiskRep.
+// FilterRep subclasses are typically "stacked" on top of their base DiskRep, and
+// then used in their place.
+//
+class FilterRep : public DiskRep {
+public:
+ FilterRep(DiskRep *orig) : mOriginal(orig) { }
+
+ DiskRep *base() { return mOriginal; }
+
+ // things that look at signature components are filtered
+ CFDataRef component(CodeDirectory::SpecialSlot slot) = 0;
+
+ // the rest of the virtual behavior devolves on the original DiskRep
+ CFDataRef identification() { return mOriginal->identification(); }
+ std::string mainExecutablePath() { return mOriginal->mainExecutablePath(); }
+ CFURLRef canonicalPath() { return mOriginal->canonicalPath(); }
+ std::string resourcesRootPath() { return mOriginal->resourcesRootPath(); }
+ void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); }
+ Universal *mainExecutableImage() { return mOriginal->mainExecutableImage(); }
+ size_t signingBase() { return mOriginal->signingBase(); }
+ size_t signingLimit() { return mOriginal->signingLimit(); }
+ std::string format() { return mOriginal->format(); }
+ CFArrayRef modifiedFiles() { return mOriginal->modifiedFiles(); }
+ UnixPlusPlus::FileDesc &fd() { return mOriginal->fd(); }
+ void flush() { return mOriginal->flush(); }
+
+ std::string recommendedIdentifier(const SigningContext &ctx)
+ { return mOriginal->recommendedIdentifier(ctx); }
+ CFDictionaryRef defaultResourceRules(const SigningContext &ctx)
+ { return mOriginal->defaultResourceRules(ctx); }
+
+private:
+ RefPointer<DiskRep> mOriginal; // underlying representation
+};
+
+
} // end namespace CodeSigning
} // end namespace Security