+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict/>
-</plist>
errSecCSGuestInvalid, /* code identity has been invalidated */
errSecCSUnsigned, /* code object is not signed */
errSecCSSignatureFailed, /* code or signature modified */
- errSecCSSignatureNotVerifiable, /* signature cannot be read, e.g., due to a filesystem that maps root to an unprivileged user */
+ errSecCSSignatureNotVerifiable, /* signature cannot be read, e.g., due to a filesystem that maps root to an unprivileged user */
errSecCSSignatureUnsupported, /* unsupported type or version of signature */
errSecCSBadDictionaryFormat, /* a required plist file or resource is malformed */
errSecCSResourcesNotSealed, /* resources are not sealed by signature */
errSecCSInvalidOperation, /* requested operation is not valid */
errSecCSNotSupported, /* operation not supported for this type of code */
errSecCSCMSTooLarge, /* signature too large to embed */
- errSecCSHostProtocolInvalidHash, /* host protocol violation - invalid guest hash */
- errSecCSStaticCodeChanged, /* the program on disk does not match what is running */
- errSecCSSigDBDenied, /* access to signature database denied */
- errSecCSSigDBAccess, /* cannot access signature database */
- errSecCSHostProtocolInvalidAttribute, /* host returned invalid or inconsistent guest attributes */
};
An abstract handle to identify a particular Guest in the context of its Host.
Guest handles are assigned by the host at will, with kSecNoGuest (zero) being
- reserved as the null value. They can be reused for new children if desired.
+ reserved as the null value). They can be reused for new children if desired.
*/
typedef u_int32_t SecGuestRef;
/*!
- @typedef SecCSFlags
+ @typddef SecCSFlags
This is the type of flags arguments to Code Signing API calls.
It provides a bit mask of request and option flags. All of the bits in these
masks are reserved to Apple; if you set any bits not defined in these headers,
guarantees that the code will always be valid, since it will die immediately
if it becomes invalid.
@constant kSecCodeSignatureForceExpiration
- Forces the kSecCSConsiderExpiration flag on all validations of the code.
+ Forces the kSecCSConsiderExpiration on all validations of the code.
*/
typedef uint32_t SecCodeSignatureFlags;
};
-/*!
- @typedef SecCodeStatus
- The code signing system attaches a set of operational flags to each running code.
- These flags are maintained by the code's host, and can be read by anyone.
- A code may change its own flags, and root may change anyone's flags.
- However, these flags are sticky in that each can change in only one direction
- (and never back, for the lifetime of the code). Not even root can violate this restriction.
-
- There are other flags in SecCodeStatus that are not publicly documented.
- Do not rely on them.
-
- @constant kSecCodeStatusValid
- Indicates that the code is dynamically valid, i.e. it started properly signed
- and has not been invalidated since it started. The valid bit can only be cleared.
- Note that this bit does not make any representations on the static validity of the code.
- @constant kSecCodeStatusHard
- Indicates that the code prefers to be denied access to resources if gaining access
- would invalidate it. This bit can only be set.
- It is undefined whether a code that is marked hard and is already invalid will still
- be denied access to a resource that would invalidate it if it were still valid. That is,
- the code may or may not get access to such a resource while being invalid, and that choice
- may seem random.
- @constant kSecCodeStatusKill
- Indicates that the code wants to be killed (terminated) if it ever loses its validity.
- This bit can only be set. Code that has the kill flag set will never be invalid (and live).
-*/
-typedef uint32_t SecCodeStatus;
-enum {
- kSecCodeStatusValid = 0x0001,
- kSecCodeStatusHard = 0x0100,
- kSecCodeStatusKill = 0x0200,
-};
-
-
/*!
@typedef SecRequirementType
An enumeration indicating different types of internal requirements for code.
- */
+*/
typedef uint32_t SecRequirementType;
enum {
+++ /dev/null
-/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*!
- @header CSCommonPriv
- SecStaticCodePriv is the private counter-part to CSCommon. Its contents are not
- official API, and are subject to change without notice.
-*/
-#ifndef _H_CSCOMMONPRIV
-#define _H_CSCOMMONPRIV
-
-#include <Security/CSCommon.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*!
- @typedef SecCodeDirectoryFlagTable
- This constant array can be used to translate between names and values
- of CodeDirectory flag bits. The table ends with an entry with NULL name.
- The elements are in no particular order.
- @field name The official text name of the flag.
- @field value The binary value of the flag.
- @field signable True if the flag can be specified during signing. False if it is set
- internally and can only be read from a signature.
- */
-typedef struct {
- const char *name;
- uint32_t value;
- bool signable;
-} SecCodeDirectoryFlagTable;
-
-extern const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[];
-
-
-/*!
- Blob types (magic numbers) for blobs used by Code Signing.
-
- @constant kSecCodeMagicRequirement Magic number for individual code requirements.
- @constant kSecCodeMagicRequirementSet Magic number for a collection of
- individual code requirements, indexed by requirement type. This is used
- for internal requirement sets.
- @constant kSecCodeMagicCodeDirectory Magic number for a CodeDirectory.
- @constant kSecCodeMagicEmbeddedSignature Magic number for a SuperBlob
- containing all the signing components that are usually embedded within
- a main executable.
- @constant kSecCodeMagicDetachedSignature Magic number for a SuperBlob that
- contains all the data for all architectures of a signature, including any
- data that is usually written to separate files. This is the format of
- detached signatures if the program is capable of having multiple architectures.
- @constant kSecCodeMagicEntitlement Magic number for a standard entitlement blob.
- @constant kSecCodeMagicByte The first byte (in NBO) shared by all these magic
- numbers. This is not a valid ASCII character; test for this to distinguish
- between text and binary data if you expect a code signing-related binary blob.
- */
-typedef uint32_t SecCodeSignatureFlags;
-
-enum {
- kSecCodeMagicRequirement = 0xfade0c00, /* single requirement */
- kSecCodeMagicRequirementSet = 0xfade0c01, /* requirement set */
- kSecCodeMagicCodeDirectory = 0xfade0c02, /* CodeDirectory */
- kSecCodeMagicEmbeddedSignature = 0xfade0cc0, /* single-architecture embedded signature */
- kSecCodeMagicDetachedSignature = 0xfade0cc1, /* detached multi-architecture signature */
- kSecCodeMagicEntitlement = 0xfade7171, /* entitlement blob */
-
- kSecCodeMagicByte = 0xfa /* shared first byte */
-};
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //_H_CSCOMMON
#include "StaticCode.h"
#include <Security/SecCodeHost.h>
#include "cskernel.h"
-#include <security_utilities/cfmunge.h>
+#include "cfmunge.h"
#include <security_utilities/debugging.h>
+#include <sys/codesign.h>
namespace Security {
namespace CodeSigning {
// Construction
//
SecCode::SecCode(SecCode *host)
- : mHost(host), mIdentified(false)
+ : mHost(host)
{
- CODESIGN_DYNAMIC_CREATE(this, host);
}
}
-//
-// CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
-// and falls back on comparing canonical paths if (both are) not.
-//
-bool SecCode::equal(SecCFObject &secOther)
-{
- SecCode *other = static_cast<SecCode *>(&secOther);
- CFDataRef mine = this->cdHash();
- CFDataRef his = other->cdHash();
- if (mine || his)
- return mine && his && CFEqual(mine, his);
- else
- return this->staticCode()->equal(*other->staticCode());
-}
-
-CFHashCode SecCode::hash()
-{
- if (CFDataRef h = this->cdHash())
- return CFHash(h);
- else
- return this->staticCode()->hash();
-}
-
-
//
// Yield the host Code
//
//
SecStaticCode *SecCode::staticCode()
{
- if (!mIdentified) {
- this->identify();
- mIdentified = true;
+ if (!mStaticCode) {
+ mStaticCode.take(this->getStaticCode());
+ secdebug("seccode", "%p got static=%p", this, mStaticCode.get());
}
assert(mStaticCode);
return mStaticCode;
}
-//
-// Yield the CodeDirectory hash as presented by our host.
-// This usually is the same as the hash of staticCode().codeDirectory(), but might not
-// if files are changing on disk while code is running.
-//
-CFDataRef SecCode::cdHash()
-{
- if (!mIdentified) {
- this->identify();
- mIdentified = true;
- }
- return mCDHash; // can be NULL (host has no dynamic identity for guest)
-}
-
-
-//
-// Retrieve current dynamic status.
-//
-SecCodeStatus SecCode::status()
-{
- if (this->isRoot())
- return kSecCodeStatusValid; // root of trust, presumed valid
- else
- return this->host()->getGuestStatus(this);
-}
-
-void SecCode::status(SecCodeStatusOperation operation, CFDictionaryRef arguments)
-{
- if (this->isRoot())
- MacOSError::throwMe(errSecCSHostProtocolStateError);
- else
- this->host()->changeGuestStatus(this, operation, arguments);
-}
-
-
//
// By default, we have no guests
//
//
-// By default, we self-identify by asking our host to identify us.
+// By default, we map ourselves to disk using our host's mapping facility.
// (This is currently only overridden in the root-of-trust (kernel) implementation.)
+// The caller owns the object returned.
//
-void SecCode::identify()
+SecStaticCode *SecCode::getStaticCode()
{
- mStaticCode.take(host()->identifyGuest(this, &mCDHash.aref()));
+ return host()->mapGuestToStatic(this);
}
//
// The default implementation cannot map guests to disk
//
-SecStaticCode *SecCode::identifyGuest(SecCode *, CFDataRef *)
+SecStaticCode *SecCode::mapGuestToStatic(SecCode *guest)
{
MacOSError::throwMe(errSecCSNoSuchCode);
}
// This function validates internal requirements in the hosting chain. It does
// not validate external requirements - the caller needs to do that with a separate call.
//
+static const uint8_t interim_hosting_default_requirement[] = {
+ // anchor apple and (identifier com.apple.translate or identifier com.apple.LaunchCFMApp)
+ 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13,
+ 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c,
+ 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x63, 0x6f, 0x6d, 0x2e,
+ 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x43, 0x46, 0x4d, 0x41,
+ 0x70, 0x70, 0x00, 0x00,
+};
+
void SecCode::checkValidity(SecCSFlags flags)
{
if (this->isRoot()) {
// the root-of-trust is valid by definition
- CODESIGN_EVAL_DYNAMIC_ROOT();
+ secdebug("validator", "%p root of trust is presumed valid", this);
return;
}
- DTRACK(CODESIGN_EVAL_DYNAMIC, this, (char*)this->staticCode()->mainExecutablePath().c_str());
+ secdebug("validator", "%p begin validating %s",
+ this, this->staticCode()->mainExecutablePath().c_str());
//
// Do not reorder the operations below without thorough cogitation. There are
- // interesting dependencies and significant performance issues. There is also
- // client code that relies on errors being noticed in a particular order.
+ // interesting dependencies and significant performance issues.
//
- // For the most part, failure of (reliable) identity will cause exceptions to be
+ // For the most part, failure of (secure) identity will cause exceptions to be
// thrown, and success is indicated by survival. If you make it to the end,
// you have won the validity race. (Good rat.)
//
myDisk->validateDirectory();
// check my own dynamic state
- if (!(this->host()->getGuestStatus(this) & kSecCodeStatusValid))
+ if (!(this->host()->getGuestStatus(this) & CS_VALID))
MacOSError::throwMe(errSecCSGuestInvalid);
-
- // check that static and dynamic views are consistent
- if (this->cdHash() && !CFEqual(this->cdHash(), myDisk->cdHash()))
- MacOSError::throwMe(errSecCSStaticCodeChanged);
// check host/guest constraints
if (!this->host()->isRoot()) { // not hosted by root of trust
myDisk->validateRequirements(kSecHostRequirementType, hostDisk, errSecCSHostReject);
hostDisk->validateRequirements(kSecGuestRequirementType, myDisk);
}
+
+ secdebug("validator", "%p validation successful", this);
}
MacOSError::throwMe(errSecCSNoSuchCode);
}
-void SecCode::changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
-{
- MacOSError::throwMe(errSecCSNoSuchCode);
-}
-
//
// Given a bag of attribute values, automagically come up with a SecCode
//
SecCode *SecCode::autoLocateGuest(CFDictionaryRef attributes, SecCSFlags flags)
{
- // special case: with no attributes at all, return the root of trust
- if (CFDictionaryGetCount(attributes) == 0)
- return KernelCode::active()->retain();
-
// main logic: we need a pid, and we'll take a canonical guest id as an option
int pid = 0;
if (!cfscan(attributes, "{%O=%d}", kSecGuestAttributePid, &pid))
code.take(process); // locateGuest gave us a retained object
if (code->staticCode()->flag(kSecCodeSignatureHost)) {
// might be a code host. Let's find out
- CFRef<CFMutableDictionaryRef> rest = makeCFMutableDictionary(attributes);
+ CFRef<CFMutableDictionaryRef> rest = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
CFDictionaryRemoveValue(rest, kSecGuestAttributePid);
if (SecCode *guest = code->locateGuest(rest))
return guest;
//
class SecCode : public SecCFObject {
NOCOPY(SecCode)
- friend class KernelCode; // overrides identify() to set mStaticCode/mCDHash
public:
SECCFFUNCTIONS(SecCode, SecCodeRef, errSecCSInvalidObjectRef, gCFObjects().Code)
SecCode(SecCode *host);
virtual ~SecCode() throw();
- bool equal(SecCFObject &other);
- CFHashCode hash();
-
SecCode *host() const;
bool isRoot() const { return host() == NULL; }
SecStaticCode *staticCode(); // cached. Result lives as long as this SecCode
- CFDataRef cdHash();
-
- SecCodeStatus status(); // dynamic status
- void status(SecCodeStatusOperation operation, CFDictionaryRef arguments);
// primary virtual drivers. Caller owns the result
- virtual void identify();
+ virtual SecStaticCode *getStaticCode();
virtual SecCode *locateGuest(CFDictionaryRef attributes);
- virtual SecStaticCode *identifyGuest(SecCode *guest, CFDataRef *cdhash);
+ virtual SecStaticCode *mapGuestToStatic(SecCode *guest);
void checkValidity(SecCSFlags flags);
- virtual SecCodeStatus getGuestStatus(SecCode *guest);
- virtual void changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments);
+ virtual uint32_t getGuestStatus(SecCode *guest);
public:
// perform "autolocation" (root-based heuristic). Caller owns the result
private:
SecPointer<SecCode> mHost;
- bool mIdentified; // called identify(), mStaticCode & mCDHash are valid
- SecPointer<SecStaticCode> mStaticCode; // (static) code origin
- CFRef<CFDataRef> mCDHash; // (dynamic) CodeDirectory hash as per host
+ SecPointer<SecStaticCode> mStaticCode;
};
#include "signer.h"
#include "reqparser.h"
#include "renum.h"
-#include "csdatabase.h"
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
#include <vector>
//
// Construct a SecCodeSigner
//
-SecCodeSigner::SecCodeSigner(SecCSFlags flags)
- : mOpFlags(flags), mRequirements(NULL)
+SecCodeSigner::SecCodeSigner()
+ : mRequirements(NULL)
{
+ secdebug("signer", "%p created", this);
}
//
SecCodeSigner::~SecCodeSigner() throw()
{
+ secdebug("signer", "%p destroyed", this);
::free((Requirements *)mRequirements);
}
//
void SecCodeSigner::parameters(CFDictionaryRef paramDict)
{
+ secdebug("signer", "%p loading %d parameters", this, int(CFDictionaryGetCount(paramDict)));
Parser(*this, paramDict);
if (!valid())
MacOSError::throwMe(errSecCSInvalidObjectRef);
}
-//
-// Roughly check for validity.
-// This isn't thorough; it just sees if if looks like we've set up the object appropriately.
-//
-bool SecCodeSigner::valid() const
-{
- if (mOpFlags & kSecCSRemoveSignature)
- return true;
- return mSigner;
-}
-
-
//
// Sign code
//
void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
{
- Signer operation(*this, code);
- if ((flags | mOpFlags) & kSecCSRemoveSignature) {
- secdebug("signer", "%p will remove signature from %p", this, code);
- operation.remove(flags);
- } else {
- if (!valid())
- MacOSError::throwMe(errSecCSInvalidObjectRef);
- secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
- operation.sign(flags);
- }
+ if (!valid())
+ MacOSError::throwMe(errSecCSInvalidObjectRef);
+ secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
+ Signer(*this, code).sign(flags);
code->resetValidity();
}
// ReturnDetachedSignature is called by writers or editors that try to return
// detached signature data (rather than annotate the target).
//
-void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
+void SecCodeSigner::returnDetachedSignature(BlobCore *blob)
{
assert(mDetached);
if (CFGetTypeID(mDetached) == CFURLGetTypeID()) {
} else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) {
CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
(const UInt8 *)blob, blob->length());
- } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
- signatureDatabase().storeCode(blob, signer.path().c_str());
} else
assert(false);
}
state.mSigner = SecIdentityRef(signer);
else
MacOSError::throwMe(errSecCSInvalidObjectRef);
+ else
+ MacOSError::throwMe(errSecCSInvalidObjectRef);
// the flags need some augmentation
if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) {
// detached can be (destination) file URL or (mutable) Data to be appended-to
if (state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached)) {
- CFTypeID type = CFGetTypeID(state.mDetached);
- if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
+ if (CFGetTypeID(state.mDetached) != CFURLGetTypeID()
+ && CFGetTypeID(state.mDetached) != CFDataGetTypeID())
MacOSError::throwMe(errSecCSInvalidObjectRef);
}
//
class SecCodeSigner : public SecCFObject {
NOCOPY(SecCodeSigner)
-public:
- class Parser;
- class Signer;
-
public:
SECCFFUNCTIONS(SecCodeSigner, SecCodeSignerRef, errSecCSInvalidObjectRef, gCFObjects().CodeSigner)
- SecCodeSigner(SecCSFlags flags);
+ SecCodeSigner();
virtual ~SecCodeSigner() throw();
void parameters(CFDictionaryRef args); // parse and set parameters
- bool valid() const;
+ bool valid() const { return mSigner; }
void sign(SecStaticCode *code, SecCSFlags flags);
- void remove(SecStaticCode *code, SecCSFlags flags);
- void returnDetachedSignature(BlobCore *blob, Signer &signer);
+ void returnDetachedSignature(BlobCore *blob);
+
+public:
+ class Parser;
+ class Signer;
private:
// parsed parameter set
- SecCSFlags mOpFlags; // operation flags
CFRef<SecIdentityRef> mSigner; // signing identity
CFRef<CFTypeRef> mDetached; // detached-signing information (NULL => attached)
CFRef<CFDictionaryRef> mResourceRules; // explicit resource collection rules (override)
#include "cs.h"
#include "Code.h"
#include "cskernel.h"
-#include <security_utilities/cfmunge.h>
+#include <security_codesigning/cfmunge.h>
+#include <sys/codesign.h>
using namespace CodeSigning;
//
-// Get a reference to the calling code.
-//
-OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
-{
- BEGIN_CSAPI
-
- checkFlags(flags);
- CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
- kSecGuestAttributePid, CFTempNumber(getpid()).get());
- Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
-
- END_CSAPI
-}
-
-
-//
-// Get the dynamic status of a code.
+// Get the root of trust Code
//
-OSStatus SecCodeGetStatus(SecCodeRef codeRef, SecCSFlags flags, SecCodeStatus *status)
+SecCodeRef SecGetRootCode(SecCSFlags flags)
{
BEGIN_CSAPI
checkFlags(flags);
- Required(status) = SecCode::required(codeRef)->status();
+ return KernelCode::active()->handle();
- END_CSAPI
+ END_CSAPI1(NULL)
}
//
-// Change the dynamic status of a code
+// Get a reference to the calling code.
//
-OSStatus SecCodeSetStatus(SecCodeRef codeRef, SecCodeStatusOperation operation,
- CFDictionaryRef arguments, SecCSFlags flags)
+OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
{
BEGIN_CSAPI
checkFlags(flags);
- SecCode::required(codeRef)->status(operation, arguments);
+ CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
+ kSecGuestAttributePid, CFTempNumber(getpid()).get());
+ Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
END_CSAPI
}
//
// Find a guest by attribute(s)
//
+const CFStringRef kSecGuestAttributePid = CFSTR("pid");
const CFStringRef kSecGuestAttributeCanonical = CFSTR("canonical");
-const CFStringRef kSecGuestAttributeHash = CFSTR("codedirectory-hash");
const CFStringRef kSecGuestAttributeMachPort = CFSTR("mach-port");
-const CFStringRef kSecGuestAttributePid = CFSTR("pid");
-const CFStringRef kSecGuestAttributeArchitecture = CFSTR("architecture");
-const CFStringRef kSecGuestAttributeSubarchitecture = CFSTR("subarchitecture");
OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef hostRef,
CFDictionaryRef attributes, SecCSFlags flags, SecCodeRef *guestRef)
const CFStringRef kSecCodeInfoCMS = CFSTR("cms");
const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement");
const CFStringRef kSecCodeInfoEntitlements = CFSTR("entitlements");
+const CFStringRef kSecCodeInfoTime = CFSTR("signing-time");
const CFStringRef kSecCodeInfoFormat = CFSTR("format");
const CFStringRef kSecCodeInfoIdentifier = CFSTR("identifier");
const CFStringRef kSecCodeInfoImplicitDesignatedRequirement = CFSTR("implicit-requirement");
const CFStringRef kSecCodeInfoPList = CFSTR("info-plist");
const CFStringRef kSecCodeInfoRequirements = CFSTR("requirements");
const CFStringRef kSecCodeInfoRequirementData = CFSTR("requirement-data");
-const CFStringRef kSecCodeInfoSource = CFSTR("source");
const CFStringRef kSecCodeInfoStatus = CFSTR("status");
-const CFStringRef kSecCodeInfoTime = CFSTR("signing-time");
const CFStringRef kSecCodeInfoTrust = CFSTR("trust");
-const CFStringRef kSecCodeInfoUnique = CFSTR("unique");
-
-const CFStringRef kSecCodeInfoCodeDirectory = CFSTR("CodeDirectory");
-const CFStringRef kSecCodeInfoCodeOffset = CFSTR("CodeOffset");
-const CFStringRef kSecCodeInfoResourceDirectory = CFSTR("ResourceDirectory");
-
OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flags,
CFDictionaryRef *infoRef)
CFRef<CFDictionaryRef> info = code->signingInformation(flags);
if (flags & kSecCSDynamicInformation)
- if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef))
+ if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef)) {
+ uint32_t status;
+ if (SecPointer<SecCode> host = dcode->host())
+ status = host->getGuestStatus(dcode);
+ else
+ status = CS_VALID; // root of trust, presumed valid
info = cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(),
- kSecCodeInfoStatus, dcode->status());
+ kSecCodeInfoStatus, status);
+ }
Required(infoRef) = info.yield();
#ifndef _H_SECCODE
#define _H_SECCODE
-#include <Security/CSCommon.h>
-
#ifdef __cplusplus
extern "C" {
#endif
+#include <Security/CSCommon.h>
+
/*!
@function SecCodeGetTypeID
CFTypeID SecCodeGetTypeID(void);
+/*!
+ @function SecGetRootCode
+ Obtains a SecCode object for the running code that hosts the entire system.
+ This object usually represents the system kernel. It is always considered
+ valid and is implicitly trusted by everyone.
+
+ This object has no host.
+
+ @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+
+ @result An object reference to the root Code. This call should never fail.
+ If this call returns NULL, Code Signing is unusable.
+*/
+SecCodeRef SecGetRootCode(SecCSFlags flags);
+
+
/*!
@function SecCodeCopySelf
Obtains a SecCode object for the code making the call.
is considered until revoked.
@param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param self Upon successful return, contains a SecCodeRef representing the caller.
@result Upon success, noErr. Upon error, an OSStatus value documented in
CSCommon.h or certain other Security framework headers.
*/
OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *self);
-
+
+
/*!
@function SecCodeCopyStaticCode
on the system that acts as a Code Signing host. As a special case, passing
NULL indicates that the Code Signing root of trust should be used as a starting
point. Currently, that is the system kernel.
- @param attributes A CFDictionary containing zero or more attribute selector
+ @param attributes A CFDictionary containing one or more attribute selector
values. Each selector has a CFString key and associated CFTypeRef value.
- The key name identifies the attribute being specified; the associated value,
+ The key name identifies the attribute being selected; the associated value,
whose type depends on the the key name, selects a particular value or other
constraint on that attribute. Each host only supports particular combinations
of keys and values, and errors will be returned if any unsupported set is requested.
As a special case, NULL is taken to mean an empty attribute set.
- Note that some hosts that support hosting chains (guests being hosts)
+ Also note that some hosts that support hosting chains (guests being hosts)
may return sub-guests in this call. In other words, do not assume that
- a SecCodeRef returned by this call is a direct guest of the queried host
+ a SecCodeRef returned by this call is an immediate guest of the queried host
(though it will be a proximate guest, i.e. a guest's guest some way down).
@param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
@param guest On successful return, a SecCode object reference identifying
- the particular guest of the host that owns the attribute value(s) specified.
+ the particular guest of the host that owns the attribute value specified.
This argument will not be changed if the call fails (does not return noErr).
@result Upon success, noErr. Upon error, an OSStatus value documented in
CSCommon.h or certain other Security framework headers. In particular:
@error errSecCSNoSuchCode The host has no guest with the attribute value given
by attributeValue, even though the value is of a supported type. This may also
be returned if the host code does not currently act as a Code Signing host.
- @error errSecCSNotAHost The specified host cannot, in fact, act as a code
+ @error errSecCSNotAHost The putative host cannot, in fact, act as a code
host. (It is missing the kSecCodeSignatureHost option flag in its code
signature.)
@error errSecCSMultipleGuests The attributes specified do not uniquely identify
a guest (the specification is ambiguous).
*/
+extern const CFStringRef kSecGuestAttributePid;
extern const CFStringRef kSecGuestAttributeCanonical;
-extern const CFStringRef kSecGuestAttributeHash;
extern const CFStringRef kSecGuestAttributeMachPort;
-extern const CFStringRef kSecGuestAttributePid;
-extern const CFStringRef kSecGuestAttributeArchitecture;
-extern const CFStringRef kSecGuestAttributeSubarchitecture;
OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef host,
CFDictionaryRef attributes, SecCSFlags flags, SecCodeRef *guest);
+/*!
+ @function SecCodeCreateWithPID
+ Asks the kernel to return a SecCode object for a process identified
+ by a UNIX process id (pid). This is a shorthand for asking SecGetRootCode()
+ for a guest whose "pid" attribute has the given pid value.
+
+ @param pid A process id for an existing UNIX process on the system.
+ @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+ @param process On successful return, a SecCode object reference identifying
+ the requesteed process.
+ @result Upon success, noErr. Upon error, an OSStatus value documented in
+ CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *process);
+
+
/*!
@function SecCodeCheckValidity
Performs dynamic validation of the given SecCode object. The call obtains and
@param requirement On successful return, contains a copy of a SecRequirement
object representing the code's Designated Requirement. On error, unchanged.
@result On success, noErr. On error, an OSStatus value
- documented in CSCommon.h or certain other Security framework headers.
+ documented in CSCommon.h or certain other Security framework headers.
*/
OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flags,
SecRequirementRef *requirement);
@param code The Code or StaticCode object to be interrogated. For a Code
argument, its StaticCode is processed as per SecCodeCopyStaticCode.
- Note that dynamic information (kSecCSDynamicInformation) cannot be obtained
- for a StaticCode argument.
@param flags Optional flags. Use any or all of the kSecCS*Information flags
to select what information to return. A generic set of entries is returned
regardless; you may specify kSecCSDefaultFlags for just those.
the flags passed. Regardless of flags, the kSecCodeInfoIdentifier key is
always present if the code is signed, and always absent if the code is
unsigned.
- Note that some of the objects returned are (retained) "live" API objects
- used by the code signing infrastructure. Making changes to these objects
- is unsupported and may cause subsequent code signing operations on the
- affected code to behave in undefined ways.
@result On success, noErr. On error, an OSStatus value
- documented in CSCommon.h or certain other Security framework headers.
-
- Flags:
+ documented in CSCommon.h or certain other Security framework headers.
@constant kSecCSSigningInformation Return cryptographic signing information,
including the certificate chain and CMS data (if any). For ad-hoc signed
contents making up the signed code on disk. It is not generally advisable to
make use of this information, but some utilities (such as software-update
tools) may find it useful.
-
- Dictionary keys:
-
- @constant kSecCodeInfoCertificates A CFArray of SecCertificates identifying the
- certificate chain of the signing certificate as seen by the system. Absent
- for ad-hoc signed code. May be partial or absent in error cases.
- @constant kSecCodeInfoChangedFiles A CFArray of CFURLs identifying all files in
- the code that may have been modified by the process of signing it. (In other
- words, files not in this list will not have been touched by the signing operation.)
- @constant kSecCodeInfoCMS A CFData containing the CMS cryptographic object that
- secures the code signature. Empty for ad-hoc signed code.
- @constant kSecCodeInfoDesignatedRequirement A SecRequirement describing the
- actual Designated Requirement of the code.
- @constant kSecCodeInfoEntitlements A CFData containing the embedded entitlement
- blob of the code, if any.
- @constant kSecCodeInfoFormat A CFString characterizing the type and format of
- the code. Suitable for display to a (knowledeable) user.
- @constant kSecCodeInfoIdentifier A CFString with the actual signing identifier
- sealed into the signature. Absent for unsigned code.
- @constant kSecCodeInfoImplicitDesignatedRequirement A SecRequirement describing
- the designated requirement that the system did generate, or would have generated,
- for the code. If the Designated Requirement was implicitly generated, this is
- the same object as kSecCodeInfoDesignatedRequirement; this can be used to test
- for an explicit Designated Requirement.
- @constant kSecCodeInfoMainExecutable A CFURL identifying the main executable file
- of the code. For single files, that is the file itself. For bundles, it is the
- main executable as identified by its Info.plist.
- @constant kSecCodeInfoPList A retained CFDictionary referring to the secured Info.plist
- as seen by code signing. Absent if no Info.plist is known to the code signing
- subsystem. Note that this is not the same dictionary as the one CFBundle would
- give you (CFBundle is free to add entries to the on-disk plist).
- @constant kSecCodeInfoRequirements A CFString describing the internal requirements
- of the code in canonical syntax.
- @constant kSecCodeInfoRequirementsData A CFData containing the internal requirements
- of the code as a binary blob.
- @constant kSecCodeInfoSource A CFString describing the source of the code signature
- used for the code object. The values are meant to be shown in informational
- displays; do not rely on the precise value returned.
- @constant kSecCodeInfoStatus A CFNumber containing the dynamic status word of the
- (running) code. This is a snapshot at the time the API is executed and may be
- out of date by the time you examine it. Do note however that most of the bits
- are sticky and thus some values are permanently reliable. Be careful.
- @constant kSecCodeInfoTime A CFDate describing the signing date (securely) embedded
- in the code signature. Note that a signer is able to omit this date or pre-date
- it. Nobody certifies that this was really the date the code was signed; however,
- you do know that this is the date the signer wanted you to see.
- Ad-hoc signatures have no CMS and thus never have secured signing dates.
- @constant kSecCodeInfoTrust The (retained) SecTrust object the system uses to
- evaluate the validity of the code's signature. You may use the SecTrust API
- to extract detailed information, particularly for reasons why certificate
- validation may have failed. This object may continue to be used for further
- evaluations of this code; if you make any changes to it, behavior is undefined.
- @constant kSecCodeInfoUnique A CFData binary identifier that uniquely identifies
- the static code in question. It can be used to recognize this particular code
- (and none other) now or in the future. Compare to kSecCodeInfoIdentifier, which
- remains stable across (developer-approved) updates.
- This is currently the SHA-1 hash of the code's CodeDirectory. However, future
- versions of the system may use a different algorithm for newly signed code.
- Already-signed code not change the reported value in this case.
*/
enum {
kSecCSInternalInformation = 1 << 0,
extern const CFStringRef kSecCodeInfoCertificates; /* Signing */
extern const CFStringRef kSecCodeInfoChangedFiles; /* Content */
extern const CFStringRef kSecCodeInfoCMS; /* Signing */
+extern const CFStringRef kSecCodeInfoTime; /* Signing */
extern const CFStringRef kSecCodeInfoDesignatedRequirement; /* Requirement */
extern const CFStringRef kSecCodeInfoEntitlements; /* Requirement */
extern const CFStringRef kSecCodeInfoFormat; /* generic */
extern const CFStringRef kSecCodeInfoPList; /* generic */
extern const CFStringRef kSecCodeInfoRequirements; /* Requirement */
extern const CFStringRef kSecCodeInfoRequirementData; /* Requirement */
-extern const CFStringRef kSecCodeInfoSource; /* generic */
extern const CFStringRef kSecCodeInfoStatus; /* Dynamic */
-extern const CFStringRef kSecCodeInfoTime; /* Signing */
extern const CFStringRef kSecCodeInfoTrust; /* Signing */
-extern const CFStringRef kSecCodeInfoUnique; /* generic */
OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags,
CFDictionaryRef *information);
+/*
+ @function SecCodeSetDetachedSignature
+ For a given Code or StaticCode object, explicitly specify the detached signature
+ data used to verify it.
+ This call unconditionally overrides any signature embedded in the Code and any
+ previously specified detached signature; only the signature data specified here
+ will be used from now on for this Code object. If NULL data is specified, this
+ call reverts to using any embedded signature.
+ Any call to this function voids all cached validations for the Code object.
+ Validations will be performed again as needed in the future. This call does not,
+ by itself, perform or trigger any validations.
+ Please note that it is possible to have multiple Code objects for the same static
+ or dynamic code entity in the system. This function only attaches signature data
+ to the particular SecStaticCodeRef involved. It is your responsibility to understand
+ the object graph and pick the right one(s).
+
+ @param code A Code or StaticCode object whose signature information is to be changed.
+ @param signature A CFDataRef containing the signature data to be used for validating
+ the given Code. This must be exactly the data previously generated as a detached
+ signature by the SecCodeSignerAddSignature API or the codesign(1) command with
+ the -D/--detached option.
+ If signature is NULL, discards any previously set signature data and reverts
+ to using the embedded signature, if any. If not NULL, the data is retained and used
+ for future validation operations.
+ @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+ */
+OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef code, CFDataRef signature,
+ SecCSFlags flags);
+
+
/*
@function SecCodeMapMemory
For a given Code or StaticCode object, ask the kernel to accept the signing information
{
BEGIN_CSAPI
- checkFlags(flags, kSecCSDedicatedHost | kSecCSGenerateGuestHash);
+ checkFlags(flags, kSecCSDedicatedHost);
Required(newGuest) = SecurityServer::ClientSession().createGuest(host,
- status, cfString(path).c_str(), CssmData(), DictData(attributes), flags);
+ status, cfString(path).c_str(), DictData(attributes), flags);
END_CSAPI
}
#define _H_SECCODEHOST
#include <Security/CSCommon.h>
+#include <System/sys/codesign.h>
#ifdef __cplusplus
extern "C" {
of the guest to act as the new guest's host. If host has a dedicated guest,
it will be deemed to be be the actual host, recursively.
@param status The Code Signing status word for the new guest. These are combinations
- of the kSecCodeStatus* flags in <Security/CSCommon.h>. Note that the proxy will enforce
- the rules for the stickiness of these bits. In particular, if you don't pass the
- kSecCodeStatusValid bit during creation, your new guest will be born invalid and will
- never have a valid identity.
+ of the CS_* flags in <sys/codesign.h>. Note that the proxy will enforce the rules for
+ the stickiness of these bits. In particular, if you don't pass the CS_VALID bit during
+ creation, your new guest will be born invalid and will never have a valid identity.
@param path The canonical path to the guest's code on disk. This is the path you would
pass to SecStaticCodeCreateWithPath to make a static code object reference. You must
use an absolute path.
to locate this particular guest among all of the caller's guests. The "canonical"
attribute is automatically added for the value of guestRef. If you pass NULL,
no other attributes are established for the guest.
- While any key can be used in the attributes dictionary, the kSecGuestAttribute* constants
- (in SecCode.h) are conventionally used here.
@param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior, or
a combination of the flags defined below for special features.
@result Upon success, noErr. Upon error, an OSStatus value documented in
It is invalid to declare dedicated hosting if other guests have already been
introduced for this host, and it is invalid to introduce additional guests
for this host after this call.
- @constant kSecCSGenerateGuestHash Ask the proxy to generate the binary identifier
- (hash of CodeDirectory) from the copy on disk at the path given. This is not optimal
- since an attacker with write access may be able to substitute a different copy just
- in time, but it is convenient. For optimal security, the host should calculate the
- hash from the loaded in-memory signature of its guest and pass the result as an
- attribute with key kSecGuestAttributeHash.
*/
enum {
kSecCSDedicatedHost = 1 << 0,
- kSecCSGenerateGuestHash = 1 << 1,
};
OSStatus SecHostCreateGuest(SecGuestRef host,
on whose behalf this thread will act from now on. This setting will be remembered
until it is changed (or the thread terminates).
@param status The new Code Signing status word for the guest. The proxy enforces
- the restrictions on changes to guest status; in particular, the kSecCodeStatusValid bit can only
- be cleared, and the kSecCodeStatusHard and kSecCodeStatusKill flags can only be set. Pass the previous
+ the restrictions on changes to guest status; in particular, the CS_VALID bit can only
+ be cleared, and the CS_HARD and CS_KILL flags can only be set. Pass the previous
guest status to indicate that no change is desired.
@param attributes An optional dictionary containing attributes to be used to distinguish
this guest from all guests of the caller. If given, it completely replaces the attributes
*
* @APPLE_LICENSE_HEADER_END@
*/
-#include "SecCodeHost.h"
+//#include <Security/SecCodeHostLib.h>
#include "SecCodeHostLib.h"
#include <Security/Security.h>
#include <Security/AuthSession.h>
if (KERN_SUCCESS != task_get_bootstrap_port(mach_task_self(), &bootstrapPort))
return errSecCSInternalError;
static char serverName[BOOTSTRAP_MAX_NAME_LEN] = SECURITYSERVER_BOOTSTRAP_NAME;
- if (KERN_SUCCESS != bootstrap_look_up(bootstrapPort, serverName, &gServerPort))
+ if (KERN_SUCCESS != bootstrap_look_up(bootstrapPort,
+ serverName, &gServerPort))
return errSecCSInternalError;
ClientSetupInfo info = { 0x1234, SSPROTOVERSION };
OSStatus SecHostLibCreateGuest(SecGuestRef host,
uint32_t status, const char *path, const char *attributeXML,
SecCSFlags flags, SecGuestRef *newGuest)
-{
- return SecHostLibCreateGuest2(host, status, path, "", 0, attributeXML, flags, newGuest);
-}
-
-OSStatus SecHostLibCreateGuest2(SecGuestRef host,
- uint32_t status, const char *path, const void *cdhash, size_t cdhashLength, const char *attributeXML,
- SecCSFlags flags, SecGuestRef *newGuest)
{
if (flags != kSecCSDedicatedHost)
return errSecCSInvalidFlags;
CALL(ucsp_client_createGuest(UCSP_ARGS, host, status, path,
- (void *)cdhash, cdhashLength, ATTRDATA(attributeXML), flags, newGuest));
+ ATTRDATA(attributeXML), flags, newGuest));
}
{
CALL(ucsp_client_registerHosting(UCSP_ARGS, hostingPort, flags));
}
-
-
-//
-// Helper for checked incorporation of code.
-//
-OSStatus SecHostLibCheckLoad(const char *path, SecRequirementType type)
-{
- CALL(ucsp_client_helpCheckLoad(UCSP_ARGS, path, type));
-}
#ifndef _H_SECCODEHOSTLIB
#define _H_SECCODEHOSTLIB
-#include <Security/SecCodeHost.h>
+//#include <Security/SecCodeHost.h>
+#include "SecCodeHost.h"
+#include <System/sys/codesign.h>
#ifdef __cplusplus
extern "C" {
*/
OSStatus SecHostLibCreateGuest(SecGuestRef host,
uint32_t status, const char *path, const char *attributeXML,
- SecCSFlags flags, SecGuestRef *newGuest) DEPRECATED_ATTRIBUTE;
-
-OSStatus SecHostLibCreateGuest2(SecGuestRef host,
- uint32_t status, const char *path, const void *cdhash, size_t cdhashLength, const char *attributeXML,
SecCSFlags flags, SecGuestRef *newGuest);
*/
-/*!
- */
-OSStatus SecHostLibCheckLoad(const char *path, SecRequirementType type);
-
-
#ifdef __cplusplus
}
#endif
+++ /dev/null
-/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*!
- @header SecCodePriv
- SecCodePriv is the private counter-part to SecCode. Its contents are not
- official API, and are subject to change without notice.
-*/
-#ifndef _H_SECCODEPRIV
-#define _H_SECCODEPRIV
-
-#include <Security/SecCode.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * Private constants for SecCodeCopySigningInformation.
- * These are returned with the
- */
-extern const CFStringRef kSecCodeInfoCodeDirectory; /* Internal */
-extern const CFStringRef kSecCodeInfoCodeOffset; /* Internal */
-extern const CFStringRef kSecCodeInfoResourceDirectory; /* Internal */
-
-
-/*!
- @function SecCodeGetStatus
- Retrieves the dynamic status for a SecCodeRef.
-
- The dynamic status of a code can change at any time; the value returned is a snapshot
- in time that is inherently stale by the time it is received by the caller. However,
- since the status bits can only change in certain ways, some information is indefinitely
- valid. For example, an indication of invalidity (kSecCodeStatusValid bit off) is permanent
- since the valid bit cannot be set once clear, while an indication of validity (bit set)
- may already be out of date.
- Use this call with caution; it is usually wiser to call the validation API functions
- and let then consider the status as part of their holistic computation. However,
- SecCodeGetStatus is useful at times to capture persistent (sticky) status configurations.
-
- @param code A valid SecCode object reference representing code running
- on the system.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param status Upon successful return, contains the dynamic status of code as
- determined by its host.
-
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
- */
-OSStatus SecCodeGetStatus(SecCodeRef code, SecCSFlags flags, SecCodeStatus *status);
-
-
-/*!
- @function SecCodeSetStatus
- Change the dynamic status of a SecCodeRef.
-
- @param code A valid SecCode object reference representing code running
- on the system.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param status Upon successful return, contains the dynamic status of code as
- determined by its host.
-
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
- */
-typedef uint32_t SecCodeStatusOperation;
-enum {
- kSecCodeOperationNull = 0,
- kSecCodeOperationInvalidate = 1,
- kSecCodeOperationSetHard = 2,
- kSecCodeOperationSetKill = 3,
-};
-
-OSStatus SecCodeSetStatus(SecCodeRef code, SecCodeStatusOperation operation,
- CFDictionaryRef arguments, SecCSFlags flags);
-
-
-/*!
- @function SecCodeCopyInternalRequirement
- For a given Code or StaticCode object, retrieves a particular kind of internal
- requirement that was sealed during signing.
-
- This function will always fail for unsigned code. Requesting a type of internal
- requirement that was not given during signing is not an error.
-
- Specifying a type of kSecDesignatedRequirementType is not the same as calling
- SecCodeCopyDesignatedRequirement. This function will only return an explicit
- Designated Requirement if one was specified during signing. SecCodeCopyDesignatedRequirement
- will synthesize a suitable Designated Requirement if one was not given explicitly.
-
- @param code The Code or StaticCode object to be interrogated. For a Code
- argument, its StaticCode is processed as per SecCodeCopyStaticCode.
- @param type A SecRequirementType specifying which internal requirement is being
- requested.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param requirement On successful return, contains a copy of the internal requirement
- of the given type included in the given code. If the code has no such internal
- requirement, this argument is set to NULL (with no error).
- @result On success, noErr. On error, an OSStatus value
- documented in CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef code, SecRequirementType type,
- SecCSFlags flags, SecRequirementRef *requirement);
-
-
-/*!
- @function SecCodeCreateWithPID
- Asks the kernel to return a SecCode object for a process identified
- by a UNIX process id (pid). This is a shorthand for asking SecGetRootCode()
- for a guest whose "pid" attribute has the given pid value.
-
- This is an obsolescent convenience function.
- Call SecCodeCopyGuestWithAttributes instead.
-
- @param pid A process id for an existing UNIX process on the system.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param process On successful return, a SecCode object reference identifying
- the requesteed process.
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *process)
- AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
-
-
-/*
- @function SecCodeSetDetachedSignature
- For a given Code or StaticCode object, explicitly specify the detached signature
- data used to verify it.
- This call unconditionally overrides any signature embedded in the Code and any
- previously specified detached signature; only the signature data specified here
- will be used from now on for this Code object. If NULL data is specified, this
- call reverts to using any embedded signature.
- Any call to this function voids all cached validations for the Code object.
- Validations will be performed again as needed in the future. This call does not,
- by itself, perform or trigger any validations.
- Please note that it is possible to have multiple Code objects for the same static
- or dynamic code entity in the system. This function only attaches signature data
- to the particular SecStaticCodeRef involved. It is your responsibility to understand
- the object graph and pick the right one(s).
-
- @param code A Code or StaticCode object whose signature information is to be changed.
- @param signature A CFDataRef containing the signature data to be used for validating
- the given Code. This must be exactly the data previously generated as a detached
- signature by the SecCodeSignerAddSignature API or the codesign(1) command with
- the -D/--detached option.
- If signature is NULL, discards any previously set signature data and reverts
- to using the embedded signature, if any. If not NULL, the data is retained and used
- for future validation operations.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- */
-OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef code, CFDataRef signature,
- SecCSFlags flags);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //_H_SECCODE
SecCodeSignerRef *signerRef)
{
BEGIN_CSAPI
-
- checkFlags(flags, kSecCSRemoveSignature);
- SecPointer<SecCodeSigner> signer = new SecCodeSigner(flags);
+ SecPointer<SecCodeSigner> signer = new SecCodeSigner;
signer->parameters(parameters);
Required(signerRef) = signer->handle();
-
END_CSAPI
}
/*
- * Copyright (c) 2006-2007 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
/*!
@header SecCodeSigner
- SecCodeSigner represents an object that can sign code.
+ SecCodeSigner represents an object that signs code.
*/
#ifndef _H_SECCODESIGNER
#define _H_SECCODESIGNER
/*!
@function SecCodeGetTypeID
- Returns the type identifier of all SecCodeSigner instances.
+ Returns the type identifier of all SecCode instances.
*/
CFTypeID SecCodeSignerGetTypeID(void);
/*!
- The following CFString constants can be used as keys in the parameters argument
- of SecCodeSignerCreate to specify various modes and options of the signing operation.
- Passing any keys not specified here may lead to undefined behavior and is not supported.
- The same applies to passing objects of types not explicitly allowed here.
-
- @constant kSecCodeSignerDetached Determines where the signature is written.
- If this key is absent, the code being signed is modified to contain the signature,
- replacing any signature already embedded there.
- If the value is kCFNull, the signature is written to the system-wide detached
- signature database. (You must have root privileges to write there.)
- If the value of this key is a CFURL, the signature is written to a file at that location,
- replacing any data there.
- If the value is a CFMutableData, the signature is appended to that data.
- @constant kSecCodeSignerDryRun A boolean value. If present and true, the actual writing
- of the signature is inhibited, and the code is not modified, but all operations
- leading up to this are performed normally, including the cryptographic access to
- the signing identity (if any).
- @constant kSecCodeSignerFlags A CFNumber specifying which flags to set in the code signature.
- Note that depending on circumstances, this value may be augmented or modified
- as part of the signing operation.
- @constant kSecCodeSignerIdentifier If present, a CFString that explicitly specifies
- the unique identifier string sealed into the code signature. If absent, the identifier
- is derived implicitly from the code being signed.
- @constant kSecCodeSignerIdentifierPrefix If the unique identifier string of the code signature
- is implicitly generated, and the resulting string does not contain any "." (dot)
- characters, then the (string) value of this parameter is prepended to the identifier.
- By convention, the prefix is usually of the form "com.yourcompany.", but any value
- is acceptable. If the kSecCodeSignerIdentifier parameter is specified, this parameter
- is ineffective (but still allowed).
@constant kSecCodeSignerIdentity A SecIdentityRef describing the signing identity
- to use for signing code. This is a mandatory parameter for signing operations.
- Its value must be either a SecIdentityRef specifying a cryptographic identity
- valid for Code Signing, or the special value kCFNull to indicate ad-hoc signing.
- @constant kSecCodeSignerOperation The type of operation to be performed. Valid values
- are kSecCodeSignerOperationSign to sign code, and kSecCodeSignerOperationRemove
- to remove any existing signature from code. The default operation is to sign code.
- @constant kSecCodeSignerPageSize An integer value explicitly specifying the page size
- used to sign the main executable. This must be a power of two. A value of zero indicates
- infinite size (no paging).
- Only certain page sizes are allowed in most circumstances, and specifying an inappropriate
- size will lead to spurious verification failures. This is for expert use only.
- @constant kSecCodeSignerRequirements Specifies the internal requirements to be sealed into
- the code signature. Must be either a CFData containing the binary (compiled) form of
- a requirements set (SuperBlob), or a CFString containing a valid text form to be
- compiled into binary form. Default requirements are automatically generated if this
- parameter is omitted, and defaults may be applied to particular requirement types
- that are not specified; but any requirement type you specify is sealed exactly as
- specified.
- @constant kSecCodeSignerResourceRules A CFDictionary containing resource scanning rules
- determining what resource files are sealed into the signature (and in what way).
- A situation-dependent default is applied if this parameter is not specified.
- @constant kSecCodeSignerSigningTime Specifies what date and time is sealed into the
- code signature's CMS data. Can be either a CFDate object specifying a date, or
- the value kCFNull indicating that no date should be included in the signature.
- If not specified, the current date is chosen and sealed.
- Since an ad-hoc signature has no CMS data, this argument is ineffective
- for ad-hoc signing operations.
+ to use for signing code. This is a mandatory parameter.
+ @constant kSecCodeSignerDetached If present, a detached code signature is generated.
+ If absent, code signature data is written into the target code (which must
+ be writable). The value is a CFURL identifying the file that is replaced with
+ the detached signature data.
+ @constant kSecCodeSignerRequirements Internal code requirements.
+ @constant kSecCodeSignerFlags Signature flags.
*/
extern const CFStringRef kSecCodeSignerApplicationData;
extern const CFStringRef kSecCodeSignerDetached;
are applied to all parameters; note however that some parameters do not have
useful defaults, and will need to be set before signing is attempted.
@param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- The kSecCSRemoveSignature flag requests that any existing signature be stripped
- from the target code instead of signing.
@param staticCode On successful return, a SecStaticCode object reference representing
the file system origin of the given SecCode. On error, unchanged.
@result Upon success, noErr. Upon error, an OSStatus value documented in
CSCommon.h or certain other Security framework headers.
*/
-enum {
- kSecCSRemoveSignature = 1 << 0, // strip existing signature
-};
-
-
OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
SecCodeSignerRef *signer);
*
* @APPLE_LICENSE_HEADER_END@
*/
+//#include <Security/SecCodeHostLib.h>
#include "SecIntegrityLib.h"
}
Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
+ secdebug("codesign", "created group requirement for %s", cfString(groupName).c_str());
+
END_CSAPI
}
END_CSAPI
}
-
-//
-// Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
-// An empty set is allowed.
-//
-OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags,
- CFDataRef *requirementSet)
-{
- BEGIN_CSAPI
-
- checkFlags(flags);
- if (requirements == NULL)
- return errSecCSObjectRequired;
- CFIndex count = CFDictionaryGetCount(requirements);
- CFNumberRef keys[count];
- SecRequirementRef reqs[count];
- CFDictionaryGetKeysAndValues(requirements, (const void **)keys, (const void **)reqs);
- Requirements::Maker maker;
- for (CFIndex n = 0; n < count; n++) {
- const Requirement *req = SecRequirement::required(reqs[n])->requirement();
- maker.add(cfNumber<Requirements::Type>(keys[n]), req->clone());
- }
- Requirements *reqset = maker.make(); // malloc'ed
- Required(requirementSet) = makeCFDataMalloc(*reqset); // takes ownership of reqs
-
- END_CSAPI
-}
-
-
-//
-// Break a requirement set (given as a CFData) into its constituent requirements
-// and return it as a CFDictionary.
-//
-OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags,
- CFDictionaryRef *requirements)
-{
- BEGIN_CSAPI
-
- checkFlags(flags);
- if (requirementSet == NULL)
- return errSecCSObjectRequired;
- const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(requirementSet);
- CFRef<CFMutableDictionaryRef> dict = makeCFMutableDictionary();
- unsigned count = reqs->count();
- for (unsigned n = 0; n < count; n++) {
- CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle();
- CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req);
- }
- Required(requirements) = dict.yield();
-
- END_CSAPI
-}
-
-
-//
-// Generically parse a string as some kind of requirement-related source form.
-// If properly recognized, return the result as a CF object:
-// SecRequirementRef for a single requirement
-// CFDataRef for a requirement set
-//
-OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags,
- CFTypeRef *result, CFErrorRef *errors)
-{
- BEGIN_CSAPI
-
- checkFlags(flags, kSecCSParseRequirement | kSecCSParseRequirementSet);
- if (text == NULL || result == NULL)
- return errSecCSObjectRequired;
- std::string s = cfString(text);
- switch (flags & (kSecCSParseRequirement | kSecCSParseRequirementSet)) {
- case kSecCSParseRequirement: // single only
- *result = (new SecRequirement(parseRequirement(s), true))->handle();
- break;
- case kSecCSParseRequirementSet: // single only
- {
- const Requirements *reqs = parseRequirements(s);
- *result = makeCFDataMalloc(*reqs);
- break;
- }
- case 0:
- case kSecCSParseRequirement | kSecCSParseRequirementSet:
- {
- const BlobCore *any = parseGeneric(s);
- if (any->is<Requirement>())
- *result = (new SecRequirement(Requirement::specific(any), true))->handle();
- else
- *result = makeCFDataMalloc(*any);
- break;
- }
- }
-
- END_CSAPI_ERRORS
-}
-
-
-//
-// Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
-// Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
-// A single requirement will return a single line that is NOT newline-terminated.
-//
-OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text)
-{
- BEGIN_CSAPI
-
- checkFlags(flags);
- if (input == NULL)
- return errSecCSObjectRequired;
- if (CFGetTypeID(input) == SecRequirementGetTypeID()) {
- return SecRequirementCopyString(SecRequirementRef(input), flags, text);
- } else if (CFGetTypeID(input) == CFDataGetTypeID()) {
- const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input));
- if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input))))
- return errSecCSReqInvalid;
- Required(text) = makeCFString(Dumper::dump(reqs, false));
- } else
- return errSecCSInvalidObjectRef;
-
- END_CSAPI
-}
#ifndef _H_SECREQUIREMENT
#define _H_SECREQUIREMENT
-#include <Security/CSCommon.h>
-#include <Security/SecCertificate.h>
-
#ifdef __cplusplus
extern "C" {
#endif
+#include <Security/CSCommon.h>
+#include <Security/SecCertificate.h>
+
/*!
@function SecRequirementGetTypeID
OSStatus SecRequirementCreateWithData(CFDataRef data, SecCSFlags flags,
SecRequirementRef *requirement);
+/*!
+ @function SecRequirementCreateWithResource
+ Create a SecRequirement object from binary form obtained from a file.
+ This call is functionally equivalent to reading the entire contents of a file
+ into a CFDataRef and then calling SecRequirementCreateWithData with that.
+ @param resource A CFURL identifying a file containing a (binary) requirement blob.
+ @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+ @param requirement On successful return, contains a reference to a SecRequirement
+ object that behaves identically to the one the data blob was obtained from.
+ @result Upon success, noErr. Upon error, an OSStatus value documented in
+ CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags,
+ SecRequirementRef *requirement);
+
/*!
@function SecRequirementCreateWithString
Create a SecRequirement object by compiling a valid text representation
OSStatus SecRequirementCreateWithStringAndErrors(CFStringRef text, SecCSFlags flags,
CFErrorRef *errors, SecRequirementRef *requirement);
+/*!
+ @function SecRequirementCreateGroup
+ Create a SecRequirement object that represents membership in a developer-defined
+ application group. Group membership is defined by an entry in the code's
+ Info.plist, and sealed to a particular signing authority.
+
+ @param groupName A CFString containing the name of the desired application group.
+ @param anchor A reference to a digital certificate representing the signing
+ authority that asserts group membership. If NULL, indicates Apple's authority.
+ @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+ @param requirement On successful return, contains a reference to a SecRequirement
+ object that requires group membership to pass validation.
+ @result Upon success, noErr. Upon error, an OSStatus value documented in
+ CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchor,
+ SecCSFlags flags, SecRequirementRef *requirement);
/*!
@function SecRequirementCopyData
+++ /dev/null
-/*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*!
- @header SecRequirement
- SecRequirementPriv is the private counter-part to SecRequirement. Its contents are not
- official API, and are subject to change without notice.
-*/
-#ifndef _H_SECREQUIREMENTPRIV
-#define _H_SECREQUIREMENTPRIV
-
-#include <Security/SecRequirement.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*!
- @function SecRequirementsCreateFromRequirements
- Take a dictionary of requirement objects and package them up as a requirement set.
-
- @param requirements A dictionary of requirements to combine into a set.
- Dictionary keys are CFNumbers representing the index keys. Values are SecRequirementRefs.
- NULL requirements are not allowed in the dictionary.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param requirementSet Upon success, receives a CFData object
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags,
- CFDataRef *requirementSet);
-
-
-/*!
- @function SecRequirementsCopyRequirements
- Create a SecRequirement object from binary form obtained from a file.
- This call is functionally equivalent to reading the entire contents of a file
- into a CFDataRef and then calling SecRequirementCreateWithData with that.
-
- @param requirementSet A CFData containing a requirement set.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param requirements Upon success, a dictionary containing each requirement contained
- in requirementSet. The keys are CFNumbers indicating the requirement type.
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags,
- CFDictionaryRef *requirements);
-
-
-/*!
- @function SecRequirementsCreateWithString
- Create a SecRequirement object or requirement set based on the string provided.
-
- @param text A CFString containing the text form of a (single) Code Requirement.
- @param flags Optional flags. Pass kSecCSDefaultFlags to accept any supported input form.
- Pass a combination of individual flags to select what forms to accept; other forms will result
- in an error.
- @param result Upon success, a CoreFoundation object of some kind representing
- the result of parsing text. Depending on the input string and flags, the result
- can be a SecRequirementRef (for a single requirement) or a CFDataRef for a requirement set.
- @param errors An optional pointer to a CFErrorRef variable. If the call fails
- (and something other than noErr is returned), and this argument is non-NULL,
- a CFErrorRef is stored there further describing the nature and circumstances
- of the failure. The caller must CFRelease() this error object when done with it.
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-enum {
- kSecCSParseRequirement = 0x0001, // accept single requirements
- kSecCSParseRequirementSet = 0x0002, // accept requirement sets
-};
-
-OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags,
- CFTypeRef *result, CFErrorRef *errors);
-
-
-/*!
- @function SecRequirementsCopyString
- Converts a requirement object of some kind into text form.
- This is the effective inverse of SecRequirementsCreateWithString.
-
- This function can process individual requirements (SecRequirementRefs)
- and requirement sets (represented as CFDataRefs).
-
- Repeated application of this function may produce text that differs in
- formatting, may contain different source comments, and may perform its
- validation functions in different order. However, it is guaranteed that
- recompiling the text using SecRequirementCreateWithString will produce a
- SecRequirement object that behaves identically to the one you start with.
-
- @param requirements A SecRequirementRef, or a CFDataRef containing a valid requirement set.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param text On successful return, contains a reference to a CFString object
- containing a text representation of the requirement.
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text);
-
-
-/*!
- @function SecRequirementCreateWithResource
- Create a SecRequirement object from binary form obtained from a file.
- This call is functionally equivalent to reading the entire contents of a file
- into a CFDataRef and then calling SecRequirementCreateWithData with that.
-
- @param resource A CFURL identifying a file containing a (binary) requirement blob.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param requirement On successful return, contains a reference to a SecRequirement
- object that behaves identically to the one the data blob was obtained from.
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags,
- SecRequirementRef *requirement);
-
-
-/*!
- @function SecRequirementCreateGroup
- Create a SecRequirement object that represents membership in a developer-defined
- application group. Group membership is defined by an entry in the code's
- Info.plist, and sealed to a particular signing authority.
-
- This is not an API-track function. Don't call it if you don't already do.
-
- @param groupName A CFString containing the name of the desired application group.
- @param anchor A reference to a digital certificate representing the signing
- authority that asserts group membership. If NULL, indicates Apple's authority.
- @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- @param requirement On successful return, contains a reference to a SecRequirement
- object that requires group membership to pass validation.
- @result Upon success, noErr. Upon error, an OSStatus value documented in
- CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchor,
- SecCSFlags flags, SecRequirementRef *requirement);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //_H_SECREQUIREMENTPRIV
| kSecCSConsiderExpiration);
SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
- DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
code->validateDirectory();
if (!(flags & kSecCSDoNotValidateExecutable))
code->validateExecutable();
}
-//
-// Fetch a particular internal requirement, if present
-//
-OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type,
- SecCSFlags flags, SecRequirementRef *requirementRef)
-{
- BEGIN_CSAPI
-
- checkFlags(flags);
- const Requirement *req =
- SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
- Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
-
- END_CSAPI
-}
-
-
//
// Record for future use a detached code signature.
//
checkFlags(flags);
SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
- if (signature)
- CFRetain(signature); // own a reference...
- code->detachedSignature(signature); // ... and pass it to the code
+ code->detachedSignature(signature);
code->resetValidity();
END_CSAPI
This includes applications, tools, frameworks, plugins, scripts, and so on.
Normally, each SecCode has a specific SecStaticCode that holds its static signing
- data. Informally, that is the SecStaticCode the SecCode "was made from" (by its host).
- There is however no viable link in the other direction - given a SecStaticCode,
- it is not possible to find, enumerate, or control any SecCode that originated from it.
+ data. Informally, that is the SecStaticCode the SecCode "was made from". There is
+ however no viable link in the other direction - given a SecStaticCode, it is not
+ possible to find, enumerate, or control any SecCode that originated from it.
*/
#ifndef _H_SECSTATICCODE
#define _H_SECSTATICCODE
-#include <Security/CSCommon.h>
-
#ifdef __cplusplus
extern "C" {
#endif
+#include <Security/CSCommon.h>
+
/*!
@function SecStaticCodeGetTypeID
linked to running code in the system.
It is possible to create a SecStaticCode object from an unsigned code object.
- Most uses of such an object will return the errSecCSUnsigned error. However,
- SecCodeCopyPath and SecCodeCopySigningInformation can be safely applied to such objects.
+ Most uses of such an object will return the errSecCSUnsigned error.
@param path A path to a location in the file system. Only file:// URLs are
currently supported. For bundles, pass a URL to the root directory of the
This call is only secure if the code is not subject to concurrent modification,
and the outcome is only valid as long as the code is unmodified thereafter.
- Consider this carefully if the underlying file system has dynamic characteristics,
- such as a network file system, union mount, FUSE, etc.
@param staticCode The code object to be validated.
@param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
the staticCode object must satisfy to be considered valid. If NULL, no additional
requirements are imposed.
@param errors An optional pointer to a CFErrorRef variable. If the call fails
- (something other than noErr is returned), and this argument is non-NULL,
+ (and something other than noErr is returned), and this argument is non-NULL,
a CFErrorRef is stored there further describing the nature and circumstances
of the failure. The caller must CFRelease() this error object when done with it.
- @result If validation succeeds, noErr. If validation fails, an OSStatus value
+ @result If validation passes, noErr. If validation fails, an OSStatus value
documented in CSCommon.h or certain other Security framework headers.
*/
enum {
+++ /dev/null
-/*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*!
- @header SecStaticCode
- SecStaticCodePriv is the private counter-part to SecStaticCode. Its contents are not
- official API, and are subject to change without notice.
-*/
-#ifndef _H_SECSTATICCODEPRIV
-#define _H_SECSTATICCODEPRIV
-
-#include <Security/SecStaticCode.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * Currently empty
- */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //_H_SECSTATICCODEPRIV
#include "sigblob.h"
#include "resources.h"
#include "renum.h"
-#include "detachedrep.h"
-#include "csdatabase.h"
#include "csutilities.h"
#include <CoreFoundation/CFURLAccess.h>
#include <Security/SecPolicyPriv.h>
#include <Security/SecCmsSignerInfo.h>
#include <Security/SecCmsSignedData.h>
#include <security_utilities/unix++.h>
-#include <security_utilities/cfmunge.h>
+#include <security_codesigning/cfmunge.h>
#include <Security/CMSDecoder.h>
using namespace UnixPlusPlus;
+//
+// We use a DetachedRep to interpose (filter) the genuine DiskRep representing
+// the code on disk, *if* a detached signature was set on this object. In this
+// situation, mRep will point to a (2 element) chain of DiskReps.
+//
+// This is a neat way of dealing with the (unusual) detached-signature case
+// without disturbing things unduly. Consider DetachedDiskRep to be closely
+// married to SecStaticCode; it's unlikely to work right if you use it elsewhere.
+//
+class DetachedRep : public DiskRep {
+public:
+ DetachedRep(CFDataRef sig, DiskRep *orig);
+
+ const RefPointer<DiskRep> original; // underlying representation
+
+ DiskRep *base() { return original; }
+ CFDataRef component(CodeDirectory::SpecialSlot slot);
+ std::string mainExecutablePath() { return original->mainExecutablePath(); }
+ CFURLRef canonicalPath() { return original->canonicalPath(); }
+ std::string recommendedIdentifier() { return original->recommendedIdentifier(); }
+ std::string resourcesRootPath() { return original->resourcesRootPath(); }
+ CFDictionaryRef defaultResourceRules() { return original->defaultResourceRules(); }
+ Universal *mainExecutableImage() { return original->mainExecutableImage(); }
+ size_t signingBase() { return original->signingBase(); }
+ size_t signingLimit() { return original->signingLimit(); }
+ std::string format() { return original->format(); }
+ FileDesc &fd() { return original->fd(); }
+ void flush() { return original->flush(); }
+
+private:
+ CFCopyRef<CFDataRef> mSignature;
+ const EmbeddedSignatureBlob *mArch; // current architecture; points into mSignature
+ const EmbeddedSignatureBlob *mGlobal; // shared elements; points into mSignature
+};
+
+
//
// Construct a SecStaticCode object given a disk representation object
//
mValidated(false), mExecutableValidated(false),
mDesignatedReq(NULL), mGotResourceBase(false), mEvalDetails(NULL)
{
- CODESIGN_STATIC_CREATE(this, rep);
- checkForSystemSignature();
}
}
-//
-// CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
-// and falls back on comparing canonical paths if (both are) not.
-//
-bool SecStaticCode::equal(SecCFObject &secOther)
-{
- SecStaticCode *other = static_cast<SecStaticCode *>(&secOther);
- CFDataRef mine = this->cdHash();
- CFDataRef his = other->cdHash();
- if (mine || his)
- return mine && his && CFEqual(mine, his);
- else
- return CFEqual(this->canonicalPath(), other->canonicalPath());
-}
-
-CFHashCode SecStaticCode::hash()
-{
- if (CFDataRef h = this->cdHash())
- return CFHash(h);
- else
- return CFHash(this->canonicalPath());
-}
-
-
//
// Attach a detached signature.
//
void SecStaticCode::detachedSignature(CFDataRef sigData)
{
- if (sigData) {
- mRep = new DetachedRep(sigData, mRep->base(), "explicit detached");
- CODESIGN_STATIC_ATTACH_EXPLICIT(this, mRep);
- } else {
+ if (sigData)
+ mRep = new DetachedRep(sigData, mRep->base());
+ else
mRep = mRep->base();
- CODESIGN_STATIC_ATTACH_EXPLICIT(this, NULL);
- }
-}
-
-
-//
-// Consult the system detached signature database to see if it contains
-// a detached signature for this StaticCode. If it does, fetch and attach it.
-// We do this only if the code has no signature already attached.
-//
-void SecStaticCode::checkForSystemSignature()
-{
- if (!this->isSigned())
- try {
- if (RefPointer<DiskRep> dsig = signatureDatabase().findCode(mRep)) {
- CODESIGN_STATIC_ATTACH_SYSTEM(this, dsig);
- mRep = dsig;
- }
- } catch (...) {
- }
-}
-
-
-//
-// Return a descriptive string identifying the source of the code signature
-//
-string SecStaticCode::signatureSource()
-{
- if (!isSigned())
- return "unsigned";
- if (DetachedRep *rep = dynamic_cast<DetachedRep *>(mRep.get()))
- return rep->source();
- return "embedded";
}
//
void SecStaticCode::resetValidity()
{
- CODESIGN_EVAL_STATIC_RESET(this);
+ secdebug("staticCode", "%p resetting validity status", this);
mValidated = false;
mExecutableValidated = false;
mDir = NULL;
mEntitlements = NULL;
mResourceDict = NULL;
mDesignatedReq = NULL;
- mGotResourceBase = false;
mTrust = NULL;
mCertChain = NULL;
mEvalDetails = NULL;
mRep->flush();
-
- // we may just have updated the system database, so check again
- checkForSystemSignature();
}
if (!mDir) {
if (mDir.take(mRep->codeDirectory())) {
const CodeDirectory *dir = reinterpret_cast<const CodeDirectory *>(CFDataGetBytePtr(mDir));
- dir->checkIntegrity();
+ dir->checkVersion();
}
}
if (mDir)
}
-//
-// Get the hash of the CodeDirectory.
-// Returns NULL if there is none.
-//
-CFDataRef SecStaticCode::cdHash()
-{
- if (!mCDHash) {
- if (const CodeDirectory *cd = codeDirectory(false)) {
- SHA1 hash;
- hash(cd, cd->length());
- SHA1::Digest digest;
- hash.finish(digest);
- mCDHash.take(makeCFData(digest, sizeof(digest)));
- CODESIGN_STATIC_CDHASH(this, digest, sizeof(digest));
- }
- }
- return mCDHash;
-}
-
-
//
// Return the CMS signature blob; NULL if none found.
//
if (!validated())
try {
// perform validation (or die trying)
- CODESIGN_EVAL_STATIC_DIRECTORY(this);
+ secdebug("staticCode", "%p validating directory", this);
mValidationExpired = verifySignature();
component(cdInfoSlot); // force load of Info Dictionary (if any)
- CodeDirectory::SpecialSlot slot = codeDirectory()->nSpecialSlots;
- if (slot > cdSlotMax) // might have more special slots than we know about...
- slot = cdSlotMax; // ... but only process the ones we understand
- for ( ; slot >= 1; --slot)
+ for (CodeDirectory::SpecialSlot slot = codeDirectory()->nSpecialSlots;
+ slot >= 1; --slot)
if (mCache[slot]) // if we already loaded that resource...
validateComponent(slot); // ... then check it now
mValidated = true; // we've done the deed...
// This performs the cryptographic tango. It returns if the signature is valid,
// or throws if it is not. As a side effect, a successful return sets up the
// cached certificate chain for future use.
-// Returns true if the signature is expired (the X.509 sense), false if it's not.
//
bool SecStaticCode::verifySignature()
{
// ad-hoc signed code is considered validly signed by definition
if (flag(kSecCodeSignatureAdhoc)) {
- CODESIGN_EVAL_STATIC_SIGNATURE_ADHOC(this);
+ secdebug("staticCode", "%p considered verified since it is ad-hoc", this);
return false;
}
-
- DTRACK(CODESIGN_EVAL_STATIC_SIGNATURE, this, (char*)this->mainExecutablePath().c_str());
// decode CMS and extract SecTrust for verification
+ secdebug("staticCode", "%p verifying signature", this);
CFRef<CMSDecoderRef> cms;
MacOSError::check(CMSDecoderCreate(&cms.aref())); // create decoder
CFDataRef sig = this->signature();
CSSM_TP_ACTION_IMPLICIT_ANCHORS // action flags
};
- for (;;) { // at most twice
+ for (;;) {
MacOSError::check(SecTrustSetParameters(mTrust,
CSSM_TP_ACTION_DEFAULT, CFTempData(&actionData, sizeof(actionData))));
SecTrustResultType trustResult;
MacOSError::check(SecTrustEvaluate(mTrust, &trustResult));
MacOSError::check(SecTrustGetResult(mTrust, &trustResult, &mCertChain.aref(), &mEvalDetails));
- CODESIGN_EVAL_STATIC_SIGNATURE_RESULT(this, trustResult, mCertChain ? CFArrayGetCount(mCertChain) : 0);
+ secdebug("staticCode", "%p verification result=%d chain=%ld",
+ this, trustResult, mCertChain ? CFArrayGetCount(mCertChain) : -1);
switch (trustResult) {
case kSecTrustResultProceed:
case kSecTrustResultConfirm:
OSStatus result;
MacOSError::check(SecTrustGetCssmResultCode(mTrust, &result));
if (result == CSSMERR_TP_CERT_EXPIRED && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) {
- CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this);
+ secdebug("staticCode", "expired certificate(s); retrying validation");
actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
continue; // retry validation
}
//
void SecStaticCode::validateComponent(CodeDirectory::SpecialSlot slot)
{
- assert(slot <= cdSlotMax);
CFDataRef data = mCache[slot];
assert(data); // must be cached
if (data == CFDataRef(kCFNull)) {
//
void SecStaticCode::validateExecutable()
{
- DTRACK(CODESIGN_EVAL_STATIC_EXECUTABLE, this,
- (char*)this->mainExecutablePath().c_str(), codeDirectory()->nCodeSlots);
+ secdebug("staticCode", "%p performing static main exec validate of %s",
+ this, mainExecutablePath().c_str());
const CodeDirectory *cd = this->codeDirectory();
if (!cd)
MacOSError::throwMe(errSecCSUnsigned);
for (size_t slot = 0; slot < cd->nCodeSlots; ++slot) {
size_t size = min(remaining, pageSize);
if (!cd->validateSlot(fd, size, slot)) {
- CODESIGN_EVAL_STATIC_EXECUTABLE_FAIL(this, slot);
+ secdebug("staticCode", "%p failed static validation of code page %zd", this, slot);
mExecutableValidated = true; // we tried
mExecutableValid = false; // it failed
MacOSError::throwMe(errSecCSSignatureFailed);
}
remaining -= size;
}
+ secdebug("staticCode", "%p validated full executable (%d pages)",
+ this, int(cd->nCodeSlots));
mExecutableValidated = true; // we tried
mExecutableValid = true; // it worked
}
// found resources, and they are sealed
CFDictionaryRef rules = cfget<CFDictionaryRef>(sealedResources, "rules");
CFDictionaryRef files = cfget<CFDictionaryRef>(sealedResources, "files");
- DTRACK(CODESIGN_EVAL_STATIC_RESOURCES, this,
- (char*)this->mainExecutablePath().c_str(), int(CFDictionaryGetCount(files)));
+ secdebug("staticCode", "%p verifying %d sealed resources",
+ this, int(CFDictionaryGetCount(files)));
// make a shallow copy of the ResourceDirectory so we can "check off" what we find
- CFRef<CFMutableDictionaryRef> resourceMap = makeCFMutableDictionary(files);
+ CFRef<CFMutableDictionaryRef> resourceMap = CFDictionaryCreateMutableCopy(NULL,
+ CFDictionaryGetCount(files), files);
+ if (!resourceMap)
+ CFError::throwMe();
// scan through the resources on disk, checking each against the resourceDirectory
CollectingContext ctx(*this); // collect all failures in here
ResourceBuilder::Rule *rule;
while (resources.next(path, rule)) {
- validateResource(path, ctx);
+ if (CFDataRef value = resource(path, ctx))
+ CFRelease(value);
CFDictionaryRemoveValue(resourceMap, CFTempString(path));
+ secdebug("staticCode", "%p validated %s", this, path.c_str());
}
if (CFDictionaryGetCount(resourceMap) > 0) {
// now check for any errors found in the reporting context
if (ctx)
ctx.throwMe();
+
+ secdebug("staticCode", "%p sealed resources okay", this);
}
}
-void SecStaticCode::validateResource(string path, ValidationContext &ctx)
-{
- if (CFDictionaryRef rdict = resourceDictionary()) {
- if (CFTypeRef file = cfget(rdict, "files.%s", path.c_str())) {
- ResourceSeal seal = file;
- if (!resourceBase()) // no resources in DiskRep
- MacOSError::throwMe(errSecCSResourcesNotFound);
- CFRef<CFURLRef> fullpath = makeCFURL(path, false, resourceBase());
- AutoFileDesc fd(cfString(fullpath), O_RDONLY, FileDesc::modeMissingOk); // open optional filee
- if (fd) {
- SHA1 hasher;
- hashFileData(fd, hasher);
- if (hasher.verify(seal.hash()))
- return; // verify good
- else
- ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // altered
- } else {
- if (!seal.optional())
- ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceMissing, fullpath); // was sealed but is now missing
- else
- return; // validly missing
- }
- } else
- ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAdded, CFTempURL(path, false, resourceBase()));
- } else
- MacOSError::throwMe(errSecCSResourcesNotSealed);
-}
-
-
//
// Test a CodeDirectory flag.
// Returns false if there is no CodeDirectory.
return false;
}
+
void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker)
{
// get the Organization DN element for the leaf
while (SecCertificateRef ca = cert(slot+1)) { // NULL if you over-run the anchor slot
CFRef<CFStringRef> caOrganization;
MacOSError::check(SecCertificateCopySubjectComponent(ca, &CSSMOID_OrganizationName, &caOrganization.aref()));
- if (!caOrganization || CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo)
+ if (CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo)
break;
slot++;
}
if (slot == CFArrayGetCount(mCertChain) - 1) // went all the way to the anchor...
slot = Requirement::anchorCert; // ... so say that
}
-
+
// nail the last cert with the leaf's Organization value
SHA1::Digest authorityHash;
hashOfCertificate(cert(slot), authorityHash);
void SecStaticCode::validateRequirements(SecRequirementType type, SecStaticCode *target,
OSStatus nullError /* = noErr */)
{
- DTRACK(CODESIGN_EVAL_STATIC_INTREQ, this, type, target, nullError);
+ secdebug("staticCode", "%p validating %s requirements for %p",
+ this, Requirement::typeNames[type], target);
if (const Requirement *req = internalRequirement(type))
target->validateRequirements(req, nullError ? nullError : errSecCSReqFailed);
- else if (nullError)
+ else if (nullError) {
+ secdebug("staticCode", "%p NULL validate for %s prohibited",
+ this, Requirement::typeNames[type]);
MacOSError::throwMe(nullError);
- else
- /* accept it */;
+ } else
+ secdebug("staticCode", "%p NULL validate (no requirements for %s)",
+ this, Requirement::typeNames[type]);
}
// [ leaf, intermed-1, ..., intermed-n, anchor ]
// 0 1 ... -2 -1
// Returns NULL if unavailable for any reason.
-//
+//
SecCertificateRef SecStaticCode::cert(int ix)
{
validateDirectory(); // need cert chain
//
-// Gather (mostly) API-official information about this StaticCode.
+// Gather API-official information about this StaticCode.
//
// This method lives in the twilight between the API and internal layers,
// since it generates API objects (Sec*Refs) for return.
if (!this->isSigned())
return dict.yield();
+
//
- // Add the generic attributes that we always include
+ // Now add the generic attributes that we always include
//
CFDictionaryAddValue(dict, kSecCodeInfoIdentifier, CFTempString(this->identifier()));
CFDictionaryAddValue(dict, kSecCodeInfoFormat, CFTempString(this->format()));
- CFDictionaryAddValue(dict, kSecCodeInfoSource, CFTempString(this->signatureSource()));
- if (CFDictionaryRef info = this->infoDictionary())
+ if (CFDictionaryRef info = infoDictionary())
CFDictionaryAddValue(dict, kSecCodeInfoPList, info);
- CFDictionaryAddValue(dict, kSecCodeInfoUnique, this->cdHash());
//
// kSecCSSigningInformation adds information about signing certificates and chains
//
if (flags & kSecCSSigningInformation) {
- if (CFArrayRef certs = this->certificates())
+ if (CFArrayRef certs = certificates())
CFDictionaryAddValue(dict, kSecCodeInfoCertificates, certs);
- if (CFDataRef sig = this->signature())
+ if (CFDataRef sig = signature())
CFDictionaryAddValue(dict, kSecCodeInfoCMS, sig);
if (mTrust)
CFDictionaryAddValue(dict, kSecCodeInfoTrust, mTrust);
- if (CFAbsoluteTime time = this->signingTime())
+ if (CFAbsoluteTime time = signingTime())
if (CFRef<CFDateRef> date = CFDateCreate(NULL, time))
CFDictionaryAddValue(dict, kSecCodeInfoTime, date);
}
// kSecCSRequirementInformation adds information on requirements
//
if (flags & kSecCSRequirementInformation) {
- if (const Requirements *reqs = this->internalRequirements()) {
+ if (const Requirements *reqs = internalRequirements()) {
CFDictionaryAddValue(dict, kSecCodeInfoRequirements,
CFTempString(Dumper::dump(reqs)));
CFDictionaryAddValue(dict, kSecCodeInfoRequirementData, CFTempData(*reqs));
}
-
- const Requirement *dreq = this->designatedRequirement();
- CFRef<SecRequirementRef> dreqRef = (new SecRequirement(dreq))->handle();
- CFDictionaryAddValue(dict, kSecCodeInfoDesignatedRequirement, dreqRef);
- if (this->internalRequirement(kSecDesignatedRequirementType)) { // explicit
- CFRef<SecRequirementRef> ddreqRef = (new SecRequirement(this->defaultDesignatedRequirement(), true))->handle();
+ const Requirement *dreq = designatedRequirement();
+ const Requirement *ddreq = defaultDesignatedRequirement();
+ CFRef<SecRequirementRef> ddreqRef = (new SecRequirement(ddreq))->handle();
+ if (dreq == ddreq) {
+ CFDictionaryAddValue(dict, kSecCodeInfoDesignatedRequirement, ddreqRef);
+ CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, ddreqRef);
+ } else {
+ CFDictionaryAddValue(dict, kSecCodeInfoDesignatedRequirement,
+ CFRef<SecRequirementRef>((new SecRequirement(dreq))->handle()));
CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, ddreqRef);
- } else { // implicit
- CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, dreqRef);
}
- if (CFDataRef ent = this->component(cdEntitlementSlot))
- CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
+ if (CFDataRef ent = component(cdEntitlementSlot))
+ CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
}
//
//
if (flags & kSecCSInternalInformation) {
if (mDir)
- CFDictionaryAddValue(dict, kSecCodeInfoCodeDirectory, mDir);
- CFDictionaryAddValue(dict, kSecCodeInfoCodeOffset, CFTempNumber(mRep->signingBase()));
+ CFDictionaryAddValue(dict, CFSTR("CodeDirectory"), mDir);
+ CFDictionaryAddValue(dict, CFSTR("CodeOffset"), CFTempNumber(mRep->signingBase()));
if (CFDictionaryRef resources = resourceDictionary())
- CFDictionaryAddValue(dict, kSecCodeInfoResourceDirectory, resources);
+ CFDictionaryAddValue(dict, CFSTR("ResourceDirectory"), resources);
}
mStatus = rc; // record first failure for eventual error return
if (type) {
if (!mCollection)
- mCollection.take(makeCFMutableDictionary());
+ mCollection.take(makeCFMutableDictionary(0));
CFMutableArrayRef element = CFMutableArrayRef(CFDictionaryGetValue(mCollection, type));
if (!element) {
element = makeCFMutableArray(0);
}
+//
+// DetachedRep construction
+//
+DetachedRep::DetachedRep(CFDataRef sig, DiskRep *orig)
+ : original(orig), mSignature(sig)
+{
+ const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
+ if (sigBlob->is<EmbeddedSignatureBlob>()) { // architecture-less
+ mArch = EmbeddedSignatureBlob::specific(sigBlob);
+ mGlobal = NULL;
+ return;
+ } else if (sigBlob->is<DetachedSignatureBlob>()) { // architecture collection
+ const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sigBlob);
+ if (Universal *fat = orig->mainExecutableImage()) {
+ if (const BlobCore *blob = dsblob->find(fat->bestNativeArch().cpuType())) {
+ mArch = EmbeddedSignatureBlob::specific(blob);
+ mGlobal = EmbeddedSignatureBlob::specific(dsblob->find(0));
+ return;
+ } else
+ secdebug("staticcode", "detached signature missing architecture %s",
+ fat->bestNativeArch().name());
+ } else
+ secdebug("staticcode", "detached signature requires Mach-O binary");
+ } else
+ secdebug("staticcode", "detached signature bad magic 0x%x", sigBlob->magic());
+ MacOSError::throwMe(errSecCSSignatureInvalid);
+}
+
+CFDataRef DetachedRep::component(CodeDirectory::SpecialSlot slot)
+{
+ if (CFDataRef result = mArch->component(slot))
+ return result;
+ if (mGlobal)
+ if (CFDataRef result = mGlobal->component(slot))
+ return result;
+ return original->component(slot);
+}
+
+
} // end namespace CodeSigning
} // end namespace Security
NOCOPY(SecStaticCode)
protected:
- //
- // A context for resource validation operations, to tailor error response.
- // The base class throws an exception immediately and ignores detail data.
- //
class ValidationContext {
public:
virtual ~ValidationContext();
virtual void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value);
};
- //
- // A CollectingContext collects all error details and throws an annotated final error.
- //
class CollectingContext : public ValidationContext {
public:
CollectingContext(SecStaticCode &c) : code(c), mStatus(noErr) { }
SecStaticCode(DiskRep *rep);
virtual ~SecStaticCode() throw();
- bool equal(SecCFObject &other);
- CFHashCode hash();
-
- void detachedSignature(CFDataRef sig); // attach an explicitly given detached signature
- void checkForSystemSignature(); // check for and attach system-supplied detached signature
+ void detachedSignature(CFDataRef sig);
const CodeDirectory *codeDirectory(bool check = true);
- CFDataRef cdHash();
CFDataRef signature();
CFAbsoluteTime signingTime();
bool isSigned() { return codeDirectory(false) != NULL; }
CFURLRef canonicalPath() const { return mRep->canonicalPath(); }
std::string identifier() { return codeDirectory()->identifier(); }
std::string format() const { return mRep->format(); }
- std::string signatureSource();
CFDataRef component(CodeDirectory::SpecialSlot slot);
CFDictionaryRef infoDictionary();
CFDictionaryRef entitlements();
CFURLRef resourceBase();
CFDataRef resource(std::string path);
CFDataRef resource(std::string path, ValidationContext &ctx);
- void validateResource(string path, ValidationContext &ctx);
bool flag(uint32_t tested);
const Requirements *internalRequirements();
const Requirement *internalRequirement(SecRequirementType type);
const Requirement *designatedRequirement();
- const Requirement *defaultDesignatedRequirement(); // newly allocated (caller owns)
+ const Requirement *defaultDesignatedRequirement();
void validateRequirements(SecRequirementType type, SecStaticCode *target,
OSStatus nullError = noErr);
CFRef<CFDictionaryRef> mEntitlements; // derived from mCache slot
CFRef<CFDictionaryRef> mResourceDict; // derived from mCache slot
const Requirement *mDesignatedReq; // cached designated req if we made one up
- CFRef<CFDataRef> mCDHash; // hash of CodeDirectory
bool mGotResourceBase; // asked mRep for resourceBasePath
CFRef<CFURLRef> mResourceBase; // URL form of resource base directory
#include "bundlediskrep.h"
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFBundlePriv.h>
-#include <security_utilities/cfmunge.h>
+#include <security_codesigning/cfmunge.h>
#include <copyfile.h>
//
// We make a CFBundleRef immediately, but everything else is lazy
//
-BundleDiskRep::BundleDiskRep(const char *path, const Context *ctx)
+BundleDiskRep::BundleDiskRep(const char *path)
: mBundle(_CFBundleCreateIfMightBeBundle(NULL, CFTempURL(path)))
{
if (!mBundle)
MacOSError::throwMe(errSecCSBadObjectFormat);
- mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
- CODESIGN_DISKREP_CREATE_BUNDLE_PATH(this, (char*)path, (void*)ctx, mExecRep);
+ mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath());
}
-BundleDiskRep::BundleDiskRep(CFBundleRef ref, const Context *ctx)
+BundleDiskRep::BundleDiskRep(CFBundleRef ref)
{
mBundle = ref; // retains
- mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
- CODESIGN_DISKREP_CREATE_BUNDLE_REF(this, ref, (void*)ctx, mExecRep);
+ mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath());
}
}
-//
-// The binary identifier is taken directly from the main executable.
-//
-CFDataRef BundleDiskRep::identification()
-{
- return mExecRep->identification();
-}
-
-
//
// Various aspects of our DiskRep personality.
//
string resources = resourcesRootPath();
string executable = mainExecutablePath();
if (!executable.compare(0, resources.length(), resources, 0, resources.length())) // is prefix
- builder.addExclusion(string("^")
- + ResourceBuilder::escapeRE(executable.substr(resources.length() + 1)) + "$");
+ builder.addExclusion(string("^") + executable.substr(resources.length() + 1) + "$");
}
if (rep->mMetaExists) {
// leave a symlink in the support directory for pre-10.5.3 compatibility (but ignore errors)
string legacy = cfString(CFBundleCopySupportFilesDirectoryURL(rep->mBundle), true) + "/" + name;
-# if FORCE_REPLACE_SYMLINK /* replace any existing file with legacy symlink */
- ::unlink(legacy.c_str()); // force-replace
-#endif
+// ::unlink(legacy.c_str()); // force-replace
::symlink((string(BUNDLEDISKREP_DIRECTORY "/") + name).c_str(), legacy.c_str());
}
} else
}
-//
-// Remove all signature data
-//
-void BundleDiskRep::Writer::remove()
-{
- // remove signature from the executable
- execWriter->remove();
-
- // remove signature files from bundle
- for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++)
- remove(slot);
- remove(cdSignatureSlot);
-}
-
-void BundleDiskRep::Writer::remove(CodeDirectory::SpecialSlot slot)
-{
- if (const char *name = CodeDirectory::canonicalSlotName(slot))
- if (::unlink(rep->metaPath(name).c_str()))
- switch (errno) {
- case ENOENT: // not found - that's okay
- break;
- default:
- UnixError::throwMe();
- }
-}
-
-
void BundleDiskRep::Writer::flush()
{
execWriter->flush();
//
class BundleDiskRep : public DiskRep {
public:
- BundleDiskRep(const char *path, const Context *ctx = NULL);
- BundleDiskRep(CFBundleRef ref, const Context *ctx = NULL);
+ BundleDiskRep(const char *path);
+ BundleDiskRep(CFBundleRef ref);
CFDataRef component(CodeDirectory::SpecialSlot slot);
- CFDataRef identification();
std::string mainExecutablePath();
CFURLRef canonicalPath();
std::string recommendedIdentifier();
Writer(BundleDiskRep *r);
void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
- void remove();
void flush();
protected:
DiskRep *execRep() { return rep->mExecRep; }
- void remove(CodeDirectory::SpecialSlot slot);
protected:
RefPointer<BundleDiskRep> rep;
// Create an (empty) builder
//
CodeDirectory::Builder::Builder()
- : mFlags(0), mSpecialSlots(0), mCodeSlots(0), mScatter(NULL), mScatterSize(0), mDir(NULL)
+ : mFlags(0), mSpecialSlots(0), mCodeSlots(0), mDir(NULL)
{
memset(mSpecial, 0, sizeof(mSpecial));
}
-CodeDirectory::Builder::~Builder()
-{
- ::free(mScatter);
-}
-
//
// Set the source of the main executable (i.e. the code pages)
}
-//
-// Allocate a Scatter vector
-//
-CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count)
-{
- mScatterSize = (count + 1) * sizeof(Scatter);
- if (!(mScatter = (Scatter *)::realloc(mScatter, mScatterSize)))
- UnixError::throwMe(ENOMEM);
- ::memset(mScatter, 0, mScatterSize);
- return mScatter;
-}
-
-
-//
-// Calculate the size we'll need for the CodeDirectory as described so far
-//
size_t CodeDirectory::Builder::size()
{
assert(mExec); // must have called executable()
}
size_t offset = sizeof(CodeDirectory);
- offset += mScatterSize; // scatter vector
offset += mIdentifier.size() + 1; // size of identifier (with null byte)
offset += (mCodeSlots + mSpecialSlots) * Hash::digestLength; // hash vector
return offset;
//
// Take everything added to date and wrap it up in a shiny new CodeDirectory.
//
-// Note that this only constructs a CodeDirectory; it does not touch any subsidiary
-// structures (resource tables, etc.), nor does it create any signature to secure
-// the CodeDirectory.
-// The returned CodeDirectory object is yours, and you may modify it as desired.
-// But the memory layout is set here, so the various sizes and counts should be good
-// when you call build().
-// It's up to us to order the dynamic fields as we wish; but note that we currently
-// don't pad them, and so they should be allocated in non-increasing order of required
-// alignment. Make sure to keep the code here in sync with the size-calculating code above.
+// Note that this doesn't include or generate the signature. You're free to
+// modify the result. But this function determines the memory layout, so the
+// sizes and counts should be correct on entry.
//
CodeDirectory *CodeDirectory::Builder::build()
{
// locate and fill flex fields
size_t offset = sizeof(CodeDirectory);
-
- if (mScatter) {
- mDir->scatterOffset = offset;
- memcpy(mDir->scatterVector(), mScatter, mScatterSize);
- offset += mScatterSize;
- }
-
mDir->identOffset = offset;
memcpy(mDir->identifier(), mIdentifier.c_str(), identLength);
offset += identLength;
class CodeDirectory::Builder {
public:
Builder();
- ~Builder();
void executable(string path, size_t pagesize, size_t offset, size_t length);
void reopen(string path, size_t offset, size_t length);
void identifier(const std::string &code) { mIdentifier = code; }
void flags(uint32_t f) { mFlags = f; }
- Scatter *scatter(unsigned count); // allocate that many scatter elements (w/o sentinel)
- Scatter *scatter() { return mScatter; } // return already allocated scatter vector
-
size_t size(); // calculate size
CodeDirectory *build(); // build CodeDirectory and return it
size_t mSpecialSlots; // highest special slot set
size_t mCodeSlots; // number of code pages (slots)
- Scatter *mScatter; // scatter vector
- size_t mScatterSize; // number of scatter elements allocated (incl. sentinel)
-
CodeDirectory *mDir; // what we're building
};
CFMDiskRep::CFMDiskRep(const char *path)
: SingleDiskRep(path), mTriedRead(false)
{
- CODESIGN_DISKREP_CREATE_CFM(this, (char*)path);
}
CFMDiskRep::~CFMDiskRep()
//
-// CFM filter heuristic.
-// We look for the PEF header within the first scanLength bytes
-// of the file's data fork, at certain alignment boundaries (probably
-// conservative).
+// CFM filter heuristic
//
-bool CFMDiskRep::candidate(FileDesc &fd)
+bool CFMDiskRep::candidiate(FileDesc &fd)
{
static const char magicMarker[] = "Joy!peffpwpc";
static const size_t magicLength = 12;
- static const size_t scanLength = 128;
- static const size_t scanAlignment = 4;
-
- char marker[scanLength];
- if (fd.read(marker, scanLength, 0) == scanLength)
- for (size_t p = 0; p <= scanLength - magicLength; p += scanAlignment)
- if (!memcmp(marker+p, magicMarker, magicLength))
- return true;
- return false;
+ char marker[magicLength];
+ return fd.read(marker, magicLength, 0) == magicLength
+ && !memcmp(marker, magicMarker, magicLength);
}
if (fd.read(&sentinel, sizeof(sentinel), fd.fileSize() - sizeof(Sentinel)) == sizeof(Sentinel))
if (sentinel.magic == EmbeddedSignatureBlob::typeMagic) {
mSigningOffset = sentinel.offset;
- if (mSigningData = EmbeddedSignatureBlob::readBlob(fd, mSigningOffset))
+ fd.seek(mSigningOffset);
+ mSigningData = EmbeddedSignatureBlob::readBlob(fd);
+ if (mSigningData)
secdebug("cfmrep", "%zd signing bytes in %d blob(s) from %s(CFM)",
mSigningData->length(), mSigningData->count(),
mainExecutablePath().c_str());
std::string format();
void flush();
- static bool candidate(UnixPlusPlus::FileDesc &fd); // could this reasonably be a CFM code?
+ static bool candidiate(UnixPlusPlus::FileDesc &fd); // could this reasonably be a CFM code?
public:
//
--- /dev/null
+/*
+ * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+// CoreFoundation building and parsing functions.
+//
+// These classes provide a printf/scanf-like interface to nested data structures
+// of the Property List Subset of CoreFoundation.
+//
+#include "cfmunge.h"
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/errors.h>
+
+namespace Security {
+
+
+//
+// Format codes for consistency
+//
+#define F_ARRAY 'A'
+#define F_BOOLEAN 'B'
+#define F_DATA 'X'
+#define F_DICTIONARY 'D'
+#define F_OBJECT 'O'
+#define F_STRING 'S'
+#define F_NUMBER 'N'
+
+
+//
+// Initialize a CFMunge. We start out with the default CFAllocator, and
+// we do not throw errors.
+//
+CFMunge::CFMunge(const char *fmt, va_list arg)
+ : format(fmt), allocator(NULL), error(noErr)
+{
+ va_copy(args, arg);
+}
+
+CFMunge::~CFMunge()
+{
+ va_end(args);
+}
+
+
+//
+// Skip whitespace and other fluff and deliver the next significant character.
+//
+char CFMunge::next()
+{
+ while (*format && (isspace(*format) || *format == ',')) ++format;
+ return *format;
+}
+
+
+//
+// Locate and consume an optional character
+//
+bool CFMunge::next(char c)
+{
+ if (next() == c) {
+ ++format;
+ return true;
+ } else
+ return false;
+}
+
+
+//
+// Process @? parameter specifications.
+// The @ operator is used for side effects, and does not return a value.
+//
+bool CFMunge::parameter()
+{
+ switch (*++format) {
+ case 'A':
+ ++format;
+ allocator = va_arg(args, CFAllocatorRef);
+ return true;
+ case 'E':
+ ++format;
+ error = va_arg(args, OSStatus);
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+//
+// The top constructor.
+//
+CFTypeRef CFMake::make()
+{
+ while (next() == '@')
+ parameter();
+ switch (next()) {
+ case '\0':
+ return NULL;
+ case '{':
+ return makedictionary();
+ case '[':
+ return makearray();
+ case '\'':
+ return makestring();
+ case '%':
+ return makeformat();
+ case '#':
+ return makespecial();
+ case ']':
+ case '}':
+ assert(false); // unexpected
+ return NULL; // error
+ default:
+ if (isdigit(*format))
+ return makenumber();
+ else if (isalpha(*format))
+ return makestring();
+ else {
+ assert(false);
+ return NULL;
+ }
+ }
+}
+
+
+CFTypeRef CFMake::makeformat()
+{
+ ++format;
+ switch (*format++) {
+ case 'b': // blob (pointer, length)
+ {
+ const void *data = va_arg(args, const void *);
+ size_t length = va_arg(args, size_t);
+ return CFDataCreate(allocator, (const UInt8 *)data, length);
+ }
+ case F_BOOLEAN: // boolean (with int promotion)
+ return va_arg(args, int) ? kCFBooleanTrue : kCFBooleanFalse;
+ case 'd':
+ return makeCFNumber(va_arg(args, int));
+ case 's':
+ return CFStringCreateWithCString(allocator, va_arg(args, const char *),
+ kCFStringEncodingUTF8);
+ case F_OBJECT:
+ return CFRetain(va_arg(args, CFTypeRef));
+ case 'u':
+ return makeCFNumber(va_arg(args, unsigned int));
+ default:
+ assert(false);
+ return NULL;
+ }
+}
+
+
+CFTypeRef CFMake::makespecial()
+{
+ ++format;
+ switch (*format++) {
+ case 'N':
+ return kCFNull;
+ case 't':
+ case 'T':
+ return kCFBooleanTrue;
+ case 'f':
+ case 'F':
+ return kCFBooleanFalse;
+ default:
+ assert(false);
+ return NULL;
+ }
+}
+
+
+CFTypeRef CFMake::makenumber()
+{
+ double value = strtod(format, (char **)&format);
+ return CFNumberCreate(allocator, kCFNumberDoubleType, &value);
+}
+
+
+//
+// Embedded strings can either be alphanumeric (only), or delimited with single quotes ''.
+// No escapes are processed within such quotes. If you want arbitrary string values, use %s.
+//
+CFTypeRef CFMake::makestring()
+{
+ const char *start, *end;
+ if (*format == '\'') {
+ start = ++format; // next quote
+ if (!(end = strchr(format, '\''))) {
+ assert(false);
+ return NULL;
+ }
+ format = end + 1;
+ } else {
+ start = format;
+ for (end = start + 1; isalnum(*end); ++end) ;
+ format = end;
+ }
+ return CFStringCreateWithBytes(allocator,
+ (const UInt8 *)start, end - start,
+ kCFStringEncodingUTF8, false);
+}
+
+
+//
+// Construct a CFDictionary
+//
+CFTypeRef CFMake::makedictionary()
+{
+ ++format; // next '{'
+ next('!'); // indicates mutable (currently always true)
+ CFMutableDictionaryRef dict;
+ if (next('+')) { // {+%O, => copy dictionary argument, then proceed
+ if (next('%') && next('O')) {
+ CFDictionaryRef source = va_arg(args, CFDictionaryRef);
+ dict = CFDictionaryCreateMutableCopy(allocator, NULL, source);
+ if (next('}'))
+ return dict;
+ } else
+ return NULL; // bad syntax
+ } else
+ dict = CFDictionaryCreateMutable(allocator, 0,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (add(dict))
+ return dict;
+ else {
+ CFRelease(dict);
+ return NULL;
+ }
+}
+
+CFDictionaryRef CFMake::add(CFMutableDictionaryRef dict)
+{
+ while (next() != '}') {
+ CFTypeRef key = make();
+ if (key == NULL)
+ return NULL;
+ if (!next('=')) {
+ CFRelease(key);
+ return NULL;
+ }
+ if (CFTypeRef value = make()) {
+ CFDictionaryAddValue(dict, key, value);
+ CFRelease(key);
+ CFRelease(value);
+ } else {
+ CFRelease(key);
+ return NULL;
+ }
+ }
+ ++format;
+ return dict;
+}
+
+
+CFDictionaryRef CFMake::addto(CFMutableDictionaryRef dict)
+{
+ if (next('{'))
+ return add(dict);
+ else {
+ assert(false);
+ return NULL;
+ }
+}
+
+
+//
+// Construct a CFArray
+//
+CFTypeRef CFMake::makearray()
+{
+ ++format; // next '['
+ next('!'); // indicates mutable (currently always)
+ CFMutableArrayRef array = makeCFMutableArray(0);
+ while (next() != ']') {
+ CFTypeRef value = make();
+ if (value == NULL) {
+ CFRelease(array);
+ return NULL;
+ }
+ CFArrayAppendValue(array, value);
+ CFRelease(value);
+ }
+ ++format;
+ return array;
+}
+
+
+//
+// A CFScan processes its format by parsing through an existing CF object
+// structure, matching and extracting values as directed. Note that CFScan
+// is a structure (tree) scanner rather than a linear parser, and will happily
+// parse out a subset of the input object graph.
+//
+class CFScan : public CFMake {
+public:
+ CFScan(const char *format, va_list args)
+ : CFMake(format, args), suppress(false) { }
+
+ bool scan(CFTypeRef obj);
+ CFTypeRef dictpath(CFTypeRef obj);
+
+protected:
+ bool scandictionary(CFDictionaryRef obj);
+ bool scanarray(CFArrayRef obj);
+ bool scanformat(CFTypeRef obj);
+
+ enum Typescan { fail = -1, more = 0, done = 1 };
+ Typescan typescan(CFTypeRef obj, CFTypeID type);
+
+ template <class Value>
+ bool CFScan::scannumber(CFTypeRef obj);
+
+ template <class Type>
+ void store(Type value);
+
+ bool suppress; // output suppression
+};
+
+
+//
+// Master scan function
+//
+bool CFScan::scan(CFTypeRef obj)
+{
+ while (next() == '@')
+ parameter();
+ switch (next()) {
+ case '\0':
+ return true; // done, okay
+ case '{':
+ if (obj && CFGetTypeID(obj) != CFDictionaryGetTypeID())
+ return false;
+ return scandictionary(CFDictionaryRef(obj));
+ case '[':
+ if (obj && CFGetTypeID(obj) != CFArrayGetTypeID())
+ return false;
+ return scanarray(CFArrayRef(obj));
+ case '%': // return this value in some form
+ return scanformat(obj);
+ case '=': // match value
+ {
+ ++format;
+ CFTypeRef match = make();
+ bool rc = CFEqual(obj, match);
+ CFRelease(match);
+ return rc;
+ }
+ case ']':
+ case '}':
+ assert(false); // unexpected
+ return false;
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+
+//
+// Primitive type-match helper.
+// Ensures the object has the CF runtime type required, and processes
+// the %?o format (return CFTypeRef) and %?n format (ignore value).
+//
+CFScan::Typescan CFScan::typescan(CFTypeRef obj, CFTypeID type)
+{
+ if (obj && CFGetTypeID(obj) != type)
+ return fail;
+ switch (*++format) {
+ case F_OBJECT: // return CFTypeRef
+ ++format;
+ store<CFTypeRef>(obj);
+ return done;
+ case 'n': // suppress assignment
+ ++format;
+ return done;
+ default:
+ return more;
+ }
+}
+
+
+//
+// Store a value into the next varargs slot, unless output suppression is on.
+//
+template <class Type>
+void CFScan::store(Type value)
+{
+ if (!suppress)
+ *va_arg(args, Type *) = value;
+}
+
+
+//
+// Convert a CFNumber to an external numeric form
+//
+template <class Value>
+bool CFScan::scannumber(CFTypeRef obj)
+{
+ ++format; // consume format code
+ if (!obj)
+ return true; // suppressed, okay
+ if (CFGetTypeID(obj) != CFNumberGetTypeID())
+ return false;
+ store<Value>(cfNumber<Value>(CFNumberRef(obj)));
+ return true;
+}
+
+
+//
+// Process % scan forms.
+// This delivers the object value, scanf-style, somehow.
+//
+bool CFScan::scanformat(CFTypeRef obj)
+{
+ switch (*++format) {
+ case F_OBJECT:
+ store<CFTypeRef>(obj);
+ return true;
+ case F_ARRAY: // %a*
+ return typescan(obj, CFArrayGetTypeID()) == done;
+ case F_BOOLEAN:
+ if (Typescan rc = typescan(obj, CFBooleanGetTypeID()))
+ return rc == done;
+ switch (*format) {
+ case 'f': // %Bf - two arguments (value, &variable)
+ {
+ unsigned flag = va_arg(args, unsigned);
+ unsigned *value = va_arg(args, unsigned *);
+ if (obj == kCFBooleanTrue && !suppress)
+ *value |= flag;
+ return true;
+ }
+ default: // %b - CFBoolean as int boolean
+ store<int>(obj == kCFBooleanTrue);
+ return true;
+ }
+ case F_DICTIONARY:
+ return typescan(obj, CFDictionaryGetTypeID()) == done;
+ case 'd': // %d - int
+ return scannumber<int>(obj);
+ case F_NUMBER:
+ return typescan(obj, CFNumberGetTypeID()) == done;
+ case F_STRING:
+ case 's':
+ if (Typescan rc = typescan(obj, CFStringGetTypeID()))
+ return rc == done;
+ // %s
+ store<std::string>(cfString(CFStringRef(obj)));
+ return true;
+ case 'u':
+ return scannumber<unsigned int>(obj);
+ case F_DATA:
+ return typescan(obj, CFDataGetTypeID()) == done;
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+
+bool CFScan::scandictionary(CFDictionaryRef obj)
+{
+ ++format; // skip '{'
+ while (next() != '}') {
+ bool optional = next('?');
+ if (CFTypeRef key = make()) {
+ bool oldSuppress = suppress;
+ CFTypeRef elem = obj ? CFDictionaryGetValue(obj, key) : NULL;
+ if (elem || optional) {
+ suppress |= (elem == NULL);
+ if (next('=')) {
+ if (scan(elem)) {
+ suppress = oldSuppress; // restore
+ CFRelease(key);
+ continue;
+ }
+ }
+ }
+ CFRelease(key);
+ return false;
+ } else {
+ assert(false); // bad format
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool CFScan::scanarray(CFArrayRef obj)
+{
+ ++format; // skip '['
+ CFIndex length = CFArrayGetCount(obj);
+ for (int pos = 0; pos < length; ++pos) {
+ if (next() == ']')
+ return true;
+ if (!scan(CFArrayGetValueAtIndex(obj, pos)))
+ return false;
+ }
+ return false; // array length exceeded
+}
+
+
+//
+// Run down a "dictionary path", validating heavily.
+//
+CFTypeRef CFScan::dictpath(CFTypeRef obj)
+{
+ while (next()) { // while we've got more text
+ next('.'); // optional
+ if (obj == NULL || CFGetTypeID(obj) != CFDictionaryGetTypeID())
+ return NULL;
+ CFTypeRef key = make();
+ obj = CFDictionaryGetValue(CFDictionaryRef(obj), key);
+ CFRelease(key);
+ }
+ return obj;
+}
+
+
+//
+// The public functions
+//
+CFTypeRef cfmake(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ CFTypeRef result = CFMake(format, args).make();
+ va_end(args);
+ return result;
+}
+
+CFTypeRef vcfmake(const char *format, va_list args)
+{
+ return CFMake(format, args).make();
+}
+
+CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ CFDictionaryRef result = CFMake(format, args).addto(dict);
+ va_end(args);
+ return result;
+}
+
+
+bool cfscan(CFTypeRef obj, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ bool result = vcfscan(obj, format, args);
+ va_end(args);
+ return result;
+}
+
+bool vcfscan(CFTypeRef obj, const char *format, va_list args)
+{
+ return CFScan(format, args).scan(obj);
+}
+
+
+CFTypeRef cfget(CFTypeRef obj, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ CFTypeRef result = vcfget(obj, format, args);
+ va_end(args);
+ return result;
+}
+
+CFTypeRef vcfget(CFTypeRef obj, const char *format, va_list args)
+{
+ return CFScan(format, args).dictpath(obj);
+}
+
+} // end namespace Security
--- /dev/null
+/*
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+// CoreFoundation building and parsing functions
+//
+#ifndef _H_CFMUNGE
+#define _H_CFMUNGE
+
+#include <security_utilities/cfutilities.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <cstdarg>
+
+namespace Security {
+
+
+//
+// Common interface to Mungers.
+// A CFMunge provides a one-pass, non-resettable scan through a format string,
+// performing various actions on the way.
+//
+class CFMunge {
+public:
+ CFMunge(const char *fmt, va_list arg);
+ ~CFMunge();
+
+protected:
+ char next();
+ bool next(char c);
+
+ bool parameter();
+
+protected:
+ const char *format;
+ va_list args;
+ CFAllocatorRef allocator;
+ OSStatus error;
+};
+
+
+//
+// A CFMake is a CFMunge for making CF data structures.
+//
+class CFMake : public CFMunge {
+public:
+ CFMake(const char *fmt, va_list arg) : CFMunge(fmt, arg) { }
+
+ CFTypeRef make();
+ CFDictionaryRef addto(CFMutableDictionaryRef dict);
+
+protected:
+ CFTypeRef makedictionary();
+ CFTypeRef makearray();
+ CFTypeRef makenumber();
+ CFTypeRef makestring();
+ CFTypeRef makeformat();
+ CFTypeRef makespecial();
+
+ CFDictionaryRef add(CFMutableDictionaryRef dict);
+};
+
+
+//
+// Make a CF object following a general recipee
+//
+CFTypeRef cfmake(const char *format, ...);
+CFTypeRef vcfmake(const char *format, va_list args);
+
+template <class CFType>
+CFType cfmake(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ CFType result = CFType(vcfmake(format, args));
+ va_end(args);
+ return result;
+}
+
+CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...);
+
+
+//
+// Parse out parts of a CF object following a general recipe.
+// Cfscan returns false on error; cfget throws.
+//
+bool cfscan(CFTypeRef source, const char *format, ...);
+bool vcfscan(CFTypeRef source, const char *format, va_list args);
+
+CFTypeRef cfget(CFTypeRef source, const char *format, ...);
+CFTypeRef vcfget(CFTypeRef source, const char *format, va_list args);
+
+template <class CFType>
+CFType cfget(CFTypeRef source, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ CFType result = CFType(vcfget(source, format, args));
+ va_end(args);
+ return CFTraits<CFType>::check(result) ? result : NULL;
+}
+
+template <class CFType>
+class CFTemp : public CFRef<CFType> {
+public:
+ CFTemp(const char *format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ this->take(CFType(vcfmake(format, args)));
+ va_end(args);
+ }
+};
+
+
+} // end namespace Security
+
+#endif //_H_CFMUNGE
// codedirectory - format and operations for code signing "code directory" structures
//
#include "codedirectory.h"
-#include "csutilities.h"
-#include "CSCommonPriv.h"
+#include "CSCommon.h"
using namespace UnixPlusPlus;
return cdComponentPerArchitecture; // raw
case cdEntitlementSlot:
return cdComponentIsBlob; // global
- case cdIdentificationSlot:
- return cdComponentPerArchitecture; // raw
default:
return 0; // global, raw
}
"info",
"requirements",
"resources",
- "application",
- "entitlement"
+ "application"
};
#endif //NDEBUG
//
-// Check a CodeDirectory for basic integrity. This should ensure that the
-// version is understood by our code, and that the internal structure
-// (offsets etc.) is intact. In particular, it must make sure that no offsets
-// point outside the CodeDirectory.
+// Check the version of this CodeDirectory for basic sanity.
// Throws if the directory is corrupted or out of versioning bounds.
// Returns if the version is usable (perhaps with degraded features due to
// compatibility hacks).
//
-// Note: There are some things we don't bother checking because they won't
-// cause crashes, and will just be flagged as nonsense later. For example,
-// a Bad Guy could overlap the identifier and hash fields, which is nonsense
-// but not dangerous.
-//
-void CodeDirectory::checkIntegrity() const
+void CodeDirectory::checkVersion() const
{
- // check version for support
if (!this->validateBlob())
MacOSError::throwMe(errSecCSSignatureInvalid); // busted
if (version > compatibilityLimit)
MacOSError::throwMe(errSecCSSignatureUnsupported); // too new - no clue
- if (version < earliestVersion)
- MacOSError::throwMe(errSecCSSignatureUnsupported); // too old - can't support
if (version > currentVersion)
secdebug("codedir", "%p version 0x%x newer than current 0x%x",
this, uint32_t(version), currentVersion);
-
- // now check interior offsets for validity
- if (!stringAt(identOffset))
- MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range
- if (!contains(hashOffset - hashSize * nSpecialSlots, hashSize * (nSpecialSlots + nCodeSlots)))
- MacOSError::throwMe(errSecCSSignatureFailed); // hash array out of blob range
- if (const Scatter *scatter = this->scatterVector()) {
- // the optional scatter vector is terminated with an element having (count == 0)
- unsigned int pagesConsumed = 0;
- while (scatter->count) {
- if (!contains(scatter, sizeof(Scatter)))
- MacOSError::throwMe(errSecCSSignatureFailed);
- pagesConsumed += scatter->count;
- scatter++;
- }
- if (!contains(scatter, sizeof(Scatter))) // (even sentinel must be in range)
- MacOSError::throwMe(errSecCSSignatureFailed);
- if (!contains((*this)[pagesConsumed-1], hashSize)) // referenced too many main hash slots
- MacOSError::throwMe(errSecCSSignatureFailed);
- }
}
//
size_t CodeDirectory::hash(FileDesc fd, Hash::Byte *digest, size_t limit)
{
- SHA1 hasher;
- size_t size = hashFileData(fd, hasher, limit);
- hasher.finish(digest);
- return size;
+ IFDEBUG(size_t hpos = fd.position());
+ IFDEBUG(size_t hlimit = limit);
+ unsigned char buffer[4096];
+ Hash hash;
+ size_t total = 0;
+ for (;;) {
+ size_t size = sizeof(buffer);
+ if (limit && limit < size)
+ size = limit;
+ size_t got = fd.read(buffer, size);
+ total += got;
+ if (fd.atEnd())
+ break;
+ hash(buffer, got);
+ if (limit && (limit -= got) == 0)
+ break;
+ }
+ hash.finish(digest);
+ secdebug("cdhash", "fd %d %zd@0x%zx => %2x.%2x.%2x...",
+ fd.fd(), hpos, hlimit, digest[0], digest[1], digest[2]);
+ return total;
}
}
-} // CodeSigning
-} // Security
-
-
//
-// Canonical text form for user-settable code directory flags.
-// Note: This table is actually exported from Security.framework.
+// Canonical text form for user-settable code directory flags
//
-const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[] = {
+const CodeDirectory::FlagItem CodeDirectory::flagItems[] = {
{ "host", kSecCodeSignatureHost, true },
{ "adhoc", kSecCodeSignatureAdhoc, false },
{ "hard", kSecCodeSignatureForceHard, true },
{ "expires", kSecCodeSignatureForceExpiration, true },
{ NULL }
};
+
+
+//
+// Parse a canonical text description of code flags, in the form
+// flag,...,flag
+// where each flag can be a prefix of a known flag name.
+// Internally set flags are not accepted.
+//
+uint32_t CodeDirectory::textFlags(std::string text)
+{
+ uint32_t flags = 0;
+ for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) {
+ string word = (comma == string::npos) ? text : text.substr(0, comma);
+ const CodeDirectory::FlagItem *item;
+ for (item = CodeDirectory::flagItems; item->name; item++)
+ if (item->external && !strncmp(word.c_str(), item->name, word.size())) {
+ flags |= item->value;
+ break;
+ }
+ if (!item) // not found
+ MacOSError::throwMe(errSecCSInvalidFlags);
+ if (comma == string::npos) // last word
+ break;
+ }
+ return flags;
+}
+
+
+} // CodeSigning
+} // Security
// indices. This enumeration is also used widely in various internal APIs, and as
// type values in embedded SuperBlobs.
//
-// How to add a slot code:
-// 1. Add the new name into the primary or virtual slot array at the end (below).
-// 2a. For slots representing existing code pieces, follow the ball for cdInfoSlot.
-// 2b. For slots representing global signature components, follow the ball for cdResourceDirSlot.
-// 2c. For slots representing per-architecture signature components, follow the ball for cdEntitlementSlot.
-// ("Follow the ball" -> Global search for that name and do likewise.)
-//
enum {
//
// Primary slot numbers.
// (add further primary slot numbers here)
cdSlotCount, // total number of special slots (+1 for slot 0)
- cdSlotMax = cdSlotCount - 1, // highest special slot number (as a positive number)
+ cdSlotMax = cdSlotCount - 1, // highest special slot number
//
// Virtual slot numbers.
// These values are NOT used in the CodeDirectory hash array. The are used as
- // internal API identifiers and as types in SuperBlobs.
+ // internal API identifiers and as types in in-image SuperBlobs.
// Zero is okay to use here; and we assign that to the CodeDirectory itself so
// it shows up first in (properly sorted) SuperBlob indices. The rest of the
// numbers is set Far Away so the primary slot set can expand safely.
//
cdCodeDirectorySlot = 0, // CodeDirectory
cdSignatureSlot = 0x10000, // CMS signature
- cdIdentificationSlot, // identification blob
// (add further virtual slot numbers here)
};
// an error. (Thus the range of special slots can be extended at will.)
//
// HOW TO MANAGE COMPATIBILITY:
-// Each CodeDirectory has a format (compatibility) version. Two constants control
+// Each CodeDirectory has a format (compatibility) version. Three constants control
// versioning:
// * currentVersion is the version used for newly created CodeDirectories.
// * compatibilityLimit is the highest version the code will accept as compatible.
// Test for version < currentVersion to detect old formats that may need special
-// handling. The current code rejects those; add backward cases to checkValidity().
+// handling. The current code rejects those; add backward cases to checkVersion().
// Break backward compatibility by rejecting versions that are unsuitable.
// Accept currentVersion < version <= compatibilityLimit as versions newer than
// those understood by this code but engineered (by newer code) to be backward
// When creating a new version, increment currentVersion. When adding new fixed fields,
// just append them; the flex fields will shift to make room. To add new flex fields,
// add a fixed field containing the new field's offset and add suitable computations
-// to the Builder to place the new data (right) before the hash array. Remember to check
-// for offset in-range in checkIntegrity(). Older code will then simply ignore your
-// new fields on load/read.
+// to the Builder to place the new data (right) before the hash array. Older code will
+// then simply ignore your new fields on load/read.
// Add flag bits to the existing flags field to add features that step outside
// of the linear versioning stream. Leave the 'spare' fields alone unless you need
// something extraordinarily weird - they're meant to be the final escape when everything
uint8_t spare1; // unused (must be zero)
uint8_t pageSize; // log2(page size in bytes); 0 => infinite
Endian<uint32_t> spare2; // unused (must be zero)
- Endian<uint32_t> scatterOffset; // offset of optional scatter vector
// works with the version field; see comments above
- static const uint32_t currentVersion = 0x20100; // "version 2.1"
+ static const uint32_t currentVersion = 0x20001; // "version 2"
static const uint32_t compatibilityLimit = 0x2F000; // "version 3 with wiggle room"
- static const uint32_t earliestVersion = 0x20001; // earliest supported version
- static const uint32_t supportsScatter = 0x20100; // first version to support scatter option
-
- void checkIntegrity() const; // throws if inconsistent or unsupported version
+ void checkVersion() const; // throws if not compatible with this code
typedef int Slot; // slot index (negative for special slots)
typedef unsigned int SpecialSlot; // positive special slot index (not for code slots)
return at<unsigned char>(hashOffset) + hashSize * slot;
}
- struct Scatter {
- Endian<uint32_t> count; // number of pages; zero for sentinel (only)
- Endian<uint32_t> base; // first page number
- Endian<uint64_t> targetOffset; // offset in target
- Endian<uint64_t> spare; // reserved
- };
- Scatter *scatterVector() // first scatter vector element (NULL if none)
- { return (version >= supportsScatter && scatterOffset) ? at<Scatter>(scatterOffset) : NULL; }
- const Scatter *scatterVector() const
- { return (version >= supportsScatter && scatterOffset) ? at<const Scatter>(scatterOffset) : NULL; }
-
-public:
bool validateSlot(const void *data, size_t size, Slot slot) const;
bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const;
bool slotIsPresent(Slot slot) const;
static const char *canonicalSlotName(SpecialSlot slot);
static unsigned slotAttributes(SpecialSlot slot);
IFDEBUG(static const char * const debugSlotName[]);
+
+public:
+ //
+ // Canonical text forms for (only) the user-settable flags
+ //
+ struct FlagItem {
+ const char *name;
+ uint32_t value;
+ bool external;
+ };
+ static const FlagItem flagItems[]; // terminated with NULL item
+
+ static uint32_t textFlags(std::string text);
};
// cs.h - code signing core header
//
#include "cs.h"
-#include <security_utilities/cfmunge.h>
+#include "cfmunge.h"
namespace Security {
namespace CodeSigning {
ModuleNexus<CFObjects> gCFObjects;
CFObjects::CFObjects()
- : Code("SecCode"),
- StaticCode("SecStaticCode"),
- Requirement("SecRequirements"),
- CodeSigner("SecCodeSigner")
+ : Code("SecCode", false),
+ StaticCode("SecStaticCode", false),
+ Requirement("SecRequirements", false),
+ CodeSigner("SecCodeSigner", false)
{
}
-OSStatus dbError(const SQLite3::Error &err)
-{
- switch (err.error) {
- case SQLITE_PERM:
- case SQLITE_READONLY:
- case SQLITE_AUTH:
- return errSecCSSigDBDenied;
- case SQLITE_CANTOPEN:
- case SQLITE_EMPTY:
- case SQLITE_NOTADB:
- return errSecCSSigDBAccess;
- default:
- return SecKeychainErrFromOSStatus(err.osStatus());
- }
-}
-
-
} // CodeSigning
} // Security
#define _H_CS
#include "cserror.h"
-#include "codesigning_dtrace.h"
-#include <Security/CSCommonPriv.h>
-#include <Security/SecCodePriv.h>
-#include <Security/SecStaticCodePriv.h>
-#include <Security/SecRequirementPriv.h>
+#include <Security/CodeSigning.h>
#include <Security/SecCodeSigner.h>
#include <Security/SecBasePriv.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <security_utilities/seccfobject.h>
#include <security_utilities/cfclass.h>
#include <security_utilities/errors.h>
-#include <security_utilities/sqlite++.h>
#include <security_utilities/cfutilities.h>
static inline SecCSFlags apiFlags() { return gCFObjects().flags(); }
-OSStatus dbError(const SQLite3::Error &err);
-
//
// Code Signing API brackets
default: return err.osStatus(); \
}} \
catch (const MacOSError &err) { return err.osStatus(); } \
- catch (const SQLite3::Error &err) { return dbError(err); } \
catch (const CommonError &err) { return SecKeychainErrFromOSStatus(err.osStatus()); } \
catch (const std::bad_alloc &) { return memFullErr; } \
- catch (...) { return errSecCSInternalError; } \
+ catch (...) { return internalComponentErr; } \
return noErr;
#define END_CSAPI_ERRORS \
default: return CSError::cfError(errors, err.osStatus()); \
}} \
catch (const MacOSError &err) { return CSError::cfError(errors, err.osStatus()); } \
- catch (const SQLite3::Error &err) { return CSError::cfError(errors, dbError(err)); } \
catch (const CommonError &err) { return CSError::cfError(errors, SecKeychainErrFromOSStatus(err.osStatus())); } \
catch (const std::bad_alloc &) { return CSError::cfError(errors, memFullErr); } \
- catch (...) { return CSError::cfError(errors, errSecCSInternalError); } \
+ catch (...) { return CSError::cfError(errors, internalComponentErr); } \
return noErr;
#define END_CSAPI1(bad) } catch (...) { return bad; }
}
-//
-// DTrace USDT function bracket.
-// Use like this:
-// DTRACK(PROVIDER_PROBE_PREFIX, arguments-after-this);
-// which will call
-// PROVIDER_PROBE_PREFIX_START(this, arguments-after-this)
-// and
-// PROVIDER_PROBE_PREFIX_END(this)
-//
-#define DTRACK(_prefix, _obj, _args...) \
- if (_prefix ## _START_ENABLED()) _prefix ## _START((_obj), ## _args); \
- struct _DTFrame ## _prefix { void *me; \
- _DTFrame ## _prefix(void *m) : me(m) { } \
- ~_DTFrame ## _prefix() { _prefix ## _END(me); } \
- } _dtframe##_prefix((_obj));
-
-
} // CodeSigning
} // Security
+++ /dev/null
-/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-//
-// csdb - system-supported Code Signing related database interfaces
-//
-#include "csdatabase.h"
-#include "detachedrep.h"
-
-namespace Security {
-namespace CodeSigning {
-
-using namespace SQLite;
-
-
-//
-// The one and only SignatureDatabase object.
-// It auto-adapts to readonly vs. writable use.
-//
-ModuleNexus<SignatureDatabase> signatureDatabase;
-
-
-//
-// Default path to the signature database.
-//
-const char SignatureDatabase::defaultPath[] = "/var/db/DetachedSignatures";
-
-
-//
-// Creation commands to initialize the system database.
-//
-const char schema[] = "\
- create table if not exists code ( \n\
- id integer primary key on conflict replace autoincrement not null, \n\
- global integer null references global (id), \n\
- identifier text not null, \n\
- architecture integer, \n\
- identification blob not null unique on conflict replace, \n\
- signature blob not null, \n\
- created text default current_timestamp \n\
- ); \n\
- create index if not exists identifier_index on code (identifier); \n\
- create index if not exists architecture_index on code (architecture); \n\
- create index if not exists id_index on code (identification); \n\
- \n\
- create table if not exists global ( \n\
- id integer primary key on conflict replace autoincrement not null, \n\
- sign_location text not null, \n\
- signature blob null \n\
- ); \n\
- create index if not exists location_index on global (sign_location); \n\
-";
-
-
-
-//
-// Open the database (creating it if necessary and possible).
-// Note that this isn't creating the schema; we do that on first write.
-//
-SignatureDatabase::SignatureDatabase(const char *path, int flags)
- : SQLite::Database(path, flags)
-{
-}
-
-SignatureDatabase::~SignatureDatabase()
-{ /* virtual */ }
-
-
-//
-// Consult the database to find code by identification blob.
-// Return the signature and (optional) global data blobs.
-//
-FilterRep *SignatureDatabase::findCode(DiskRep *rep)
-{
- if (CFRef<CFDataRef> identification = rep->identification())
- if (!this->empty()) {
- SQLite::Statement query(*this,
- "select code.signature, global.signature from code, global \
- where code.identification = ?1 and code.global = global.id;");
- query.bind(1) = identification.get();
- if (query.nextRow())
- return new DetachedRep(query[0].data(), query[1].data(), rep, "system");
- }
-
- // no joy
- return NULL;
-}
-
-
-//
-// Given a unified detached signature blob, store its data in the database.
-// This writes exactly one Global record, plus one Code record per architecture
-// (where non-architectural code is treated as single-architecture).
-//
-void SignatureDatabase::storeCode(const BlobCore *sig, const char *location)
-{
- Transaction xa(*this, Transaction::exclusive); // lock out everyone
- if (this->empty())
- this->execute(schema); // initialize schema
- if (const EmbeddedSignatureBlob *esig = EmbeddedSignatureBlob::specific(sig)) { // architecture-less
- int64 globid = insertGlobal(location, NULL);
- insertCode(globid, 0, esig);
- xa.commit();
- return;
- } else if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sig)) {
- int64 globid = insertGlobal(location, dsblob->find(0));
- unsigned count = dsblob->count();
- for (unsigned n = 0; n < count; n++)
- if (uint32_t arch = dsblob->type(n))
- insertCode(globid, arch, EmbeddedSignatureBlob::specific(dsblob->blob(n)));
- xa.commit();
- return;
- }
-
- MacOSError::throwMe(errSecCSSignatureInvalid);
-
-}
-
-int64 SignatureDatabase::insertGlobal(const char *location, const BlobCore *blob)
-{
- Statement insert(*this, "insert into global (sign_location, signature) values (?1, ?2);");
- insert.bind(1) = location;
- if (blob)
- insert.bind(2).blob(blob, blob->length(), true);
- insert();
- return lastInsert();
-}
-
-void SignatureDatabase::insertCode(int64 globid, int arch, const EmbeddedSignatureBlob *sig)
-{
- // retrieve binary identifier (was added by signer)
- const BlobWrapper *ident = BlobWrapper::specific(sig->find(cdIdentificationSlot));
- assert(ident);
-
- // extract CodeDirectory to get some information from it
- const CodeDirectory *cd = CodeDirectory::specific(sig->find(cdCodeDirectorySlot));
- assert(cd);
-
- // write the record
- Statement insert(*this,
- "insert into code (global, identifier, architecture, identification, signature) values (?1, ?2, ?3, ?4, ?5);");
- insert.bind(1) = globid;
- insert.bind(2) = cd->identifier();
- if (arch)
- insert.bind(3) = arch;
- insert.bind(4).blob(ident->data(), ident->length(), true);
- insert.bind(5).blob(sig, sig->length(), true);
- insert();
-}
-
-
-
-} // end namespace CodeSigning
-} // end namespace Security
+++ /dev/null
-/*
- * Copyright (c) 2007 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-//
-// csdb - system-supported Code Signing related database interfaces
-//
-#ifndef _H_CSDATABASE
-#define _H_CSDATABASE
-
-#include "diskrep.h"
-#include "sigblob.h"
-#include <Security/Security.h>
-#include <security_utilities/globalizer.h>
-#include <security_utilities/sqlite++.h>
-#include <security_utilities/cfutilities.h>
-
-
-namespace Security {
-namespace CodeSigning {
-
-namespace SQLite = SQLite3;
-
-
-class SignatureDatabase : public SQLite::Database {
-public:
- SignatureDatabase(const char *path = defaultPath,
- int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
- virtual ~SignatureDatabase();
-
- FilterRep *findCode(DiskRep *rep);
- void storeCode(const BlobCore *sig, const char *location);
-
-private:
- SQLite::int64 insertGlobal(const char *location, const BlobCore *blob);
- void insertCode(SQLite::int64 globid, int arch, const EmbeddedSignatureBlob *sig);
-
-public:
- static const char defaultPath[];
-};
-
-
-extern ModuleNexus<SignatureDatabase> signatureDatabase;
-
-
-} // end namespace CodeSigning
-} // end namespace Security
-
-#endif // !_H_CSDATABASE
// cserror.h - extended-diagnostics Code Signing errors
//
#include "cs.h"
-#include <security_utilities/cfmunge.h>
+#include "cfmunge.h"
namespace Security {
namespace CodeSigning {
mach_port_t subport;
CALL(host, findGuest, guestRef(), attrPtr, attrLength,
&guestPath, &guestPathLength, &subport);
- CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport);
+ secdebug("genericcode", "%p found guest chain length=%d",
+ this, guestPathLength);
SecPointer<SecCode> code = this;
for (unsigned n = 0; n < guestPathLength; n++)
code = new GenericCode(code, guestPath[n]);
//
-// Identify a guest by returning its StaticCode and running CodeDirectory hash.
+// Map a guest to its StaticCode.
// This uses cshosting RPCs to ask the host (or its proxy).
//
-SecStaticCode *GenericCode::identifyGuest(SecCode *guest, CFDataRef *cdhashOut)
-{
- if (GenericCode *iguest = dynamic_cast<GenericCode *>(guest)) {
- FilePathOut path;
- CFRef<CFDataRef> cdhash;
- CFDictionary attributes(errSecCSHostProtocolInvalidAttribute);
- identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref());
- DiskRep::Context ctx;
- if (CFNumberRef architecture = attributes.get<CFNumberRef>(kSecGuestAttributeArchitecture)) {
- cpu_type_t cpu = cfNumber<cpu_type_t>(architecture);
- if (CFNumberRef subarchitecture = attributes.get<CFNumberRef>(kSecGuestAttributeSubarchitecture))
- ctx.arch = Architecture(cpu, cfNumber<cpu_subtype_t>(subarchitecture));
- else
- ctx.arch = Architecture(cpu);
- }
- SecPointer<GenericStaticCode> code = new GenericStaticCode(DiskRep::bestGuess(path, &ctx));
- CODESIGN_GUEST_IDENTIFY_GENERIC(iguest, iguest->guestRef(), code);
- if (cdhash) {
- CODESIGN_GUEST_CDHASH_GENERIC(iguest, (void *)CFDataGetBytePtr(cdhash), CFDataGetLength(cdhash));
- *cdhashOut = cdhash.yield();
- }
- return code.yield();
- } else
- MacOSError::throwMe(errSecCSNotAHost);
-}
-
-// helper to drive the identifyGuest hosting IPC and return results as CF objects
-void GenericCode::identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes)
+SecStaticCode *GenericCode::mapGuestToStatic(SecCode *guest)
{
if (Port host = hostingPort()) {
- HashDataOut hash;
- uint32_t hashLength;
- XMLBlobOut attr;
- uint32_t attrLength;
- CALL(host, identifyGuest, guest, path, hash, &hashLength, &attr, &attrLength);
- if (hashLength)
- cdhash = makeCFData(hash, hashLength);
- if (attrLength) {
- CFRef<CFDataRef> attrData = makeCFData(attr, attrLength);
- attributes = makeCFDictionaryFrom(attrData);
-#if ROSETTA_TEST_HACK
- CFMutableDictionaryRef hattr = makeCFMutableDictionary(attributes);
- CFDictionaryAddValue(hattr, kSecGuestAttributeArchitecture, CFTempNumber(CPU_TYPE_POWERPC));
- CFRelease(attributes);
- attributes = hattr;
-#endif
- }
+ char path[MAXPATHLEN];
+ CALL(host, guestPath, safe_cast<GenericCode *>(guest)->guestRef(), path);
+ return (new GenericStaticCode(DiskRep::bestGuess(path)))->retain();
} else
MacOSError::throwMe(errSecCSNotAHost);
}
// Get the Code Signing Status Word for a Code.
// This uses cshosting RPCs to ask the host (or its proxy).
//
-SecCodeStatus GenericCode::getGuestStatus(SecCode *guest)
+uint32_t GenericCode::getGuestStatus(SecCode *guest)
{
if (Port host = hostingPort()) {
uint32_t status;
}
-//
-// Status changes are transmitted through the cshosting RPCs.
-//
-void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
-{
- if (GenericCode *guest = dynamic_cast<GenericCode *>(iguest))
- switch (operation) {
- case kSecCodeOperationNull:
- break;
- case kSecCodeOperationInvalidate:
- case kSecCodeOperationSetHard:
- case kSecCodeOperationSetKill:
- MacOSError::throwMe(errSecCSUnimplemented);
- break;
- default:
- MacOSError::throwMe(errSecCSInvalidOperation);
- }
- else
- MacOSError::throwMe(errSecCSNoSuchCode);
-}
-
-
//
// Return the Hosting Port for this Code.
// May return MACH_PORT_NULL if the code is not a code host.
Port GenericCode::hostingPort()
{
if (!mHostingPort) {
- if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost) {
+ if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost)
mHostingPort = getHostingPort();
- CODESIGN_GUEST_HOSTINGPORT(this, mHostingPort);
- }
}
return mHostingPort;
}
GenericCode(SecCode *host, SecGuestRef guestRef = kSecNoGuest);
SecCode *locateGuest(CFDictionaryRef attributes);
- SecStaticCode *identifyGuest(SecCode *guest, CFDataRef *cdhash);
- SecCodeStatus getGuestStatus(SecCode *guest);
- void changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments);
+ SecStaticCode *mapGuestToStatic(SecCode *guest);
+ uint32_t getGuestStatus(SecCode *guest);
SecGuestRef guestRef() const { return mGuestRef; }
protected:
MachPlusPlus::Port hostingPort();
+
virtual mach_port_t getHostingPort();
-
-private:
- void identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes);
private:
MachPlusPlus::Port mHostingPort; // cached hosting port for this Code
*/
//
-// cskernel - Kernel implementation of the Code Signing Host Interface.
-//
-// The kernel host currently supports only UNIX processes as guests.
-// It tracks then by their pid. Perhaps one day we'll get a more stable
-// means of tracking processes that doesn't involve reusing identifiers.
-//
-// The kernel host could represent non-process guests one day. One candidate
-// are Kernel Extensions.
+// cskernel - Kernel implementation of the Code Signing Host Interface
//
#include "cskernel.h"
#include "csprocess.h"
#include "kerneldiskrep.h"
-#include "machorep.h"
#include <libproc.h>
#include <sys/codesign.h>
#include <sys/param.h> // MAXPATHLEN
//
-// Identify our guests (UNIX processes) by attribute.
-// The only supported lookup attribute is currently the pid. (We could support
-// task ports, but those can easily be mapped to pids.)
-// Note that we don't actually validate the pid here; if it's invalid, we'll notice
-// when we try to ask the kernel about it later.
+// We locate a guest (process) by invoking a kernel service.
+// The only attributes supported are ("pid", pid_t).
+// (We could also support task ports if we liked, but those can be translated
+// to pids by the caller without trouble.)
//
SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
{
//
// We map guests to disk by calling a kernel service.
-// It is here that we verify that our user-space concept of the code identity
-// matches the kernel's idea (to defeat just-in-time switching attacks).
//
-SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash)
+SecStaticCode *KernelCode::mapGuestToStatic(SecCode *iguest)
{
if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
char path[2 * MAXPATHLEN]; // reasonable upper limit
- if (::proc_pidpath(guest->pid(), path, sizeof(path))) {
- off_t offset;
- csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset));
- SecPointer<SecStaticCode> code = new ProcessStaticCode(DiskRep::bestGuess(path, offset));
- CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code);
- if (cdhash) {
- SHA1::Digest kernelHash;
- if (::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1)
- switch (errno) {
- case EBADEXEC: // means "no CodeDirectory hash for this program"
- *cdhash = NULL;
- break;
- case ESRCH:
- MacOSError::throwMe(errSecCSNoSuchCode);
- default:
- UnixError::throwMe();
- }
- else // succeeded
- *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
- CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash));
- }
- return code.yield();
- } else
+ if (::proc_pidpath(guest->pid(), path, sizeof(path)))
+ return (new ProcessStaticCode(DiskRep::bestGuess(path)))->retain();
+ else
UnixError::throwMe();
}
MacOSError::throwMe(errSecCSNoSuchCode);
//
// We obtain the guest's status by asking the kernel
//
-SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
+uint32_t KernelCode::getGuestStatus(SecCode *iguest)
{
if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
uint32_t pFlags;
- csops(guest, CS_OPS_STATUS, &pFlags);
+ if (::csops(guest->pid(), CS_OPS_STATUS, &pFlags, 0) == -1) {
+ secdebug("kcode", "cannot get guest status of %p(%d) errno=%d",
+ guest, guest->pid(), errno);
+ switch (errno) {
+ case ESRCH:
+ MacOSError::throwMe(errSecCSNoSuchCode);
+ default:
+ UnixError::throwMe();
+ }
+ }
secdebug("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
+
+#if defined(USERSPACE_VALIDATION)
+ // Former static substitute for dynamic kernel validation of executable pages.
+ // This is now done in the kernel's page-in path.
+ guest->staticCode()->validateExecutable();
+#endif //USERSPACE_VALIDATION
+
return pFlags;
} else
MacOSError::throwMe(errSecCSNoSuchCode);
}
-//
-// We tell the kernel to make status changes
-//
-void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
-{
- if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest))
- switch (operation) {
- case kSecCodeOperationNull:
- break;
- case kSecCodeOperationInvalidate:
- csops(guest, CS_OPS_MARKINVALID);
- break;
- case kSecCodeOperationSetHard:
- csops(guest, CS_OPS_MARKHARD);
- break;
- case kSecCodeOperationSetKill:
- csops(guest, CS_OPS_MARKKILL);
- break;
- default:
- MacOSError::throwMe(errSecCSInvalidOperation);
- }
- else
- MacOSError::throwMe(errSecCSNoSuchCode);
-}
-
-
//
// The StaticCode for the running kernel is explicit.
// We can't ask our own host for it, naturally.
//
-void KernelCode::identify()
+SecStaticCode *KernelCode::getStaticCode()
{
- mStaticCode.take(globals().staticCode->retain());
- // the kernel isn't currently signed, so we don't get a cdHash for it
-}
-
-
-//
-// Interface to kernel csops() system call.
-//
-void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length)
-{
- if (::csops(proc->pid(), op, addr, length) == -1) {
- switch (errno) {
- case ESRCH:
- MacOSError::throwMe(errSecCSNoSuchCode);
- default:
- UnixError::throwMe();
- }
- }
+ return globals().staticCode->retain();
}
namespace CodeSigning {
-class ProcessCode;
-
-
//
// The nominal StaticCode representing the kernel on disk.
// This is barely used, since we don't validate the kernel (it's the root of trust)
KernelCode();
SecCode *locateGuest(CFDictionaryRef attributes);
- SecStaticCode *identifyGuest(SecCode *guest, CFDataRef *cdhash);
- SecCodeStatus getGuestStatus(SecCode *guest);
- void changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments);
+ SecStaticCode *mapGuestToStatic(SecCode *guest);
+ uint32_t getGuestStatus(SecCode *guest);
static KernelCode *active() { return globals().code; }
static ModuleNexus<Globals> globals;
protected:
- void identify();
- void csops(ProcessCode *proc, unsigned int op, void *addr = NULL, size_t length = 0);
+ SecStaticCode *getStaticCode();
+
+private:
};
}
-//
-// Calculate hashes of (a section of) a file.
-// Starts at the current file position.
-// Extends to end of file, or (if limit > 0) at most limit bytes.
-//
-size_t hashFileData(const char *path, SHA1 &hasher)
-{
- UnixPlusPlus::AutoFileDesc fd(path);
- return hashFileData(fd, hasher);
-}
-
-size_t hashFileData(UnixPlusPlus::FileDesc fd, SHA1 &hasher, size_t limit /* = 0 */)
-{
- unsigned char buffer[4096];
- size_t total = 0;
- for (;;) {
- size_t size = sizeof(buffer);
- if (limit && limit < size)
- size = limit;
- size_t got = fd.read(buffer, size);
- total += got;
- if (fd.atEnd())
- break;
- hasher(buffer, got);
- if (limit && (limit -= got) == 0)
- break;
- }
- return total;
-}
-
-
-
//
// Check to see if a certificate contains a particular field, by OID. This works for extensions,
// even ones not recognized by the local CL. It does not return any value, only presence.
}
-//
-// Copyfile
-//
-Copyfile::Copyfile()
-{
- if (!(mState = copyfile_state_alloc()))
- UnixError::throwMe();
-}
-
-void Copyfile::set(uint32_t flag, const void *value)
-{
- check(::copyfile_state_set(mState, flag, value));
-}
-
-void Copyfile::get(uint32_t flag, void *value)
-{
- check(::copyfile_state_set(mState, flag, value));
-}
-
-void Copyfile::operator () (const char *src, const char *dst, copyfile_flags_t flags)
-{
- check(::copyfile(src, dst, mState, flags));
-}
-
-void Copyfile::check(int rc)
-{
- if (rc < 0)
- UnixError::throwMe();
-}
-
-
} // end namespace CodeSigning
} // end namespace Security
#include <Security/Security.h>
#include <security_utilities/hashing.h>
-#include <security_utilities/unix++.h>
#include <security_cdsa_utilities/cssmdata.h>
-#include <copyfile.h>
+
namespace Security {
namespace CodeSigning {
void hashOfCertificate(SecCertificateRef cert, SHA1::Digest digest);
-//
-// Calculate hashes of (a section of) a file.
-// Starts at the current file position.
-// Extends to end of file, or (if limit > 0) at most limit bytes.
-// Returns number of bytes digested.
-//
-size_t hashFileData(const char *path, SHA1 &hasher);
-size_t hashFileData(UnixPlusPlus::FileDesc fd, SHA1 &hasher, size_t limit = 0);
-
-
//
// Check to see if a certificate contains a particular field, by OID. This works for extensions,
// even ones not recognized by the local CL. It does not return any value, only presence.
bool certificateHasField(SecCertificateRef cert, const CssmOid &oid);
-//
-// Encapsulation of the copyfile(3) API.
-// This is slated to go into utilities once stable.
-//
-class Copyfile {
-public:
- Copyfile();
- ~Copyfile() { copyfile_state_free(mState); }
-
- operator copyfile_state_t () const { return mState; }
-
- void set(uint32_t flag, const void *value);
- void get(uint32_t flag, void *value);
-
- void operator () (const char *src, const char *dst, copyfile_flags_t flags);
-
-private:
- void check(int rc);
-
-private:
- copyfile_state_t mState;
-};
-
-
-//
-// A reliable uid set/reset bracket
-//
-class UidGuard {
-public:
- UidGuard() : mPrevious(-1) { }
- UidGuard(uid_t uid) : mPrevious(-1) { seteuid(uid); }
- ~UidGuard()
- {
- if (active())
- UnixError::check(::seteuid(mPrevious));
- }
-
- bool seteuid(uid_t uid)
- {
- if (uid == geteuid())
- return true; // no change, don't bother the kernel
- if (!active())
- mPrevious = ::geteuid();
- return ::seteuid(uid) == 0;
- }
-
- bool active() const { return mPrevious != uid_t(-1); }
- operator bool () const { return active(); }
- uid_t saved() const { assert(active()); return mPrevious; }
-
-private:
- uid_t mPrevious;
-};
-
-
} // end namespace CodeSigning
} // end namespace Security
+++ /dev/null
-/*
- * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-//
-// detachedrep - prefix diskrep representing a detached signature stored in a file
-//
-#include "detachedrep.h"
-
-
-namespace Security {
-namespace CodeSigning {
-
-
-//
-// We construct a DetachedRep from the data blob of the detached signature
-// and a reference of the original DiskRep we chain to.
-// We accept an EmbeddedSignatureBlob (for a non-architected signature)
-// or a DetachedSignatureBlob (for architected signatures) that is a SuperBlob
-// of EmbeddedSignatureBlobs.
-//
-DetachedRep::DetachedRep(CFDataRef sig, DiskRep *orig, const std::string &source)
- : FilterRep(orig), mSig(sig), mSource(source)
-{
- const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
- if (sigBlob->is<EmbeddedSignatureBlob>()) { // architecture-less
- if (mArch = EmbeddedSignatureBlob::specific(sigBlob)) {
- mGlobal = NULL;
- CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), NULL);
- return;
- }
- } else if (sigBlob->is<DetachedSignatureBlob>()) // architecture collection
- if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sigBlob))
- if (Universal *fat = orig->mainExecutableImage())
- if (const BlobCore *blob = dsblob->find(fat->bestNativeArch().cpuType()))
- if (mArch = EmbeddedSignatureBlob::specific(blob))
- if (mGlobal = EmbeddedSignatureBlob::specific(dsblob->find(0))) {
- CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), (void*)mGlobal);
- return;
- }
- MacOSError::throwMe(errSecCSSignatureInvalid);
-}
-
-
-//
-// Here's a version to construct a DetachedRep if we already have the right architecture
-// and (optional) associated global blob. Just take them.
-//
-DetachedRep::DetachedRep(CFDataRef sig, CFDataRef gsig, DiskRep *orig, const std::string &source)
- : FilterRep(orig), mSig(sig), mGSig(gsig), mSource(source)
-{
- const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
- mArch = EmbeddedSignatureBlob::specific(sigBlob);
- if (!mArch)
- MacOSError::throwMe(errSecCSSignatureInvalid);
- if (gsig) {
- const BlobCore *gsigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(gsig));
- mGlobal = EmbeddedSignatureBlob::specific(gsigBlob);
- if (!mGlobal)
- MacOSError::throwMe(errSecCSSignatureInvalid);
- } else
- mGlobal = NULL;
- CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), (void*)mGlobal);
-}
-
-
-//
-// We look up components by first checking for a per-architecture item,
-// then for a global item in the detached signature, and finally falling
-// back on the original DiskRep (for static components).
-//
-CFDataRef DetachedRep::component(CodeDirectory::SpecialSlot slot)
-{
- if (CFDataRef result = mArch->component(slot))
- return result;
- if (mGlobal)
- if (CFDataRef result = mGlobal->component(slot))
- return result;
- return this->base()->component(slot);
-}
-
-
-} // end namespace CodeSigning
-} // end namespace Security
+++ /dev/null
-/*
- * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-//
-// detachedrep - prefix diskrep representing a detached signature stored in a file
-//
-#ifndef _H_DETACHEDREP
-#define _H_DETACHEDREP
-
-#include "diskrep.h"
-#include "sigblob.h"
-
-namespace Security {
-namespace CodeSigning {
-
-
-//
-// We use a DetachedRep to interpose (filter) the genuine DiskRep representing
-// the code on disk, *if* a detached signature was set on this object. In this
-// situation, mRep will point to a (2 element) chain of DiskReps.
-//
-// This is a neat way of dealing with the (unusual) detached-signature case
-// without disturbing things unduly. Consider DetachedDiskRep to be closely
-// married to SecStaticCode; it's unlikely to work right if you use it elsewhere.
-//
-// Note that there's no *writing* code here. Writing detached signatures is handled
-// specially in the signing code.
-//
-class DetachedRep : public FilterRep {
-public:
- DetachedRep(CFDataRef sig, DiskRep *orig, const std::string &source); // SuperBlob of all architectures
- DetachedRep(CFDataRef sig, CFDataRef gsig, DiskRep *orig, const std::string &source); // one architecture + globals
-
- CFDataRef component(CodeDirectory::SpecialSlot slot);
-
- const std::string &source() const { return mSource; }
-
-private:
- CFRef<CFDataRef> mSig, mGSig;
- const EmbeddedSignatureBlob *mArch; // current architecture; points into mSignature
- const EmbeddedSignatureBlob *mGlobal; // shared elements; points into mSignature
- std::string mSource; // source description (readable)
-};
-
-
-} // end namespace CodeSigning
-} // end namespace Security
-
-#endif // !_H_DETACHEDREP
#include "filediskrep.h"
#include "bundlediskrep.h"
#include "cfmdiskrep.h"
-#include "slcrep.h"
+#include "foreigndiskrep.h"
namespace Security {
}
DiskRep::~DiskRep()
-{
- CODESIGN_DISKREP_DESTROY(this);
-}
+{ /* virtual */ }
//
}
-void DiskRep::Writer::addDiscretionary(CodeDirectory::Builder &)
-{
- // do nothing
-}
-
-
//
// Given a file system path, come up with the most likely correct
// disk representation for what's there.
// fine in ordinary use. If you happen to know what you're looking at
// (say, a bundle), then just create the suitable subclass of DiskRep directly.
// That's quite legal.
-// The optional context argument can provide additional information that guides the guess.
//
-DiskRep *DiskRep::bestGuess(const char *path, const Context *ctx)
+DiskRep *DiskRep::bestGuess(const char *path)
{
try {
- if (!(ctx && ctx->fileOnly)) {
- struct stat st;
- if (::stat(path, &st))
- UnixError::throwMe();
-
- // if it's a directory, assume it's a bundle
- if ((st.st_mode & S_IFMT) == S_IFDIR) // directory - assume bundle
- return new BundleDiskRep(path, ctx);
-
- // see if it's the main executable of a recognized bundle
- if (CFRef<CFURLRef> pathURL = makeCFURL(path))
- if (CFRef<CFBundleRef> bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, pathURL))
- return new BundleDiskRep(bundle, ctx);
- }
+ struct stat st;
+ if (::stat(path, &st))
+ UnixError::throwMe();
- // try the various single-file representations
- AutoFileDesc fd(path, O_RDONLY);
- if (MachORep::candidate(fd))
- return new MachORep(path, ctx);
- if (CFMDiskRep::candidate(fd))
- return new CFMDiskRep(path);
- if (DYLDCacheRep::candidate(fd))
- return new DYLDCacheRep(path);
-
- // ultimate fallback - the generic file representation
- return new FileDiskRep(path);
-
+ // if it's a directory, assume it's a bundle
+ if ((st.st_mode & S_IFMT) == S_IFDIR) // directory - assume bundle
+ return new BundleDiskRep(path);
+
+ // see if it's the main executable of a recognized bundle
+ if (CFRef<CFURLRef> pathURL = makeCFURL(path))
+ if (CFRef<CFBundleRef> bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, pathURL))
+ return new BundleDiskRep(bundle);
+
+ // follow the file choosing rules
+ return bestFileGuess(path);
} catch (const CommonError &error) {
switch (error.unixError()) {
case ENOENT:
}
-DiskRep *DiskRep::bestFileGuess(const char *path, const Context *ctx)
+DiskRep *DiskRep::bestFileGuess(const char *path)
{
- Context dctx;
- if (ctx)
- dctx = *ctx;
- dctx.fileOnly = true;
- return bestGuess(path, &dctx);
-}
+ AutoFileDesc fd(path, O_RDONLY);
+ if (MachORep::candidiate(fd))
+ return new MachORep(path);
+ if (CFMDiskRep::candidiate(fd))
+ return new CFMDiskRep(path);
+ if (ForeignDiskRep::candidate(fd))
+ return new ForeignDiskRep(path);
-
-//
-// Given a main executable known to be a Mach-O binary, and an offset into
-// the file of the actual architecture desired (of a Universal file),
-// produce a suitable MachORep.
-// This function does not consider non-MachO binaries. It does however handle
-// bundles with Mach-O main executables correctly.
-//
-DiskRep *DiskRep::bestGuess(const char *path, size_t archOffset)
-{
- try {
- // is it the main executable of a bundle?
- if (CFRef<CFURLRef> pathURL = makeCFURL(path))
- if (CFRef<CFBundleRef> bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, pathURL)) {
- Context ctx; ctx.offset = archOffset;
- return new BundleDiskRep(bundle, &ctx); // ask bundle to make bundle-with-MachO-at-offset
- }
- // else, must be a Mach-O binary
- Context ctx; ctx.offset = archOffset;
- return new MachORep(path, &ctx);
- } catch (const CommonError &error) {
- switch (error.unixError()) {
- case ENOENT:
- MacOSError::throwMe(errSecCSStaticCodeNotFound);
- default:
- throw;
- }
- }
+ return new FileDiskRep(path);
}
void DiskRep::Writer::flush()
{ /* do nothing */ }
-void DiskRep::Writer::remove()
-{
- MacOSError::throwMe(errSecCSNotSupported);
-}
-
} // end namespace CodeSigning
} // end namespace Security
#include "cs.h"
#include "codedirectory.h"
-#include "cdbuilder.h"
#include "requirement.h"
#include "resources.h"
-#include <security_utilities/macho++.h> // for class Architecture
+#include "macho++.h" // for class Architecture
#include <security_utilities/refcount.h>
#include <security_utilities/superblob.h>
#include <CoreFoundation/CFData.h>
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 Writer *writer();
public:
- struct Context {
- Context() : arch(Architecture::none), offset(0), fileOnly(false) { }
- Architecture arch; // explicit architecture
- off_t offset; // explicit file offset
- bool fileOnly; // only consider single-file representations
- };
-
- 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
+ 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()); }
- 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:
static const size_t segmentedPageSize = 4096; // default page size for system-paged signatures
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 recommendedIdentifier() { return mOriginal->recommendedIdentifier(); }
- std::string resourcesRootPath() { return mOriginal->resourcesRootPath(); }
- CFDictionaryRef defaultResourceRules() { return mOriginal->defaultResourceRules(); }
- Universal *mainExecutableImage() { return mOriginal->mainExecutableImage(); }
- size_t signingBase() { return mOriginal->signingBase(); }
- size_t signingLimit() { return mOriginal->signingLimit(); }
- std::string format() { return mOriginal->format(); }
- UnixPlusPlus::FileDesc &fd() { return mOriginal->fd(); }
- void flush() { return mOriginal->flush(); }
-
-private:
- RefPointer<DiskRep> mOriginal; // underlying representation
-};
-
-
} // end namespace CodeSigning
} // end namespace Security
*/
#include "filediskrep.h"
#include "StaticCode.h"
-#include <security_utilities/macho++.h>
+#include "macho++.h" // may perhaps move into security_utilities...
#include <cstring>
FileDiskRep::FileDiskRep(const char *path)
: SingleDiskRep(path)
{
- CODESIGN_DISKREP_CREATE_FILE(this, (char*)path);
}
CFDataRef FileDiskRep::getAttribute(const char *name)
{
string aname = attrName(name);
- try {
- ssize_t length = fd().getAttrLength(aname);
- if (length < 0)
- return NULL; // no such attribute
- CFMallocData buffer(length);
- fd().getAttr(aname, buffer, length);
- return buffer;
- } catch (const UnixError &err) {
- // recover some errors that happen in (relatively) benign circumstances
- switch (err.error) {
- case ENOTSUP: // no extended attributes on this filesystem
- case EPERM: // filesystem objects to name(?)
- return NULL;
- default:
- throw;
- }
- }
+ ssize_t length = fd().getAttrLength(aname);
+ if (length < 0)
+ return NULL; // no such attribute
+ CFMallocData buffer(length);
+ fd().getAttr(aname, buffer, length);
+ return buffer;
}
// package up as host requirement and return that
Requirements::Maker maker;
maker.add(kSecHostRequirementType, req->clone());
+ secdebug("filediskrep", "made a scripting host requirement");
return maker.make();
}
} catch (...) {
void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
try {
- fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)),
- CFDataGetBytePtr(data), CFDataGetLength(data));
+ fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)),
+ CFDataGetBytePtr(data), CFDataGetLength(data));
} catch (const UnixError &error) {
if (error.error == ERANGE)
MacOSError::throwMe(errSecCSCMSTooLarge);
}
-//
-// Clear all signing data
-//
-void FileDiskRep::Writer::remove()
-{
- for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++)
- if (const char *name = CodeDirectory::canonicalSlotName(slot))
- fd().removeAttr(attrName(name));
- fd().removeAttr(attrName(kSecCS_SIGNATUREFILE));
-}
-
-
//
// We are NOT the preferred store for components because our approach
// (extended attributes) suffers from some serious limitations.
friend class FileDiskRep;
public:
void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
- void remove();
bool preferredStore();
protected:
--- /dev/null
+/*
+ * Copyright (c) 2007 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// foreigndiskrep - foreign executable disk representation
+//
+#include "foreigndiskrep.h"
+#include <cstring>
+
+
+namespace Security {
+namespace CodeSigning {
+
+using namespace UnixPlusPlus;
+
+
+//
+// Everything's lazy in here
+//
+ForeignDiskRep::ForeignDiskRep(const char *path)
+ : SingleDiskRep(path), mTriedRead(false)
+{
+}
+
+ForeignDiskRep::~ForeignDiskRep()
+{
+ if (mTriedRead)
+ delete mSigningData;
+}
+
+
+//
+// Foreign filter heuristic
+//
+bool ForeignDiskRep::candidate(FileDesc &fd)
+{
+ static const char magicMarker[] = "MZ\0\0\0\0\0\0\0\0\0\0PE\0\0 \b";
+ static const size_t magicLength = 18;
+ char marker[magicLength];
+ return fd.read(marker, magicLength, 0) == magicLength
+ && !memcmp(marker, magicMarker, magicLength);
+}
+
+
+//
+// Extract and return a component by slot number.
+// If we have a Mach-O binary, use embedded components.
+// Otherwise, look for and return the extended attribute, if any.
+//
+CFDataRef ForeignDiskRep::component(CodeDirectory::SpecialSlot slot)
+{
+ if (!mTriedRead)
+ readSigningData();
+ if (mSigningData)
+ return mSigningData->component(slot);
+ else
+ return NULL;
+}
+
+
+//
+// Default to system-paged signing
+//
+size_t ForeignDiskRep::pageSize()
+{
+ return segmentedPageSize;
+}
+
+
+//
+// Various other aspects of our DiskRep personality.
+//
+string ForeignDiskRep::format()
+{
+ return "foreign binary";
+}
+
+
+//
+// Discard cached information
+//
+void ForeignDiskRep::flush()
+{
+ mTriedRead = false;
+ ::free(mSigningData);
+}
+
+
+//
+// Locate, read, and cache embedded signing data from the foreign binary.
+//
+void ForeignDiskRep::readSigningData()
+{
+ if (!mTriedRead) { // try it once
+ mSigningData = NULL; // preset failure
+ mTriedRead = true; // we've tried (and perhaps failed)
+
+ AutoFileDesc fd(cspath(), O_RDONLY);
+ mSigningData = EmbeddedSignatureBlob::readBlob(fd);
+ if (mSigningData)
+ secdebug("foreignrep", "%zd signing bytes in %d blob(s) from %s(foreign)",
+ mSigningData->length(), mSigningData->count(),
+ mainExecutablePath().c_str());
+ else
+ secdebug("foreignrep", "failed to read signing bytes from %s(foreign)",
+ mainExecutablePath().c_str());
+ }
+}
+
+
+//
+// Generate the path to the (default) sidecar file
+// This is generated as /path/to/.CS.execfilename.
+// We're assuming that we're only dealing with absolute paths here.
+//
+string ForeignDiskRep::cspath()
+{
+ string p = this->path();
+ string::size_type slash = p.rfind('/');
+ assert(slash != string::npos);
+ return p.substr(0, slash+1) + ".CS." + p.substr(slash+1); // => /path/to/.CS.executable
+}
+
+
+//
+// ForeignDiskRep::Writers
+//
+DiskRep::Writer *ForeignDiskRep::writer()
+{
+ return new Writer(this);
+}
+
+ForeignDiskRep::Writer::~Writer()
+{
+ delete mSigningData;
+}
+
+
+//
+// Write a component.
+// Note that this isn't concerned with Mach-O writing; this is handled at
+// a much higher level. If we're called, it's extended attribute time.
+//
+void ForeignDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
+{
+ EmbeddedSignatureBlob::Maker::component(slot, data);
+}
+
+
+//
+// Append the superblob we built to the foreign binary.
+// Note: Aligning the signing blob to a 16-byte boundary is not strictly necessary,
+// but it's what the Mach-O case does, and it probably improves performance a bit.
+//
+void ForeignDiskRep::Writer::flush()
+{
+ delete mSigningData; // ditch previous blob just in case
+ mSigningData = Maker::make(); // assemble new signature SuperBlob
+ AutoFileDesc fd(rep->cspath(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ fd.writeAll(mSigningData, mSigningData->length());
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
--- /dev/null
+/*
+ * Copyright (c) 2007 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// foreigndiskrep - foreign executable disk representation
+//
+#ifndef _H_FOREIGNDISKREP
+#define _H_FOREIGNDISKREP
+
+#include "singlediskrep.h"
+#include "sigblob.h"
+#include "signerutils.h"
+#include <security_utilities/unix++.h>
+#include <security_utilities/cfutilities.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+//
+//
+class ForeignDiskRep : public SingleDiskRep {
+public:
+ ForeignDiskRep(const char *path);
+ ~ForeignDiskRep();
+
+ CFDataRef component(CodeDirectory::SpecialSlot slot);
+ size_t pageSize();
+ std::string format();
+ void flush();
+
+ static bool candidate(UnixPlusPlus::FileDesc &fd); // could this reasonably be a CFM code?
+
+public:
+ DiskRep::Writer *writer();
+ class Writer;
+ friend class Writer;
+
+protected:
+ void readSigningData(); // read and cache signing data
+ string cspath(); // path to sidecar
+
+private:
+ bool mTriedRead; // tried to get signing data
+ size_t mSigningOffset; // where we found the signing data
+ EmbeddedSignatureBlob *mSigningData; // cached signing data
+};
+
+
+//
+// The write side of a FileDiskRep
+//
+class ForeignDiskRep::Writer : public DiskRep::Writer, private EmbeddedSignatureBlob::Maker {
+ friend class ForeignDiskRep;
+public:
+ Writer(ForeignDiskRep *r) : rep(r), mSigningData(NULL) { }
+ ~Writer();
+
+ void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
+ virtual void flush();
+
+protected:
+ RefPointer<ForeignDiskRep> rep;
+ EmbeddedSignatureBlob *mSigningData;
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_FOREIGNDISKREP
//
KernelDiskRep::KernelDiskRep()
{
- CODESIGN_DISKREP_CREATE_KERNEL(this);
}
return NULL;
}
-CFDataRef KernelDiskRep::identification()
-{
- return NULL;
-}
-
-
CFURLRef KernelDiskRep::canonicalPath()
{
return makeCFURL("/mach_kernel");
KernelDiskRep();
CFDataRef component(CodeDirectory::SpecialSlot slot);
- CFDataRef identification();
std::string mainExecutablePath();
CFURLRef canonicalPath();
std::string recommendedIdentifier();
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// macho++ - Mach-O object file helpers
+//
+#include "macho++.h"
+#include <security_utilities/memutils.h>
+#include <security_utilities/endian.h>
+#include <mach/machine.h>
+
+namespace Security {
+
+
+//
+// Architecture values
+//
+Architecture::Architecture(const fat_arch &arch)
+ : pair<cpu_type_t, cpu_subtype_t>(arch.cputype, arch.cpusubtype)
+{
+}
+
+
+//
+// The local architecture (on demand; cached)
+//
+struct LocalArch {
+ const NXArchInfo *arch;
+ LocalArch() { arch = NXGetLocalArchInfo(); }
+};
+static ModuleNexus<LocalArch> localArch;
+
+Architecture Architecture::local()
+{
+ const NXArchInfo &local = *localArch().arch;
+ return Architecture(local.cputype, local.cpusubtype);
+}
+
+
+#define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
+
+//
+// Translate between names and numbers
+//
+static const char *uob(char *s) { if (*s != 'a') for (char *p = s; *p; p++) *p ^= 0x77; return s; }
+
+const char *Architecture::name() const
+{
+ if (const NXArchInfo *info = NXGetArchInfoFromCpuType(cpuType(), cpuSubtype()))
+ return info->name;
+ else if (cpuType() == CPU_TYPE_ARM) { // work-around for non-ARM Leopard systems
+ static char arm5[] = "\026\005\032\001B";
+ static char arm6[] = "\026\005\032\001A";
+ static char arm7[] = "\026\005\032\001@";
+ static char arm[] = "\026\005\032";
+ if (cpuSubtype() == CPU_SUBTYPE_ARM_V5TEJ)
+ return uob(arm5);
+ else if (cpuSubtype() == CPU_SUBTYPE_ARM_V6)
+ return uob(arm6);
+ else if (cpuSubtype() == CPU_SUBTYPE_ARM_V7)
+ return uob(arm7);
+ else
+ return uob(arm);
+ } else
+ return NULL;
+}
+
+
+//
+// Create a MachO object from an open file and a starting offset.
+// We load (only) the header and load commands into memory at that time.
+//
+MachO::MachO(FileDesc fd, size_t offset, size_t length)
+ : FileDesc(fd), mOffset(offset), mLength(length ? length : (fd.fileSize() - offset))
+{
+ size_t size = fd.read(&mHeader, sizeof(mHeader), mOffset);
+ if (size != sizeof(mHeader))
+ UnixError::throwMe(ENOEXEC);
+ switch (mHeader.magic) {
+ case MH_MAGIC:
+ mFlip = false;
+ m64 = false;
+ break;
+ case MH_CIGAM:
+ mFlip = true;
+ m64 = false;
+ break;
+ case MH_MAGIC_64:
+ mFlip = false;
+ m64 = true;
+ break;
+ case MH_CIGAM_64:
+ mFlip = true;
+ m64 = true;
+ break;
+ default:
+ UnixError::throwMe(ENOEXEC);
+ }
+
+ size_t cmdSize = flip(mHeader.sizeofcmds);
+ size_t cmdStart = m64 ? sizeof(mach_header_64) : sizeof(mach_header);
+ mCommands = (load_command *)malloc(cmdSize);
+ if (!mCommands)
+ UnixError::throwMe();
+ if (fd.read(mCommands, cmdSize, cmdStart + mOffset) != cmdSize)
+ UnixError::throwMe(ENOEXEC);
+ mEndCommands = LowLevelMemoryUtilities::increment<load_command>(mCommands, cmdSize);
+ secdebug("macho", "%p created fd=%d offset=0x%zx size=0x%zx %s%s %d command(s)",
+ this, this->fd(), mOffset, mLength, mFlip ? " flipped" : "", m64 ? " 64-bit" : "",
+ flip(mHeader.ncmds));
+}
+
+
+//
+// Destroy a MachO.
+// Note that we don't close the file descriptor.
+//
+MachO::~MachO()
+{
+ secdebug("macho", "%p destroyed", this);
+ ::free(mCommands);
+}
+
+
+//
+// Return various header fields
+//
+Architecture MachO::architecture() const
+{
+ return Architecture(flip(mHeader.cputype), flip(mHeader.cpusubtype));
+}
+
+uint32_t MachO::type() const
+{
+ return flip(mHeader.filetype);
+}
+
+uint32_t MachO::flags() const
+{
+ return flip(mHeader.flags);
+}
+
+
+//
+// Iterate through load commands
+//
+const load_command *MachO::nextCommand(const load_command *command) const
+{
+ using LowLevelMemoryUtilities::increment;
+ command = increment<const load_command>(command, flip(command->cmdsize));
+ return (command < mEndCommands) ? command : NULL;
+}
+
+
+//
+// Locate a segment command, by name
+//
+const segment_command *MachO::findSegment(const char *segname) const
+{
+ for (const load_command *command = loadCommands(); command; command = nextCommand(command)) {
+ if (flip(command->cmd) == LC_SEGMENT) {
+ const segment_command *seg = reinterpret_cast<const segment_command *>(command);
+ if (!strcmp(seg->segname, segname))
+ return seg;
+ }
+ }
+ return NULL;
+}
+
+const section *MachO::findSection(const char *segname, const char *sectname) const
+{
+ using LowLevelMemoryUtilities::increment;
+ if (const segment_command *seg = findSegment(segname)) {
+ if (is64()) {
+ const segment_command_64 *seg64 = reinterpret_cast<const segment_command_64 *>(seg);
+ const section_64 *sect = increment<const section_64>(seg64 + 1, 0);
+ for (unsigned n = flip(seg64->nsects); n > 0; n--, sect++) {
+ if (!strcmp(sect->sectname, sectname))
+ return reinterpret_cast<const section *>(sect);
+ }
+ } else {
+ const section *sect = increment<const section>(seg + 1, 0);
+ for (unsigned n = flip(seg->nsects); n > 0; n--, sect++) {
+ if (!strcmp(sect->sectname, sectname))
+ return sect;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//
+// Figure out where the Code Signing information starts in the Mach-O binary image.
+// The code signature is at the end of the file, and identified
+// by a specially-named section. So its starting offset is also the end
+// of the signable part.
+// Note that the offset returned is relative to the start of the Mach-O image.
+// Returns zero if not found (usually indicating that the binary was not signed).
+//
+const linkedit_data_command *MachO::findCodeSignature() const
+{
+ for (const load_command *cmd = loadCommands(); cmd; cmd = nextCommand(cmd))
+ if (flip(cmd->cmd) == LC_CODE_SIGNATURE)
+ return reinterpret_cast<const linkedit_data_command *>(cmd);
+ return NULL; // not found
+}
+
+size_t MachO::signingOffset() const
+{
+ if (const linkedit_data_command *lec = findCodeSignature())
+ return flip(lec->dataoff);
+ else
+ return 0;
+}
+
+size_t MachO::signingLength() const
+{
+ if (const linkedit_data_command *lec = findCodeSignature())
+ return flip(lec->datasize);
+ else
+ return 0;
+}
+
+
+//
+// Return the signing-limit length for this Mach-O binary image.
+// This is the signingOffset if present, or the full length if not.
+//
+size_t MachO::signingExtent() const
+{
+ if (size_t offset = signingOffset())
+ return offset;
+ else
+ return length();
+}
+
+
+//
+// I/O operations
+//
+void MachO::seek(size_t offset)
+{
+ FileDesc::seek(mOffset + offset);
+}
+
+CFDataRef MachO::dataAt(size_t offset, size_t size)
+{
+ CFMallocData buffer(size);
+ if (this->read(buffer, size, mOffset + offset) != size)
+ UnixError::throwMe();
+ return buffer;
+}
+
+
+//
+// Fat (aka universal) file wrappers
+//
+Universal::Universal(FileDesc fd)
+ : FileDesc(fd)
+{
+ union {
+ fat_header header; // if this is a fat file
+ mach_header mheader; // if this is a thin file
+ };
+ const size_t size = max(sizeof(header), sizeof(mheader));
+ if (fd.read(&header, size, 0) != size)
+ UnixError::throwMe(ENOEXEC);
+ switch (header.magic) {
+ case FAT_MAGIC:
+ case FAT_CIGAM:
+ {
+ mArchCount = ntohl(header.nfat_arch);
+ size_t archSize = sizeof(fat_arch) * mArchCount;
+ mArchList = (fat_arch *)malloc(archSize);
+ if (!mArchList)
+ UnixError::throwMe();
+ if (fd.read(mArchList, archSize, sizeof(header)) != archSize) {
+ ::free(mArchList);
+ UnixError::throwMe(ENOEXEC);
+ }
+ for (fat_arch *arch = mArchList; arch < mArchList + mArchCount; arch++) {
+ n2hi(arch->cputype);
+ n2hi(arch->cpusubtype);
+ n2hi(arch->offset);
+ n2hi(arch->size);
+ n2hi(arch->align);
+ }
+ secdebug("macho", "%p is a fat file with %d architectures",
+ this, mArchCount);
+ break;
+ }
+ case MH_MAGIC:
+ case MH_MAGIC_64:
+ mArchList = NULL;
+ mArchCount = 0;
+ mThinArch = Architecture(mheader.cputype, mheader.cpusubtype);
+ secdebug("macho", "%p is a thin file (%s)", this, mThinArch.name());
+ break;
+ case MH_CIGAM:
+ case MH_CIGAM_64:
+ mArchList = NULL;
+ mArchCount = 0;
+ mThinArch = Architecture(flip(mheader.cputype), flip(mheader.cpusubtype));
+ secdebug("macho", "%p is a thin file (%s)", this, mThinArch.name());
+ break;
+ default:
+ UnixError::throwMe(ENOEXEC);
+ }
+}
+
+Universal::~Universal()
+{
+ ::free(mArchList);
+}
+
+
+//
+// Get the "local" architecture from the fat file
+// Throws ENOEXEC if not found.
+//
+MachO *Universal::architecture() const
+{
+ if (isUniversal())
+ return findImage(bestNativeArch());
+ else
+ return new MachO(*this);
+}
+
+size_t Universal::archOffset() const
+{
+ if (isUniversal())
+ return findArch(bestNativeArch())->offset;
+ else
+ return 0;
+}
+
+
+//
+// Get the specified architecture from the fat file
+// Throws ENOEXEC if not found.
+//
+MachO *Universal::architecture(const Architecture &arch) const
+{
+ if (isUniversal())
+ return findImage(arch);
+ else if (mThinArch.matches(arch))
+ return new MachO(*this);
+ else
+ UnixError::throwMe(ENOEXEC);
+}
+
+size_t Universal::archOffset(const Architecture &arch) const
+{
+ if (isUniversal())
+ return findArch(arch)->offset;
+ else if (mThinArch.matches(arch))
+ return 0;
+ else
+ UnixError::throwMe(ENOEXEC);
+}
+
+
+//
+// Locate an architecture from the fat file's list.
+// Throws ENOEXEC if not found.
+//
+const fat_arch *Universal::findArch(const Architecture &target) const
+{
+ assert(isUniversal());
+ const fat_arch *end = mArchList + mArchCount;
+ // exact match
+ for (const fat_arch *arch = mArchList; arch < end; ++arch)
+ if (arch->cputype == target.cpuType()
+ && arch->cpusubtype == target.cpuSubtype())
+ return arch;
+ // match for generic model of main architecture
+ for (const fat_arch *arch = mArchList; arch < end; ++arch)
+ if (arch->cputype == target.cpuType() && arch->cpusubtype == 0)
+ return arch;
+ // match for any subarchitecture of the main architeture (questionable)
+ for (const fat_arch *arch = mArchList; arch < end; ++arch)
+ if (arch->cputype == target.cpuType())
+ return arch;
+ // no match
+ UnixError::throwMe(ENOEXEC); // not found
+}
+
+MachO *Universal::findImage(const Architecture &target) const
+{
+ const fat_arch *arch = findArch(target);
+ return new MachO(*this, arch->offset, arch->size);
+}
+
+
+//
+// Find the best-matching architecture for this fat file.
+// We pick the native architecture if it's available.
+// If it contains exactly one architecture, we take that.
+// Otherwise, we throw.
+//
+Architecture Universal::bestNativeArch() const
+{
+ if (isUniversal()) {
+ // ask the NXArch API for our native architecture
+ const Architecture native = Architecture::local();
+ if (fat_arch *match = NXFindBestFatArch(native.cpuType(), native.cpuSubtype(), mArchList, mArchCount))
+ return *match;
+ // if the system can't figure it out, pick (arbitrarily) the first one
+ return mArchList[0];
+ } else
+ return mThinArch;
+}
+
+
+//
+// List all architectures from the fat file's list.
+//
+void Universal::architectures(Architectures &archs)
+{
+ if (isUniversal()) {
+ for (unsigned n = 0; n < mArchCount; n++)
+ archs.insert(mArchList[n]);
+ } else {
+ auto_ptr<MachO> macho(architecture());
+ archs.insert(macho->architecture());
+ }
+}
+
+
+//
+// Quickly guess the Mach-O type of a file.
+// Returns type zero if the file isn't Mach-O or Universal.
+// Does not reposition the file.
+//
+uint32_t Universal::typeOf(FileDesc fd)
+{
+ mach_header header;
+ if (fd.read(&header, sizeof(header), 0) != sizeof(header))
+ return false;
+ for (;;) {
+ switch (header.magic) {
+ case MH_MAGIC:
+ case MH_MAGIC_64:
+ return header.filetype;
+ break;
+ case MH_CIGAM:
+ case MH_CIGAM_64:
+ return flip(header.filetype);
+ break;
+ case FAT_MAGIC:
+ case FAT_CIGAM:
+ {
+ const fat_arch *arch1 =
+ LowLevelMemoryUtilities::increment<fat_arch>(&header, sizeof(fat_header));
+ if (fd.read(&header, sizeof(header), ntohl(arch1->offset)) != sizeof(header))
+ return 0;
+ continue;
+ }
+ default:
+ return 0;
+ }
+ }
+}
+
+
+} // Security
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// macho++ - Mach-O object file helpers
+//
+#ifndef _H_MACHOPLUSPLUS
+#define _H_MACHOPLUSPLUS
+
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/arch.h>
+#include <security_utilities/globalizer.h>
+#include <security_utilities/endian.h>
+#include <security_utilities/unix++.h>
+#include <security_utilities/cfutilities.h>
+
+namespace Security {
+
+
+//
+// An architecture specification.
+// Simply a pair or (cpu type, cpu subtype), really.
+//
+class Architecture : public std::pair<cpu_type_t, cpu_subtype_t> {
+ typedef std::pair<cpu_type_t, cpu_subtype_t> _Pair;
+public:
+ Architecture() { }
+ explicit Architecture(cpu_type_t type, cpu_subtype_t sub = CPU_SUBTYPE_MULTIPLE)
+ : std::pair<cpu_type_t, cpu_subtype_t>(type, sub) { }
+ Architecture(const fat_arch &archInFile);
+
+ cpu_type_t cpuType() const { return this->first; }
+ cpu_subtype_t cpuSubtype() const { return this->second; }
+ const char *name() const;
+
+ static const cpu_type_t none = 0;
+ operator bool () const { return cpuType() != none; }
+ bool operator ! () const { return cpuType() == none; }
+
+public:
+ friend bool operator == (const Architecture &a1, const Architecture &a2)
+ { return _Pair(a1) == _Pair(a2); }
+
+ friend bool operator < (const Architecture &a1, const Architecture &a2)
+ { return _Pair(a1) < _Pair(a2); }
+
+ bool matches(const Architecture &templ) const
+ { return first == templ.first && (second == templ.second || templ.second == 0 || templ.second == CPU_SUBTYPE_MULTIPLE); }
+
+public:
+ static Architecture local();
+};
+
+
+//
+// A Mach-O formatted file segment.
+//
+class MachO : public UnixPlusPlus::FileDesc {
+public:
+ MachO(FileDesc fd, size_t offset = 0, size_t length = 0);
+ ~MachO();
+
+ size_t offset() const { return mOffset; }
+ size_t length() const { return mLength; }
+
+ template <class T>
+ T flip(T value) const
+ { return mFlip ? Security::flip(value) : value; }
+
+ bool isFlipped() const { return mFlip; }
+ bool is64() const { return m64; }
+
+ Architecture architecture() const;
+ uint32_t type() const;
+ uint32_t flags() const;
+
+ const load_command *loadCommands() const { return mCommands; }
+ const load_command *nextCommand(const load_command *command) const;
+
+ const segment_command *findSegment(const char *segname) const;
+ const section *findSection(const char *segname, const char *sectname) const;
+
+ const linkedit_data_command *findCodeSignature() const;
+
+ size_t signingOffset() const; // starting offset of CS section, or 0 if none
+ size_t signingLength() const; // length of CS section, or 0 if none
+ size_t signingExtent() const; // signingOffset, or file length if none
+
+ void seek(size_t offset); // relative to start of image
+ CFDataRef dataAt(size_t offset, size_t size);
+
+private:
+ size_t mOffset; // starting file offset
+ size_t mLength; // Mach-O file length
+ bool m64; // is 64-bit
+ bool mFlip; // wrong byte order (flip all integers)
+ mach_header mHeader; // Mach-O header
+ load_command *mCommands; // load commands
+ load_command *mEndCommands; // end of load commands
+};
+
+
+//
+// A Universal object represents a Mach-O binary image (whole) file.
+// It can represent a true Universal (aka "Fat") file with multiple
+// architectures; but it will also represent a single Mach-O ("thin")
+// binary and make you believe it's a Universal with just one architecture.
+//
+class Universal : public UnixPlusPlus::FileDesc {
+public:
+ Universal(FileDesc fd);
+ ~Universal();
+
+ // return a genuine MachO object for the given architecture
+ MachO *architecture() const; // native
+ MachO *architecture(const Architecture &arch) const; // given
+
+ // return (just) the starting offset of an architecture
+ size_t archOffset() const; // native
+ size_t archOffset(const Architecture &arch) const; // given
+
+ // return a set of architectures contained
+ typedef std::set<Architecture> Architectures;
+ void architectures(Architectures &archs);
+
+ bool isUniversal() const { return mArchList != NULL; }
+ Architecture bestNativeArch() const;
+
+public:
+ static uint32_t typeOf(FileDesc fd);
+
+private:
+ const fat_arch *findArch(const Architecture &arch) const;
+ MachO *findImage(const Architecture &arch) const;
+
+private:
+ fat_arch *mArchList; // architectures (NULL if thin file)
+ unsigned mArchCount; // number of architectures (if fat)
+ Architecture mThinArch; // single architecture (if thin)
+};
+
+
+} // end namespace Security
+
+#endif // !_H_MACHOPLUSPLUS
// machorep - DiskRep mix-in for handling Mach-O main executables
//
#include "machorep.h"
-#include "StaticCode.h"
-#include "reqmaker.h"
namespace Security {
//
// Object management.
// We open the main executable lazily, so nothing much happens on construction.
-// If the context specifies a file offset, we directly pick that Mach-O binary (only).
-// if it specifies an architecture, we try to pick that. Otherwise, we deliver the whole
-// Universal object (which will usually deliver the "native" architecture later).
//
-MachORep::MachORep(const char *path, const Context *ctx)
+MachORep::MachORep(const char *path)
: SingleDiskRep(path), mSigningData(NULL)
{
- if (ctx)
- if (ctx->offset)
- mExecutable = new Universal(fd(), ctx->offset);
- else if (ctx->arch) {
- auto_ptr<Universal> full(new Universal(fd()));
- mExecutable = new Universal(fd(), full->archOffset(ctx->arch));
- } else
- mExecutable = new Universal(fd());
- else
- mExecutable = new Universal(fd());
- assert(mExecutable);
- CODESIGN_DISKREP_CREATE_MACHO(this, (char*)path, (void*)ctx);
+ mExecutable = new Universal(fd());
}
MachORep::~MachORep()
//
// Sniffer function for "plausible Mach-O binary"
//
-bool MachORep::candidate(FileDesc &fd)
+bool MachORep::candidiate(FileDesc &fd)
{
switch (Universal::typeOf(fd)) {
case MH_EXECUTE:
//
-// The default suggested requirements for Mach-O binaries are as follows:
-// Hosting requirement: Rosetta if it's PPC, none otherwise.
-// Library requirement: Composed from dynamic load commands.
+// For Mach-O binaries that are of PowerPC architecture, we recommend
+// allowing the Rosetta translator as a host. Otherwise, no suggestions.
//
-static const uint8_t ppc_host_ireq[] = { // anchor apple and identifier com.apple.translate
- 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x63, 0x6f, 0x6d, 0x2e,
- 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65, 0x00,
+static const uint8_t ppc_ireqs[] = { // host => anchor apple and identifier com.apple.translate
+ 0xfa, 0xde, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x14, 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13,
+ 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c,
+ 0x61, 0x74, 0x65, 0x00,
};
const Requirements *MachORep::defaultRequirements(const Architecture *arch)
{
assert(arch); // enforced by signing infrastructure
- Requirements::Maker maker;
-
- // if ppc architecture, add hosting requirement for Rosetta's translate tool
if (arch->cpuType() == CPU_TYPE_POWERPC)
- maker.add(kSecHostRequirementType, ((const Requirement *)ppc_host_ireq)->clone());
-
- // add library requirements from DYLIB commands (if any)
- if (Requirement *libreq = libraryRequirements(arch))
- maker.add(kSecLibraryRequirementType, libreq); // takes ownership
-
- // that's all
- return maker.make();
-}
-
-Requirement *MachORep::libraryRequirements(const Architecture *arch)
-{
- auto_ptr<MachO> macho(mainExecutableImage()->architecture(*arch));
- Requirement::Maker maker;
- Requirement::Maker::Chain chain(maker, opOr);
- if (macho.get()) {
- for (const load_command *command = macho->loadCommands(); command; command = macho->nextCommand(command)) {
- if (macho->flip(command->cmd) == LC_LOAD_DYLIB) {
- const dylib_command *dycmd = (const dylib_command *)command;
- if (const char *name = macho->string(command, dycmd->dylib.name))
- try {
- secdebug("machorep", "examining DYLIB %s", name);
- // find path on disk, get designated requirement (if signed)
- if (RefPointer<DiskRep> rep = DiskRep::bestFileGuess(name))
- if (SecPointer<SecStaticCode> code = new SecStaticCode(rep))
- if (const Requirement *req = code->designatedRequirement()) {
- secdebug("machorep", "adding library requirement for %s", name);
- chain.add();
- chain.maker.copy(req);
- }
- } catch (...) {
- secdebug("machorep", "exception getting library requirement (ignored)");
- }
- else
- secdebug("machorep", "no string for DYLIB command (ignored)");
- }
- }
- }
- if (chain.empty())
- return NULL;
+ return ((const Requirements *)ppc_ireqs)->clone(); // need to pass ownership
else
- return maker.make();
+ return NULL;
}
-
//
// Obtain, cache, and return a Universal reference to the main executable,
// IF the main executable is a Mach-O binary (or fat version thereof).
}
-//
-// We choose the binary identifier for a Mach-O binary as follows:
-// - If the Mach-O headers have a UUID command, use the UUID.
-// - Otherwise, use the SHA-1 hash of the (entire) load commands.
-//
-CFDataRef MachORep::identification()
-{
- std::auto_ptr<MachO> macho(mainExecutableImage()->architecture());
- return identificationFor(macho.get());
-}
-
-CFDataRef MachORep::identificationFor(MachO *macho)
-{
- // if there is a LC_UUID load command, use the UUID contained therein
- if (const load_command *cmd = macho->findCommand(LC_UUID)) {
- const uuid_command *uuidc = reinterpret_cast<const uuid_command *>(cmd);
- char result[4 + sizeof(uuidc->uuid)];
- memcpy(result, "UUID", 4);
- memcpy(result+4, uuidc->uuid, sizeof(uuidc->uuid));
- return makeCFData(result, sizeof(result));
- }
-
- // otherwise, use the SHA-1 hash of the entire load command area
- SHA1 hash;
- hash(&macho->header(), sizeof(mach_header));
- hash(macho->loadCommands(), macho->commandLength());
- SHA1::Digest digest;
- hash.finish(digest);
- return makeCFData(digest, sizeof(digest));
-}
-
-
//
// Retrieve a component from the executable.
// This reads the entire signing SuperBlob when first called for an executable,
//
CFDataRef MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot)
{
- if (!mSigningData) { // fetch and cache
- auto_ptr<MachO> macho(mainExecutableImage()->architecture());
- if (macho.get())
- if (const linkedit_data_command *cs = macho->findCodeSignature()) {
- size_t offset = macho->flip(cs->dataoff);
- size_t length = macho->flip(cs->datasize);
- if (mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd(), macho->offset() + offset, length)) {
- secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
- mSigningData->length(), mSigningData->count(),
- mainExecutablePath().c_str(), macho->architecture().name());
- } else {
- secdebug("machorep", "failed to read signing bytes from %s(%s)",
- mainExecutablePath().c_str(), macho->architecture().name());
- MacOSError::throwMe(errSecCSSignatureInvalid);
+ if (!mSigningData) // fetch and cache
+ try {
+ auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+ if (macho.get())
+ if (size_t offset = macho->signingOffset()) {
+ macho->seek(offset);
+ mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd());
+ if (mSigningData)
+ secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
+ mSigningData->length(), mSigningData->count(),
+ mainExecutablePath().c_str(), macho->architecture().name());
+ else
+ secdebug("machorep", "failed to read signing bytes from %s(%s)",
+ mainExecutablePath().c_str(), macho->architecture().name());
}
- }
- }
+ } catch (...) {
+ secdebug("machorep", "exception reading Mach-O from universal");
+ }
if (mSigningData)
return mSigningData->component(slot);
if (const section *sect = macho->findSection("__TEXT", "__info_plist")) {
if (macho->is64()) {
const section_64 *sect64 = reinterpret_cast<const section_64 *>(sect);
- info.take(macho->dataAt(macho->flip(sect64->offset), macho->flip(sect64->size)));
+ info = macho->dataAt(macho->flip(sect64->offset), macho->flip(sect64->size));
} else {
- info.take(macho->dataAt(macho->flip(sect->offset), macho->flip(sect->size)));
+ info = macho->dataAt(macho->flip(sect->offset), macho->flip(sect->size));
}
}
} catch (...) {
return string("Mach-O thin (") + archs.begin()->name() + ")";
}
} else
- return "Mach-O (unrecognized format)";
+ return "not Mach-O"; // (you don't usually show that one to the user)
}
//
void MachORep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
- assert(false);
MacOSError::throwMe(errSecCSInternalError);
}
#include "singlediskrep.h"
#include "sigblob.h"
#include <security_utilities/unix++.h>
-#include <security_utilities/macho++.h>
+#include <security_codesigning/macho++.h>
namespace Security {
namespace CodeSigning {
//
class MachORep : public SingleDiskRep {
public:
- MachORep(const char *path, const Context *ctx = NULL);
+ MachORep(const char *path);
virtual ~MachORep();
CFDataRef component(CodeDirectory::SpecialSlot slot);
- CFDataRef identification();
std::string recommendedIdentifier();
const Requirements *defaultRequirements(const Architecture *arch);
Universal *mainExecutableImage();
void flush(); // flush cache
- static bool candidate(UnixPlusPlus::FileDesc &fd);
-
-public:
- static CFDataRef identificationFor(MachO *macho);
+ static bool candidiate(UnixPlusPlus::FileDesc &fd);
public:
DiskRep::Writer *writer();
protected:
CFDataRef embeddedComponent(CodeDirectory::SpecialSlot slot);
CFDataRef infoPlist();
- Requirement *libraryRequirements(const Architecture *arch);
private:
Universal *mExecutable; // cached Mach-O/Universal reference to mainExecutablePath()
using namespace UnixPlusPlus;
-//
-// Table of reserved words (keywords), generated by ANTLR
-//
-static const char * const keywords[] = {
-#include "RequirementKeywords.h"
- "",
- NULL
-};
-
-
//
// Printf to established output channel
//
print("anchor apple generic");
break;
case opAnchorHash:
- print("certificate"); certSlot(); print(" = "); hashData();
+ print("anchor"); certSlot(); print(" = "); hashData();
break;
case opInfoKeyValue:
if (mDebug)
void Dumper::certSlot()
{
- switch (int32_t slot = get<int32_t>()) {
+ switch (uint32_t slot = get<uint32_t>()) {
case Requirement::anchorCert:
print(" root");
break;
{
switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
case matchExists:
- print(" /* exists */");
+ print(" exists");
break;
case matchEqual:
print(" = "); data();
break; // pessimal
}
- if (bestMode == isSimple) {
- string s((const char *)data, length);
- for (const char * const * k = keywords; *k; k++)
- if (s == *k) {
- bestMode = isPrintable; // reserved word; need quotes
- break;
- }
- }
-
+ if (length == 0 && bestMode == isSimple)
+ bestMode = isPrintable; // force quotes for empty string
+
switch (bestMode) {
case isSimple:
print("%.*s", length, data);
// reqinterp - Requirement language (exprOp) interpreter
//
#include "reqinterp.h"
-#include "codesigning_dtrace.h"
#include <Security/SecTrustSettingsPriv.h>
#include <Security/SecCertificatePriv.h>
#include <security_utilities/memutils.h>
bool Requirement::Interpreter::evaluate()
{
ExprOp op = ExprOp(get<uint32_t>());
- CODESIGN_EVAL_REQINT_OP(op, this->pc() - sizeof(uint32_t));
switch (op & ~opFlagMask) {
case opFalse:
return false;
// unknown opcode, but it has a size field and can be safely bypassed
skip(get<uint32_t>());
if (op & opGenericFalse) {
- CODESIGN_EVAL_REQINT_UNKNOWN_FALSE(op);
+ secdebug("csinterp", "opcode 0x%x interpreted as false", op);
return false;
} else {
- CODESIGN_EVAL_REQINT_UNKNOWN_SKIPPED(op);
+ secdebug("csinterp", "opcode 0x%x ignored; continuing", op);
return evaluate();
}
}
for (const CertField *cf = certFields; cf->name; cf++)
if (cf->name == key) {
CFRef<CFStringRef> value;
- if (OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
+ if (IFDEBUG(OSStatus rc =) SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%ld", cert, key.c_str(), rc);
return false;
}
bool Requirement::Interpreter::appleSigned()
{
if (appleAnchored())
- if (SecCertificateRef intermed = mContext->cert(-2)) // first intermediate
- // first intermediate common name match (exact)
- if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
+ if (SecCertificateRef intermed = mContext->cert(-2)) // first intermediate
+ // first intermediate common name match (exact)
+ if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
&& certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
- return true;
+ return true;
return false;
}
Match(CFStringRef value, MatchOperation op) : mValue(value), mOp(op) { } // explicit
Match() : mValue(NULL), mOp(matchExists) { } // explict test for presence
bool operator () (CFTypeRef candidate) const; // match to candidate
-
+
protected:
bool inequality(CFTypeRef candidate, CFStringCompareFlags flags, CFComparisonResult outcome, bool negate) const;
template <class T>
Endian<T> &insert(const Label &label, size_t length = sizeof(T))
{ return *reinterpret_cast<Endian<T>*>(insert(label, length)); }
-
+
//
// Help with making operator chains (foo AND bar AND baz...).
// Note that the empty case (no elements at all) must be resolved by the caller.
#include "reqparser.h"
#include "antlrplugin.h"
#include "cserror.h"
-#include "codesigning_dtrace.h"
#include <CoreFoundation/CoreFoundation.h>
#include <security_utilities/osxcode.h>
{
if (CFBundleRef securityFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")))
if (CFURLRef plugins = CFBundleCopyBuiltInPlugInsURL(securityFramework))
- if (CFRef<CFURLRef> pluginURL = makeCFURL("csparser.bundle", true, plugins)) {
+ if (CFRef<CFURLRef> pluginURL = CFURLCreateWithFileSystemPathRelativeToBase(NULL,
+ CFSTR("csparser.bundle"), kCFURLPOSIXPathStyle, true, plugins)) {
+ secdebug("antlrplugin", "loading antlr parser plugin from %s", cfString(pluginURL).c_str());
plugin = new LoadableBundle(cfString(pluginURL).c_str());
plugin->load();
- CODESIGN_LOAD_ANTLR();
antlr = reinterpret_cast<FindAntlrPlugin *>(plugin->lookupSymbol(FINDANTLRPLUGIN))();
return;
}
{ return RequirementParser<Requirements>()(source); }
template <class Input>
-inline const BlobCore *parseGeneric(const Input &source)
+inline const Requirements *parseGeneric(const Input &source)
{ return RequirementParser<BlobCore>()(source); }
Requirement::Reader::Reader(const Requirement *req)
: mReq(req), mPC(sizeof(Requirement))
{
- assert(req);
- if (req->kind() != exprForm)
- MacOSError::throwMe(errSecCSReqUnsupported);
}
{
checkSize(sizeof(T));
const Endian<const T> *value = mReq->at<Endian<const T> >(mPC);
- mPC += sizeof(T);
+ mPC += sizeof(value);
return *value;
}
//
#include "requirement.h"
#include "reqinterp.h"
-#include "codesigning_dtrace.h"
#include <security_utilities/errors.h>
#include <security_utilities/unix++.h>
#include <security_utilities/logging.h>
//
void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
{
- CODESIGN_EVAL_REQINT_START((void*)this, this->length());
switch (kind()) {
case exprForm:
- if (Requirement::Interpreter(this, &ctx).evaluate()) {
- CODESIGN_EVAL_REQINT_END(0);
- return;
- } else {
- CODESIGN_EVAL_REQINT_END(failure);
+ if (!Requirement::Interpreter(this, &ctx).evaluate())
MacOSError::throwMe(failure);
- }
+ return;
default:
- CODESIGN_EVAL_REQINT_END(errSecCSReqUnsupported);
+ secdebug("reqval", "unrecognized requirement kind %d", kind());
MacOSError::throwMe(errSecCSReqUnsupported);
}
}
#endif //TEST_APPLE_ANCHOR
-//
-// InternalRequirements
-//
-void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted)
-{
- if (defaulted) {
- this->add(defaulted);
- ::free((void *)defaulted); // was malloc(3)ed by DiskRep
- }
- if (given)
- this->add(given);
- mReqs = make();
-}
-
//
// Debug dump support
opIdent, // match canonical code [string]
opAppleAnchor, // signed by Apple as Apple's product
opAnchorHash, // match anchor [cert hash]
- opInfoKeyValue, // *legacy* - use opInfoKeyField [key; value]
- opAnd, // binary prefix expr AND expr [expr; expr]
- opOr, // binary prefix expr OR expr [expr; expr]
- opCDHash, // match hash of CodeDirectory directly [cd hash]
- opNot, // logical inverse [expr]
+ opInfoKeyValue, // *legacy* match Info.plist field [key; value]
+ opAnd, // binary prefix expr AND expr
+ opOr, // binary prefix expr OR expr
+ opCDHash, // match hash of CodeDirectory directly
+ opNot, // logical inverse
opInfoKeyField, // Info.plist key field [string; match suffix]
opCertField, // Certificate field [cert index; field name; match suffix]
opTrustedCert, // require trust settings to approve one particular cert [cert index]
typedef SuperBlob<0xfade0c01> Requirements;
-//
-// A helper to deal with the magic merger logic of internal requirements
-//
-class InternalRequirements : public Requirements::Maker {
-public:
- InternalRequirements() : mReqs(NULL) { }
- ~InternalRequirements() { ::free((void *)mReqs); }
- void operator () (const Requirements *given, const Requirements *defaulted);
- operator const Requirements * () const { return mReqs; }
-
-private:
- const Requirements *mReqs;
-};
-
-
} // CodeSigning
// resource directory construction and verification
//
#include "resources.h"
-#include "csutilities.h"
#include <Security/CSCommon.h>
-#include <security_utilities/unix++.h>
-#include <security_utilities/cfmunge.h>
+#include <security_codesigning/cfmunge.h>
namespace Security {
namespace CodeSigning {
}
if (!bestRule || rule->weight > bestRule->weight)
bestRule = rule;
- }
+ }
}
if (!bestRule || (bestRule->flags & omitted))
continue;
CFDictionaryRef ResourceBuilder::build()
{
secdebug("codesign", "start building resource directory");
- CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
+ CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary(0);
string path;
Rule *rule;
}
secdebug("codesign", "finished code directory with %d entries",
int(CFDictionaryGetCount(files)));
-
- return cfmake<CFDictionaryRef>("{rules=%O,files=%O}", mRawRules.get(), files.get());
+
+ return makeCFDictionary(2,
+ CFSTR("rules"), mRawRules.get(),
+ CFSTR("files"), files.get()
+ );
}
//
CFDataRef ResourceBuilder::hashFile(const char *path)
{
- UnixPlusPlus::AutoFileDesc fd(path);
+ CFRef<CFDataRef> data = cfLoadFile(path);
+ secdebug("rdirenum", " %s (%d bytes)", path, int(CFDataGetLength(data)));
SHA1 hasher;
- hashFileData(fd, hasher);
- SHA1::Digest digest;
+ hasher(CFDataGetBytePtr(data), CFDataGetLength(data));
+ unsigned char digest[CC_SHA1_DIGEST_LENGTH];
hasher.finish(digest);
return CFDataCreate(NULL, digest, sizeof(digest));
}
}
-std::string ResourceBuilder::escapeRE(const std::string &s)
-{
- string r;
- for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
- char c = *it;
- if (strchr("\\[]{}().+*", c))
- r.push_back('\\');
- r.push_back(c);
- }
- return r;
-}
-
-
//
// Resource Seals
//
};
void addRule(Rule *rule) { mRules.push_back(rule); }
void addExclusion(const std::string &pattern) { mRules.insert(mRules.begin(), new Rule(pattern, 0, exclusion)); }
-
- static std::string escapeRE(const std::string &s);
FTSENT *next(std::string &path, Rule * &rule); // enumerate next file and match rule
+++ /dev/null
-/*
- * DTrace static providers at the Code Signing layer
- */
-#define int32_t int
-#define uint32_t unsigned
-#define mach_port_t uint32_t
-
-
-/*
- * Basic semantic events of the code signing subsystem
- */
-provider codesign {
- probe diskrep__create__macho(void *me, const char *path, const void *ctx);
- probe diskrep__create__bundle__path(void *me, const char *path, void *ctx, void *exec);
- probe diskrep__create__bundle__ref(void *me, void *cfbundle, void *ctx, void *exec);
- probe diskrep__create__file(void *me, const char *path);
- probe diskrep__create__cfm(void *me, const char *path);
- probe diskrep__create__slc(void *me, const char *path);
- probe diskrep__create__detached(void *me, void *orig, const char *source, void *glob);
- probe diskrep__create__kernel(void *me);
- probe diskrep__destroy(void *me);
-
- probe static__create(void *me, void *host);
- probe dynamic__create(void *me, void *rep);
-
- probe static__cdhash(void *me, const void *cdhash, uint32_t length);
- probe static__attach__explicit(void *me, void *rep);
- probe static__attach__system(void *me, void *rep);
-
- probe eval__dynamic__start(void *me, const char *path);
- probe eval__dynamic__end(void *me);
- probe eval__dynamic__root();
-
- probe eval__static__start(void *me, const char *path);
- probe eval__static__end(void *me);
- probe eval__static__reset(void *me);
-
- probe eval__static__executable__start(void *me, const char *path, uint32_t pages);
- probe eval__static__executable__fail(void *me, uint32_t badPage);
- probe eval__static__executable__end(void *me);
- probe eval__static__resources__start(void *me, const char *path, int count);
- probe eval__static__resources__end(void *me);
-
- probe eval__static__directory(void *me);
- probe eval__static__intreq__start(void *me, uint32_t reqType, void *target, int32_t nullError);
- probe eval__static__intreq__end(void *me);
-
- probe eval__static__signature__start(void *me, const char *path);
- probe eval__static__signature__adhoc(void *me);
- probe eval__static__signature__result(void *me, uint32_t result, uint32_t chainLength);
- probe eval__static__signature__expired(void *me);
- probe eval__static__signature__end(void *me);
-
- probe eval__reqint__start(const void *reqdata, uint32_t reqlength);
- probe eval__reqint__end(uint32_t result);
- probe eval__reqint__op(uint32_t opcode, uint32_t offset);
- probe eval__reqint__unknown_false(uint32_t opcode);
- probe eval__reqint__unknown_skipped(uint32_t opcode);
-
- probe guest__hostingport(void *host, mach_port_t hostingPort);
- probe guest__locate__generic(void *host, uint32_t *guestPath, uint32_t guestPathLength, mach_port_t subport);
- probe guest__identify__process(void *guest, uint32_t guestPid, void *code);
- probe guest__cdhash__process(void *code, const void *cdhash, uint32_t length);
- probe guest__identify__generic(void *guest, uint32_t guestRef, void *code);
- probe guest__cdhash__generic(void *code, const void *cdhash, uint32_t length);
-
- probe allocate__validate(const char *path, uint32_t pid);
- probe allocate__arch(const char *arch, uint32_t size);
- probe allocate__archn(uint32_t cputype, uint32_t cpusubtype, uint32_t size);
- probe allocate__write(const char *arch, off_t offset, uint32_t length, uint32_t available);
-
- probe load__antlr();
-};
# @APPLE_LICENSE_HEADER_END@
#
_SecCodeGetTypeID
+_SecGetRootCode
_SecCodeCopySelf
-_SecCodeCopyInternalRequirement
-_SecCodeGetStatus
-_SecCodeSetStatus
_SecCodeCopyStaticCode
_SecCodeCopyHost
_SecCodeCopyGuestWithAttributes
_SecRequirementCreateGroup
_SecRequirementCopyData
_SecRequirementCopyString
-_SecRequirementsCreateFromRequirements
-_SecRequirementsCopyRequirements
-_SecRequirementsCreateWithString
-_SecRequirementsCopyString
_SecCodeSignerGetTypeID
_SecCodeSignerCreate
_SecCodeSignerAddSignature
_SecHostSelectGuest
_SecHostSelectedGuest
_SecHostSetHostingPort
-_kSecCodeDirectoryFlagTable
_kSecCodeSignerApplicationData
_kSecCodeSignerDetached
_kSecCodeSignerDryRun
_kSecCodeInfoPList
_kSecCodeInfoRequirements
_kSecCodeInfoRequirementData
-_kSecCodeInfoSource
_kSecCodeInfoStatus
_kSecCodeInfoTrust
-_kSecCodeInfoUnique
-_kSecCodeInfoCodeDirectory
-_kSecCodeInfoCodeOffset
-_kSecCodeInfoResourceDirectory
+_kSecGuestAttributePid
_kSecGuestAttributeCanonical
-_kSecGuestAttributeHash
_kSecGuestAttributeMachPort
-_kSecGuestAttributePid
_kSecCFErrorPattern
_kSecCFErrorResourceSeal
_kSecCFErrorResourceAdded
// sigblob - signature (Super)Blob types
//
#include "sigblob.h"
-#include "CSCommon.h"
namespace Security {
if (const BlobCore *blob = this->find(slot))
if (CodeDirectory::slotAttributes(slot) & cdComponentIsBlob)
return makeCFData(*blob); // is a native Blob
- else if (const BlobWrapper *wrap = BlobWrapper::specific(blob))
- return makeCFData(*wrap);
else
- MacOSError::throwMe(errSecCSSignatureInvalid);
+ return makeCFData(*BlobWrapper::specific(blob)); // unwrap payload
return NULL;
}
#include <Security/SecIdentity.h>
#include <Security/CMSEncoder.h>
#include <Security/CMSPrivate.h>
-#include <Security/CSCommonPriv.h>
#include <CoreFoundation/CFBundlePriv.h>
#include "renum.h"
-#include "machorep.h"
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
-#include <security_utilities/cfmunge.h>
+#include <security_codesigning/cfmunge.h>
namespace Security {
namespace CodeSigning {
//
void SecCodeSigner::Signer::sign(SecCSFlags flags)
{
+ // set up access to the subject Code
rep = code->diskRep()->base();
- this->prepare(flags);
- if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
- signMachO(fat);
- } else {
- signArchitectureAgnostic();
- }
-}
-
-
-//
-// Remove any existing code signature from code
-//
-void SecCodeSigner::Signer::remove(SecCSFlags flags)
-{
- // can't remove a detached signature
- if (state.mDetached)
- MacOSError::throwMe(errSecCSNotSupported);
-
- rep = code->diskRep();
- if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
- // architecture-sensitive removal
- MachOEditor editor(rep->writer(), *fat, rep->mainExecutablePath());
- editor.allocate(); // create copy
- editor.commit(); // commit change
- } else {
- // architecture-agnostic removal
- RefPointer<DiskRep::Writer> writer = rep->writer();
- writer->remove();
- writer->flush();
- }
-}
-
-
-//
-// Contemplate the object-to-be-signed and set up the Signer state accordingly.
-//
-void SecCodeSigner::Signer::prepare(SecCSFlags flags)
-{
+
// get the Info.plist out of the rep for some creative defaulting
CFRef<CFDictionaryRef> infoDict;
if (CFRef<CFDataRef> infoData = rep->component(cdInfoSlot))
identifier = state.mIdentifier;
if (identifier.empty()) {
identifier = rep->recommendedIdentifier();
- if (identifier.find('.') == string::npos)
+ if (identifier.find('.') == string::npos && !state.mIdentifierPrefix.empty())
identifier = state.mIdentifierPrefix + identifier;
secdebug("signer", "using default identifier=%s", identifier.c_str());
} else
if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags")))
if (CFGetTypeID(csflags) == CFNumberGetTypeID()) {
cdFlags = cfNumber<uint32_t>(CFNumberRef(csflags));
- secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags);
+ secdebug("signer", "using numeric cdFlags=0x%x from Info.dict", cdFlags);
} else if (CFGetTypeID(csflags) == CFStringGetTypeID()) {
- cdFlags = cdTextFlags(cfString(CFStringRef(csflags)));
- secdebug("signer", "using text cdFlags=0x%x from Info.plist", cdFlags);
+ cdFlags = CodeDirectory::textFlags(cfString(CFStringRef(csflags)));
+ secdebug("signer", "using text cdFlags=0x%x from Info.dict", cdFlags);
} else
MacOSError::throwMe(errSecCSBadDictionaryFormat);
}
if (state.mSigner == SecIdentityRef(kCFNull)) // ad-hoc signing requested...
- cdFlags |= kSecCodeSignatureAdhoc; // ... so note that
+ cdFlags |= kSecCodeSignatureAdhoc; // ... so allow that
// prepare the resource directory, if any
string rpath = rep->resourcesRootPath();
if (!rpath.empty()) {
// explicitly given resource rules always win
- CFCopyRef<CFDictionaryRef> resourceRules = state.mResourceRules;
+ CFCopyRef<CFDictionaryRef> resourceRules(state.mResourceRules);
// embedded resource rules come next
- if (!resourceRules && infoDict)
- if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey)) {
+ if (!resourceRules)
+ if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey))
if (CFGetTypeID(spec) == CFStringGetTypeID())
if (CFRef<CFDataRef> data = cfLoadFile(rpath + "/" + cfString(CFStringRef(spec))))
- if (CFDictionaryRef dict = makeCFDictionaryFrom(data))
- resourceRules.take(dict);
- if (!resourceRules) // embedded rules present but unacceptable
- MacOSError::throwMe(errSecCSResourceRulesInvalid);
- }
+ if (CFRef<CFDictionaryRef> dict = makeCFDictionaryFrom(data))
+ resourceRules = dict;
// finally, ask the DiskRep for its default
if (!resourceRules)
// build the resource directory
ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"));
- rep->adjustResources(resources); // DiskRep-specific adjustments
+ rep->adjustResources(resources);
CFRef<CFDictionaryRef> rdir = resources.build();
resourceDirectory.take(CFPropertyListCreateXMLData(NULL, rdir));
}
}
pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize();
+
+ if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
+ signMachO(fat);
+ } else {
+ signArchitectureAgnostic();
+ }
}
populate(arch);
populate(arch.cdbuilder, arch, arch.ireqs,
arch.source->offset(), arch.source->signingExtent());
-
- // add identification blob (made from this architecture) only if we're making a detached signature
- if (state.mDetached) {
- CFRef<CFDataRef> identification = MachORep::identificationFor(arch.source.get());
- arch.add(cdIdentificationSlot, BlobWrapper::alloc(
- CFDataGetBytePtr(identification), CFDataGetLength(identification)));
- }
-
// prepare SuperBlob size estimate
size_t cdSize = arch.cdbuilder.size();
arch.blobSize = arch.size(cdSize, state.mCMSSize, 0);
ireqs(state.mRequirements, rep->defaultRequirements(NULL));
populate(*writer);
populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit());
-
- // add identification blob (made from this architecture) only if we're making a detached signature
- if (state.mDetached) {
- CFRef<CFDataRef> identification = rep->identification();
- writer->component(cdIdentificationSlot, identification);
- }
-
CodeDirectory *cd = builder.build();
CFRef<CFDataRef> signature = signCodeDirectory(cd);
if (!state.mDryRun) {
builder.flags(cdFlags);
builder.identifier(identifier);
- if (CFDataRef data = rep->component(cdInfoSlot))
- builder.special(cdInfoSlot, data);
- if (ireqs) {
- CFRef<CFDataRef> data = makeCFData(*ireqs);
- writer.component(cdRequirementsSlot, data);
- builder.special(cdRequirementsSlot, data);
- }
- if (resourceDirectory)
- builder.special(cdResourceDirSlot, resourceDirectory);
+ for (CodeDirectory::Slot slot = cdSlotMax; slot >= 1; --slot)
+ switch (slot) {
+ case cdRequirementsSlot:
+ if (ireqs) {
+ CFRef<CFDataRef> data = makeCFData(*ireqs);
+ writer.component(cdRequirementsSlot, data);
+ builder.special(slot, data);
+ }
+ break;
+ case cdResourceDirSlot:
+ if (resourceDirectory)
+ builder.special(slot, resourceDirectory);
+ break;
+ case cdApplicationSlot:
#if NOT_YET
- if (state.mApplicationData)
- builder.special(cdApplicationSlot, state.mApplicationData);
+ if (state.mApplicationData)
+ builder.special(slot, state.mApplicationData);
#endif
- if (state.mEntitlementData) {
- writer.component(cdEntitlementSlot, state.mEntitlementData);
- builder.special(cdEntitlementSlot, state.mEntitlementData);
- }
-
- writer.addDiscretionary(builder);
+ break;
+ case cdEntitlementSlot:
+ if (state.mEntitlementData) {
+ writer.component(cdEntitlementSlot, state.mEntitlementData);
+ builder.special(slot, state.mEntitlementData);
+ }
+ break;
+ default:
+ if (CFDataRef data = rep->component(slot))
+ builder.special(slot, data);
+ break;
+ }
}
}
-//
-// Parse a text of the form
-// flag,...,flag
-// where each flag is the canonical name of a signable CodeDirectory flag.
-// No abbreviations are allowed, and internally set flags are not accepted.
-//
-uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text)
-{
- uint32_t flags = 0;
- for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) {
- string word = (comma == string::npos) ? text : text.substr(0, comma);
- const SecCodeDirectoryFlagTable *item;
- for (item = kSecCodeDirectoryFlagTable; item->name; item++)
- if (item->signable && word == item->name) {
- flags |= item->value;
- break;
- }
- if (!item->name) // not found
- MacOSError::throwMe(errSecCSInvalidFlags);
- if (comma == string::npos) // last word
- break;
- }
- return flags;
-}
-
-
} // end namespace CodeSigning
} // end namespace Security
public:
Signer(SecCodeSigner &s, SecStaticCode *c) : state(s), code(c) { }
void sign(SecCSFlags flags);
- void remove(SecCSFlags flags);
SecCodeSigner &state;
SecStaticCode * const code;
- std::string path() const { return cfString(rep->canonicalPath()); }
-
protected:
- void prepare(SecCSFlags flags); // set up signing parameters
void signMachO(Universal *fat); // sign a Mach-O binary
void signArchitectureAgnostic(); // sign anything else
void populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer,
InternalRequirements &ireqs, size_t offset = 0, size_t length = 0); // per-architecture
CFDataRef signCodeDirectory(const CodeDirectory *cd);
-
- uint32_t cdTextFlags(std::string text); // convert text CodeDirectory flags
private:
RefPointer<DiskRep> rep; // DiskRep of Code being signed
#include <Security/SecIdentity.h>
#include <Security/CMSEncoder.h>
#include "renum.h"
-#include "csutilities.h"
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
#include <vector>
// for helper validation
#include "Code.h"
-#include <security_utilities/cfmunge.h>
+#include "cfmunge.h"
#include <sys/codesign.h>
static const size_t csAlign = 16;
+//
+// InternalRequirements
+//
+void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted)
+{
+ if (defaulted) {
+ this->add(defaulted);
+ ::free((void *)defaulted); // was malloc(3)ed by DiskRep
+ }
+ if (given)
+ this->add(given);
+ mReqs = make();
+}
+
+
//
// BlobWriters
//
void DetachedBlobWriter::flush()
{
EmbeddedSignatureBlob *blob = this->make();
- signer.code->detachedSignature(makeCFData(*blob));
- signer.state.returnDetachedSignature(blob, signer);
+ signer.code->detachedSignature(CFTempData(*blob));
+ signer.state.returnDetachedSignature(blob);
::free(blob);
}
// finish up the superblob and deliver it
DetachedSignatureBlob *blob = mMaker.make();
- signer.state.returnDetachedSignature(blob, signer);
+ signer.state.returnDetachedSignature(blob);
::free(blob);
}
delete mNewCode;
if (mTempMayExist)
::remove(tempPath.c_str()); // ignore error (can't do anything about it)
- this->kill();
+
+ //@@@ this code should be in UnixChild::kill() -- migrate it there
+ if (state() == alive) {
+ this->kill(SIGTERM); // shoot it once
+ checkChildren(); // check for quick death
+ if (state() == alive) {
+ usleep(500000); // give it some grace
+ if (state() == alive) { // could have been reaped by another thread
+ checkChildren(); // check again
+ if (state() == alive) { // it... just... won't... die...
+ this->kill(SIGKILL); // take THAT!
+ checkChildren();
+ if (state() == alive) // stuck zombie
+ abandon(); // leave the body behind
+ }
+ }
+ }
+ }
}
mNewCode = new Universal(mFd);
}
-static const unsigned char appleReq[] = {
- // anchor apple and info["Application-Group"] = "com.apple.tool.codesign_allocate"
- 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x41, 0x70, 0x70, 0x6c,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
- 0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f,
- 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65,
+static const unsigned char appleReq[] = { // anchor apple
+ 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
};
void MachOEditor::parentAction()
{
if (mHelperOverridden) {
- CODESIGN_ALLOCATE_VALIDATE((char*)mHelperPath, this->pid());
+ secdebug("machoedit", "validating alternate codesign_allocate at %s (pid=%d)", mHelperPath, this->pid());
// check code identity of an overridden allocation helper
SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(mHelperPath));
code->validateDirectory();
arguments.push_back(tempPath.c_str());
for (Iterator it = architecture.begin(); it != architecture.end(); ++it) {
- size_t size = LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign);
- char *ssize; // we'll leak this (execv is coming soon)
- asprintf(&ssize, "%d", size);
+ char *size; // we'll leak this (execv is coming soon)
+ asprintf(&size, "%d", LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign));
+ secdebug("machoedit", "preparing %s size=%s", it->first.name(), size);
if (const char *arch = it->first.name()) {
- CODESIGN_ALLOCATE_ARCH((char*)arch, size);
arguments.push_back("-a");
arguments.push_back(arch);
} else {
- CODESIGN_ALLOCATE_ARCHN(it->first.cpuType(), it->first.cpuSubtype(), size);
arguments.push_back("-A");
char *anum;
asprintf(&anum, "%d", it->first.cpuType());
asprintf(&anum, "%d", it->first.cpuSubtype());
arguments.push_back(anum);
}
- arguments.push_back(ssize);
+ arguments.push_back(size);
}
arguments.push_back(NULL);
{
if (size_t offset = arch.source->signingOffset()) {
size_t signingLength = arch.source->signingLength();
- CODESIGN_ALLOCATE_WRITE((char*)arch.architecture.name(), offset, blob->length(), signingLength);
+ secdebug("codesign", "writing architecture %s at 0x%zx (%zd of %zd)",
+ arch.architecture.name(), offset, blob->length(), signingLength);
if (signingLength < blob->length())
MacOSError::throwMe(errSecCSCMSTooLarge);
arch.source->seek(offset);
}
+//
+// Copyfile
+//
+Copyfile::Copyfile()
+{
+ if (!(mState = copyfile_state_alloc()))
+ UnixError::throwMe();
+}
+
+void Copyfile::set(uint32_t flag, const void *value)
+{
+ check(::copyfile_state_set(mState, flag, value));
+}
+
+void Copyfile::get(uint32_t flag, void *value)
+{
+ check(::copyfile_state_set(mState, flag, value));
+}
+
+void Copyfile::operator () (const char *src, const char *dst, copyfile_flags_t flags)
+{
+ check(::copyfile(src, dst, mState, flags));
+}
+
+void Copyfile::check(int rc)
+{
+ if (rc < 0)
+ UnixError::throwMe();
+}
+
+
} // end namespace CodeSigning
} // end namespace Security
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
+extern "C" {
+#include <copyfile.h>
+}
+
namespace Security {
namespace CodeSigning {
+//
+// A helper to deal with the magic merger logic of internal requirements
+//
+class InternalRequirements : public Requirements::Maker {
+public:
+ InternalRequirements() : mReqs(NULL) { }
+ ~InternalRequirements() { ::free((void *)mReqs); }
+ void operator () (const Requirements *given, const Requirements *defaulted);
+ operator const Requirements * () const { return mReqs; }
+
+private:
+ const Requirements *mReqs;
+};
+
+
//
// A DiskRep::Writer that assembles data in a SuperBlob (in memory)
//
class BlobEditor : public ArchEditor {
public:
BlobEditor(Universal &fat, SecCodeSigner::Signer &s) : ArchEditor(fat), signer(s) { }
+ ~BlobEditor() { }
SecCodeSigner::Signer &signer;
};
+//
+// Encapsulation of the copyfile(3) API.
+// This is slated to go into utilities once stable.
+//
+class Copyfile {
+public:
+ Copyfile();
+ ~Copyfile() { copyfile_state_free(mState); }
+
+ operator copyfile_state_t () const { return mState; }
+
+ void set(uint32_t flag, const void *value);
+ void get(uint32_t flag, void *value);
+
+ void operator () (const char *src, const char *dst, copyfile_flags_t flags);
+
+private:
+ void check(int rc);
+
+private:
+ copyfile_state_t mState;
+};
+
+
+//
+// A reliable uid set/reset bracket
+//
+class UidGuard {
+public:
+ UidGuard() : mPrevious(-1) { }
+ UidGuard(uid_t uid) : mPrevious(-1) { seteuid(uid); }
+ ~UidGuard()
+ {
+ if (active())
+ UnixError::check(::seteuid(mPrevious));
+ }
+
+ bool seteuid(uid_t uid)
+ {
+ if (uid == geteuid())
+ return true; // no change, don't bother the kernel
+ if (!active())
+ mPrevious = ::geteuid();
+ return ::seteuid(uid) == 0;
+ }
+
+ bool active() const { return mPrevious != uid_t(-1); }
+ operator bool () const { return active(); }
+ uid_t saved() const { assert(active()); return mPrevious; }
+
+private:
+ uid_t mPrevious;
+};
+
+
} // end namespace CodeSigning
} // end namespace Security
// singlediskrep - semi-abstract diskrep for a single file of some kind
//
#include "singlediskrep.h"
-#include "csutilities.h"
-#include <security_utilities/cfutilities.h>
+
namespace Security {
namespace CodeSigning {
//
// Construct a SingleDiskRep
//
-SingleDiskRep::SingleDiskRep(const std::string &path)
+SingleDiskRep::SingleDiskRep(const char *path)
: mPath(path)
{
}
-//
-// The default binary identification of a SingleDiskRep is the (SHA-1) hash
-// of the entire file itself.
-//
-CFDataRef SingleDiskRep::identification()
-{
- SHA1 hash;
- this->fd().seek(0);
- hashFileData(this->fd(), hash);
- SHA1::Digest digest;
- hash.finish(digest);
- return makeCFData(digest, sizeof(digest));
-}
-
-
//
// Both the canonical and main executable path of a SingleDiskRep is, well, its path.
//
//
class SingleDiskRep : public DiskRep {
public:
- SingleDiskRep(const std::string &path);
+ SingleDiskRep(const char *path);
- CFDataRef identification(); // partial file hash
std::string mainExecutablePath(); // base path
CFURLRef canonicalPath(); // base path
std::string recommendedIdentifier(); // basename(path)
+++ /dev/null
-/*
- * Copyright (c) 2009 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-//
-// slcrep - DiskRep representing the Mac OS Shared Library Cache
-//
-#include "slcrep.h"
-
-
-namespace Security {
-namespace CodeSigning {
-
-using namespace UnixPlusPlus;
-
-
-//
-// Object management.
-// We open the file lazily, so nothing much happens on constructions.
-// We can construct directly from a file path, or from an architecture
-// (represented by Context), which will find the file in its usual
-// location on disk.
-//
-DYLDCacheRep::DYLDCacheRep(const char *path)
- : SingleDiskRep(path), mCache(path)
-{
- this->setup();
-}
-
-DYLDCacheRep::DYLDCacheRep(const Context *ctx)
- : SingleDiskRep(DYLDCache::pathFor(((ctx && ctx->arch) ? ctx->arch : Architecture::local()))),
- mCache(this->path())
-{
- this->setup();
-}
-
-void DYLDCacheRep::setup()
-{
- mSigningData = NULL;
- if (mCache.totalSize() >= mCache.mapSize() + sizeof(BlobCore)) {
- const EmbeddedSignatureBlob *blob = mCache.at<const EmbeddedSignatureBlob>(mCache.mapSize());
- if (mCache.totalSize() >= mCache.mapSize() + blob->length()) // entire blob fits in file
- mSigningData = blob;
- }
- CODESIGN_DISKREP_CREATE_SLC(this, (char*)this->mainExecutablePath().c_str());
-}
-
-
-//
-// Sniffer function for "plausible shared library cache file".
-//
-bool DYLDCacheRep::candidate(FileDesc &fd)
-{
- return DYLDCache::validate(fd);
-}
-
-
-//
-// Default to system page size for segmented (paged) signatures
-//
-size_t DYLDCacheRep::pageSize()
-{
- return segmentedPageSize;
-}
-
-
-//
-// Retrieve a component from the executable.
-// Our mCache has mapped the entire file, so we just fish the contents out of
-// the mapped area as needed.
-//
-CFDataRef DYLDCacheRep::component(CodeDirectory::SpecialSlot slot)
-{
- return mSigningData ? mSigningData->component(slot) : NULL;
-}
-
-
-//
-// Provide a (vaguely) human readable characterization of this code
-//
-string DYLDCacheRep::format()
-{
- if (const char *name = mCache.architecture().name()) {
- char result[100];
- snprintf(result, sizeof(result), "OS X Shared Library Cache (%s @ 0x%llx)",
- name, mCache.baseAddress());
- return result;
- } else
- return "OS X Shared Library Cache (unknown type)";
-}
-
-
-//
-// DYLDCacheRep::Writers
-//
-DiskRep::Writer *DYLDCacheRep::writer()
-{
- return new Writer(this);
-}
-
-
-//
-// Write a component.
-//
-void DYLDCacheRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
-{
- EmbeddedSignatureBlob::Maker::component(slot, data);
-}
-
-
-//
-// Append the superblob we built to the cache file.
-//
-void DYLDCacheRep::Writer::flush()
-{
- delete mSigningData; // ditch previous blob just in case
- mSigningData = Maker::make(); // assemble new signature SuperBlob
- fd().seek(rep->mCache.mapSize()); // end of impage proper
- fd().writeAll(*mSigningData);
-}
-
-
-//
-// The discretionary additions insert a Scatter vector describing the file's mapping table.
-//
-void DYLDCacheRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
-{
- unsigned count = rep->mCache.mappingCount();
- builder.scatter(count);
- for (unsigned n = 0; n < count; n++) {
- const DYLDCache::Mapping dmap = rep->mCache.mapping(n);
- CodeDirectory::Scatter *scatter = builder.scatter() + n;
- scatter->targetOffset = dmap.address();
- scatter->base = dmap.offset() / segmentedPageSize;
- assert(dmap.offset() % segmentedPageSize == 0);
- scatter->count = dmap.size() / segmentedPageSize;
- assert(dmap.size() % segmentedPageSize == 0);
- }
-}
-
-
-} // end namespace CodeSigning
-} // end namespace Security
+++ /dev/null
-/*
- * Copyright (c) 2009 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-//
-// slcrep - DiskRep representing the Mac OS Shared Library Cache
-//
-#ifndef _H_SLCREP
-#define _H_SLCREP
-
-#include "singlediskrep.h"
-#include "sigblob.h"
-#include <security_utilities/unix++.h>
-#include <security_utilities/macho++.h>
-#include <security_utilities/dyldcache.h>
-
-namespace Security {
-namespace CodeSigning {
-
-
-//
-// DYLDCacheRep implements the on-disk format for the Mac OS X
-// Shared Library Cache, which coalesces a set of system libraries
-// and frameworks into one big (mappable) code blob in the sky.
-//
-class DYLDCacheRep : public SingleDiskRep {
-public:
- DYLDCacheRep(const Context *ctx = NULL);
- DYLDCacheRep(const char *path);
-
- CFDataRef component(CodeDirectory::SpecialSlot slot);
- size_t pageSize();
- std::string format();
-
- static bool candidate(UnixPlusPlus::FileDesc &fd);
-
-public:
- static CFDataRef identificationFor(MachO *macho);
-
-public:
- DiskRep::Writer *writer();
- class Writer;
- friend class Writer;
-
-private:
- void setup();
-
-private:
- DYLDCache mCache;
- const EmbeddedSignatureBlob *mSigningData; // pointer to signature SuperBlob (in mapped memory)
-};
-
-
-//
-// The write side of a FileDiskRep
-//
-class DYLDCacheRep::Writer : public SingleDiskRep::Writer, private EmbeddedSignatureBlob::Maker {
- friend class FileDiskRep;
-public:
- Writer(DYLDCacheRep *r) : SingleDiskRep::Writer(r, writerNoGlobal), rep(r), mSigningData(NULL) { }
- void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
- void flush();
- void addDiscretionary(CodeDirectory::Builder &builder);
-
-private:
- DYLDCacheRep *rep;
- EmbeddedSignatureBlob *mSigningData;
-};
-
-
-} // end namespace CodeSigning
-} // end namespace Security
-
-#endif // !_H_SLCREP
objects = {
/* Begin PBXAggregateTarget section */
- C26AC7090DAEB3A7005BFB40 /* DTrace */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = C26AC70D0DAEB3C6005BFB40 /* Build configuration list for PBXAggregateTarget "DTrace" */;
- buildPhases = (
- C26AC7080DAEB3A7005BFB40 /* ShellScript */,
- );
- dependencies = (
- );
- name = DTrace;
- productName = DTrace;
- };
C2D383B80A23A8C4005C63A2 /* Requirements Language */ = {
isa = PBXAggregateTarget;
buildConfigurationList = C2D383C00A23A8E3005C63A2 /* Build configuration list for PBXAggregateTarget "Requirements Language" */;
/* Begin PBXBuildFile section */
C2093AA80BB0948000EB8599 /* reqreader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2093AA60BB0948000EB8599 /* reqreader.cpp */; };
+ C2093AA90BB0948000EB8599 /* reqreader.h in Headers */ = {isa = PBXBuildFile; fileRef = C2093AA70BB0948000EB8599 /* reqreader.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2093AC80BB0967D00EB8599 /* reqreader.h in Headers */ = {isa = PBXBuildFile; fileRef = C2093AA70BB0948000EB8599 /* reqreader.h */; settings = {ATTRIBUTES = (Public, ); }; };
C21CFC5F0A250D1C006CD5B1 /* reqdumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */; };
C21CFC620A250D1C006CD5B1 /* reqdumper.h in Headers */ = {isa = PBXBuildFile; fileRef = C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */; settings = {ATTRIBUTES = (Public, ); }; };
C21EA3DD0AD2F81300E6E31C /* SecCodeSigner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */; };
+ C21EA3DE0AD2F81300E6E31C /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
C21EA3E00AD2F81300E6E31C /* SecCodeSigner.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
C21EA3E30AD2FA0900E6E31C /* CodeSigner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */; };
C224635F0B8620F800626F1B /* RequirementParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383F00A23A9D3005C63A2 /* RequirementParser.cpp */; };
C22463600B8620F800626F1B /* RequirementLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383EE0A23A9D3005C63A2 /* RequirementLexer.cpp */; };
C22463610B86210100626F1B /* antlrplugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CC31130B85254F005FA59D /* antlrplugin.cpp */; };
C236E3D70AD59446000F5140 /* signer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D50AD59446000F5140 /* signer.cpp */; };
+ C236E3D80AD59446000F5140 /* signer.h in Headers */ = {isa = PBXBuildFile; fileRef = C236E3D60AD59446000F5140 /* signer.h */; };
C236E3DB0AD595C2000F5140 /* signerutils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D90AD595C2000F5140 /* signerutils.cpp */; };
+ C236E3DC0AD595C2000F5140 /* signerutils.h in Headers */ = {isa = PBXBuildFile; fileRef = C236E3DA0AD595C2000F5140 /* signerutils.h */; };
C250F6C30B5EF1910076098F /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
+ C25942440BA7095000877E56 /* foreigndiskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25942420BA7095000877E56 /* foreigndiskrep.cpp */; };
+ C25942450BA7095000877E56 /* foreigndiskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C25942430BA7095000877E56 /* foreigndiskrep.h */; };
C259DFD60AD6D9BA00C9ACC6 /* sigblob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */; };
+ C259DFD70AD6D9BA00C9ACC6 /* sigblob.h in Headers */ = {isa = PBXBuildFile; fileRef = C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */; };
C26B45C10B8A9C0A003C0ACA /* ucspc in Frameworks */ = {isa = PBXBuildFile; fileRef = C26B45C00B8A9C00003C0ACA /* ucspc */; };
- C26FF62D0E5B375A00F640A0 /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF62E0E5B375A00F640A0 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF62F0E5B376B00F640A0 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C26FF6300E5B376B00F640A0 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C26FF6310E5B376B00F640A0 /* CSCommonPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF6320E5B376B00F640A0 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C26FF6330E5B376B00F640A0 /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF6340E5B376B00F640A0 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C26FF6350E5B376B00F640A0 /* SecStaticCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF6360E5B376B00F640A0 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C26FF6370E5B376B00F640A0 /* SecRequirementPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF6380E5B376B00F640A0 /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C26FF6390E5B376B00F640A0 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C26FF63A0E5B376B00F640A0 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C28342E60E366E6800E54360 /* csdatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = C28342E50E366E6800E54360 /* csdatabase.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C28342E70E366E6800E54360 /* csdatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28342E40E366E6800E54360 /* csdatabase.cpp */; };
- C28342ED0E36719D00E54360 /* detachedrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C28342EC0E36719D00E54360 /* detachedrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C28342EE0E36719D00E54360 /* detachedrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28342EB0E36719D00E54360 /* detachedrep.cpp */; };
C297DF250B014BB300E94EE0 /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2A436150F2133B2007A41A6 /* slcrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2A436130F2133B2007A41A6 /* slcrep.cpp */; };
- C2A436160F2133B2007A41A6 /* slcrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A436140F2133B2007A41A6 /* slcrep.h */; };
+ C2A36B4B0D906C08003412BA /* resources.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E911E10ADEBE3200275CB2 /* resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2A487530B7914F400849490 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2A487540B79150C00849490 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2A487550B79152A00849490 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2A487560B79152A00849490 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2A752B70B80EAFB004CF655 /* SecIntegrity.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
C2A752B80B80EAFB004CF655 /* SecCodeHostLib.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; };
C2A976AA0B8A2E36008B4EA0 /* csutilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */; };
+ C2A976AB0B8A2E36008B4EA0 /* csutilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A976A90B8A2E36008B4EA0 /* csutilities.h */; };
C2BC1F350B580DA7003EC9DC /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; };
C2BD519C0A9392FD000FE43D /* machorep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2BD519A0A9392FD000FE43D /* machorep.cpp */; };
C2BD519F0A9392FD000FE43D /* machorep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BD519B0A9392FD000FE43D /* machorep.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2BD61BD0AC9C77B0057FD3D /* csgeneric.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BD60F90AC863FC0057FD3D /* csgeneric.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2C1DF140A2E3D7200D1B02B /* requirement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383350A237F47005C63A2 /* requirement.cpp */; };
C2C1DFBB0A2F80EB00D1B02B /* reqinterp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C1DFB90A2F80EB00D1B02B /* reqinterp.cpp */; };
+ C2C1DFBC0A2F80EB00D1B02B /* reqinterp.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFBA0A2F80EB00D1B02B /* reqinterp.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2C1DFBE0A2F80EB00D1B02B /* reqinterp.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFBA0A2F80EB00D1B02B /* reqinterp.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2C1DFC30A2F820500D1B02B /* reqmaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C1DFC10A2F820500D1B02B /* reqmaker.cpp */; };
+ C2C1DFC40A2F820500D1B02B /* reqmaker.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFC20A2F820500D1B02B /* reqmaker.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2C1DFC60A2F820500D1B02B /* reqmaker.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFC20A2F820500D1B02B /* reqmaker.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2C315D70D9319E800E7AA0C /* csutilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A976A90B8A2E36008B4EA0 /* csutilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2C3BC5F0BA1D6FE00E869D1 /* cfmdiskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C3BC5D0BA1D6FE00E869D1 /* cfmdiskrep.cpp */; };
+ C2C3BC600BA1D6FE00E869D1 /* cfmdiskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C3BC5E0BA1D6FE00E869D1 /* cfmdiskrep.h */; };
C2C3BCD30BA1E47E00E869D1 /* singlediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C3BCD10BA1E47E00E869D1 /* singlediskrep.cpp */; };
+ C2C3BCD40BA1E47E00E869D1 /* singlediskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C3BCD20BA1E47E00E869D1 /* singlediskrep.h */; };
C2C931B40AB8BA1200F83950 /* SecCodeHost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C931B30AB8BA1200F83950 /* SecCodeHost.cpp */; };
+ C2C931B50AB8BA8200F83950 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2C931B60AB8BAC200F83950 /* SecCodeHost.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; };
C2CC31050B8523AD005FA59D /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2CC31060B8523F8005FA59D /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2CC310F0B852424005FA59D /* SecIntegrityLib.c in Sources */ = {isa = PBXBuildFile; fileRef = C2CC310E0B852424005FA59D /* SecIntegrityLib.c */; };
C2CC31100B852447005FA59D /* SecIntegrityLib.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; };
- C2CFB9C70DF8789A003F57E4 /* SecCodeHost.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; };
- C2D213870D9844F700E76E7D /* resources.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E911E10ADEBE3200275CB2 /* resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C2CCF0310A3F523D0085795A /* macho++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CCF02F0A3F523D0085795A /* macho++.cpp */; };
+ C2CCF0340A3F523D0085795A /* macho++.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CCF0300A3F523D0085795A /* macho++.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2D3833C0A237F47005C63A2 /* bundlediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383120A237F47005C63A2 /* bundlediskrep.cpp */; };
C2D3833E0A237F47005C63A2 /* cdbuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383140A237F47005C63A2 /* cdbuilder.cpp */; };
C2D383400A237F47005C63A2 /* codedirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383160A237F47005C63A2 /* codedirectory.cpp */; };
C2D383440A237F47005C63A2 /* cs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3831A0A237F47005C63A2 /* cs.cpp */; };
+ C2D383460A237F47005C63A2 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D383470A237F47005C63A2 /* SecCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3831D0A237F47005C63A2 /* SecCode.cpp */; };
+ C2D383480A237F47005C63A2 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D383490A237F47005C63A2 /* cskernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3831F0A237F47005C63A2 /* cskernel.cpp */; };
C2D3834B0A237F47005C63A2 /* SecStaticCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383210A237F47005C63A2 /* SecStaticCode.cpp */; };
+ C2D3834C0A237F47005C63A2 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D3834D0A237F47005C63A2 /* csprocess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383230A237F47005C63A2 /* csprocess.cpp */; };
C2D3834F0A237F47005C63A2 /* SecRequirement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383250A237F47005C63A2 /* SecRequirement.cpp */; };
+ C2D383500A237F47005C63A2 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D383510A237F47005C63A2 /* diskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383270A237F47005C63A2 /* diskrep.cpp */; };
C2D383550A237F47005C63A2 /* filediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3832B0A237F47005C63A2 /* filediskrep.cpp */; };
C2D383570A237F47005C63A2 /* Code.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3832D0A237F47005C63A2 /* Code.cpp */; };
C2D3835B0A237F47005C63A2 /* StaticCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383310A237F47005C63A2 /* StaticCode.cpp */; };
C2D3835D0A237F47005C63A2 /* reqparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383330A237F47005C63A2 /* reqparser.cpp */; };
C2D383610A237F47005C63A2 /* Requirements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383370A237F47005C63A2 /* Requirements.cpp */; };
+ C2D383630A237F47005C63A2 /* security_codesigning.exp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383390A237F47005C63A2 /* security_codesigning.exp */; };
C2D383670A237F47005C63A2 /* bundlediskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383130A237F47005C63A2 /* bundlediskrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2D383690A237F47005C63A2 /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2D3836B0A237F47005C63A2 /* codedirectory.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383170A237F47005C63A2 /* codedirectory.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2D3836C0A237F47005C63A2 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2D3836D0A237F47005C63A2 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C2D3836C0A237F47005C63A2 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2D3836D0A237F47005C63A2 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D3836F0A237F47005C63A2 /* cs.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831B0A237F47005C63A2 /* cs.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2D383700A237F47005C63A2 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2D383720A237F47005C63A2 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C2D383700A237F47005C63A2 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2D383720A237F47005C63A2 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D383740A237F47005C63A2 /* cskernel.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383200A237F47005C63A2 /* cskernel.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2D383760A237F47005C63A2 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C2D383760A237F47005C63A2 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D383780A237F47005C63A2 /* csprocess.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383240A237F47005C63A2 /* csprocess.h */; settings = {ATTRIBUTES = (Public, ); }; };
- C2D3837A0A237F47005C63A2 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C2D3837A0A237F47005C63A2 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D3837C0A237F47005C63A2 /* diskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383280A237F47005C63A2 /* diskrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2D383800A237F47005C63A2 /* filediskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3832C0A237F47005C63A2 /* filediskrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2D383820A237F47005C63A2 /* Code.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3832E0A237F47005C63A2 /* Code.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2D383920A23803A005C63A2 /* SecCode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; };
C2D383930A23803A005C63A2 /* SecStaticCode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; };
C2D383940A23803A005C63A2 /* SecRequirement.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; };
+ C2D3839A0A238132005C63A2 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; };
- C2D50CE10E155ABC0059A195 /* CSCommonPriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2D50CE20E155AE60059A195 /* CSCommonPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C2D8A07F0AE7F6E300F68F79 /* cfmunge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D8A07D0AE7F6E300F68F79 /* cfmunge.cpp */; };
+ C2D8A0800AE7F6E300F68F79 /* cfmunge.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */; };
+ C2D8A0980AE7F74500F68F79 /* cfmunge.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2E2873D0B5D8D80009336A0 /* SecCodeHostLib.c in Sources */ = {isa = PBXBuildFile; fileRef = C2E2873C0B5D8D80009336A0 /* SecCodeHostLib.c */; };
- C2E8AF2A0DE25D11000F6D3B /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2E8AF2B0DE25D11000F6D3B /* SecStaticCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2E8AF2C0DE25D11000F6D3B /* SecRequirementPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C2E8AF2D0DE25D74000F6D3B /* SecCodePriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */; };
- C2E8AF2E0DE25D74000F6D3B /* SecStaticCodePriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */; };
- C2E8AF2F0DE25D74000F6D3B /* SecRequirementPriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */; };
C2E911E20ADEBE3200275CB2 /* resources.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2E911E00ADEBE3200275CB2 /* resources.cpp */; };
+ C2E911E30ADEBE3200275CB2 /* resources.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E911E10ADEBE3200275CB2 /* resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2EF10100A49BD89005A44BB /* renum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2EF100E0A49BD89005A44BB /* renum.cpp */; };
+ C2EF10110A49BD89005A44BB /* renum.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EF100F0A49BD89005A44BB /* renum.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2EF10130A49BD89005A44BB /* renum.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EF100F0A49BD89005A44BB /* renum.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F6566C0BCBFB250078779E /* cserror.cpp */; };
+ C2F6566F0BCBFB250078779E /* cserror.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F6566D0BCBFB250078779E /* cserror.h */; };
C2F656930BCBFFF40078779E /* cserror.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F6566D0BCBFB250078779E /* cserror.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */
remoteGlobalIDString = C2BC1F250B580D3A003EC9DC;
remoteInfo = libintegrity;
};
- C26AC70E0DAEB400005BFB40 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = C26AC7090DAEB3A7005BFB40;
- remoteInfo = DTrace;
- };
C2E287400B5D8F97009336A0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
dstPath = SecurityPieces/Headers/Security;
dstSubfolderSpec = 16;
files = (
- C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */,
- C2D383910A23803A005C63A2 /* CSCommon.h in CopyFiles */,
- C2D383920A23803A005C63A2 /* SecCode.h in CopyFiles */,
- C2D383930A23803A005C63A2 /* SecStaticCode.h in CopyFiles */,
- C2D383940A23803A005C63A2 /* SecRequirement.h in CopyFiles */,
- C2CFB9C70DF8789A003F57E4 /* SecCodeHost.h in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
dstPath = SecurityPieces/PrivateHeaders/Security;
dstSubfolderSpec = 16;
files = (
- C2D50CE10E155ABC0059A195 /* CSCommonPriv.h in CopyFiles */,
- C2E8AF2D0DE25D74000F6D3B /* SecCodePriv.h in CopyFiles */,
- C2E8AF2E0DE25D74000F6D3B /* SecStaticCodePriv.h in CopyFiles */,
- C2E8AF2F0DE25D74000F6D3B /* SecRequirementPriv.h in CopyFiles */,
C2CC31100B852447005FA59D /* SecIntegrityLib.h in CopyFiles */,
C21EA3E00AD2F81300E6E31C /* SecCodeSigner.h in CopyFiles */,
+ C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */,
+ C2D383910A23803A005C63A2 /* CSCommon.h in CopyFiles */,
+ C2D383920A23803A005C63A2 /* SecCode.h in CopyFiles */,
+ C2D383930A23803A005C63A2 /* SecStaticCode.h in CopyFiles */,
+ C2D383940A23803A005C63A2 /* SecRequirement.h in CopyFiles */,
+ C2C931B60AB8BAC200F83950 /* SecCodeHost.h in CopyFiles */,
C2A752B70B80EAFB004CF655 /* SecIntegrity.h in CopyFiles */,
C2A752B80B80EAFB004CF655 /* SecCodeHostLib.h in CopyFiles */,
);
/* Begin PBXFileReference section */
4C56351E0540A55300DCF0C8 /* security_codesigning.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = security_codesigning.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 4CA1FEBE052A3C8100F22E42 /* security_codesigning */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = security_codesigning; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4CA1FEBE052A3C8100F22E42 /* security_codesigning */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = security_codesigning; sourceTree = BUILT_PRODUCTS_DIR; };
C2093AA60BB0948000EB8599 /* reqreader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqreader.cpp; sourceTree = "<group>"; };
C2093AA70BB0948000EB8599 /* reqreader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqreader.h; sourceTree = "<group>"; };
C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqdumper.cpp; sourceTree = "<group>"; };
C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = "<group>"; };
C250F6C20B5EF1910076098F /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrity.h; sourceTree = "<group>"; };
C250F6C60B5EF5B50076098F /* SecIntegrity.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecIntegrity.cpp; sourceTree = "<group>"; };
+ C25942420BA7095000877E56 /* foreigndiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = foreigndiskrep.cpp; sourceTree = "<group>"; };
+ C25942430BA7095000877E56 /* foreigndiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = foreigndiskrep.h; sourceTree = "<group>"; };
C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = sigblob.cpp; sourceTree = "<group>"; };
C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sigblob.h; sourceTree = "<group>"; };
- C26AC6FD0DAEB2C4005BFB40 /* security_codesigning.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = security_codesigning.d; sourceTree = "<group>"; };
C26B45C00B8A9C00003C0ACA /* ucspc */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = ucspc; sourceTree = "<group>"; };
- C28342E40E366E6800E54360 /* csdatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = csdatabase.cpp; sourceTree = "<group>"; };
- C28342E50E366E6800E54360 /* csdatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = csdatabase.h; sourceTree = "<group>"; };
- C28342EB0E36719D00E54360 /* detachedrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = detachedrep.cpp; sourceTree = "<group>"; };
- C28342EC0E36719D00E54360 /* detachedrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = detachedrep.h; sourceTree = "<group>"; };
- C2A436130F2133B2007A41A6 /* slcrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slcrep.cpp; sourceTree = "<group>"; };
- C2A436140F2133B2007A41A6 /* slcrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slcrep.h; sourceTree = "<group>"; };
C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = "<group>"; };
C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = "<group>"; };
- C2B9F1D20D51646600CAB713 /* RequirementKeywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequirementKeywords.h; sourceTree = "<group>"; };
C2BC1F260B580D3A003EC9DC /* libintegrity.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libintegrity.a; sourceTree = BUILT_PRODUCTS_DIR; };
C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcodehost.a; sourceTree = BUILT_PRODUCTS_DIR; };
C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeHostLib.h; sourceTree = "<group>"; };
C2C3BC5E0BA1D6FE00E869D1 /* cfmdiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cfmdiskrep.h; sourceTree = "<group>"; };
C2C3BCD10BA1E47E00E869D1 /* singlediskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = singlediskrep.cpp; sourceTree = "<group>"; };
C2C3BCD20BA1E47E00E869D1 /* singlediskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = singlediskrep.h; sourceTree = "<group>"; };
- C2C4F4EE0E0980C700137848 /* codesigning_dtrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = codesigning_dtrace.h; sourceTree = "<group>"; };
C2C931B30AB8BA1200F83950 /* SecCodeHost.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeHost.cpp; sourceTree = "<group>"; };
C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CoreFoundation.framework; sourceTree = "<group>"; };
C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrityLib.h; sourceTree = "<group>"; };
C2CC310E0B852424005FA59D /* SecIntegrityLib.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SecIntegrityLib.c; sourceTree = "<group>"; };
C2CC31130B85254F005FA59D /* antlrplugin.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = antlrplugin.cpp; path = lib/antlrplugin.cpp; sourceTree = "<group>"; };
C2CC31140B85254F005FA59D /* antlrplugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = antlrplugin.h; path = lib/antlrplugin.h; sourceTree = "<group>"; };
+ C2CCF02F0A3F523D0085795A /* macho++.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "macho++.cpp"; sourceTree = "<group>"; };
+ C2CCF0300A3F523D0085795A /* macho++.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "macho++.h"; sourceTree = "<group>"; };
C2D383120A237F47005C63A2 /* bundlediskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = bundlediskrep.cpp; sourceTree = "<group>"; };
C2D383130A237F47005C63A2 /* bundlediskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = bundlediskrep.h; sourceTree = "<group>"; };
C2D383140A237F47005C63A2 /* cdbuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cdbuilder.cpp; sourceTree = "<group>"; };
C2D383F10A23A9D3005C63A2 /* RequirementParser.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RequirementParser.hpp; sourceTree = "<group>"; };
C2D383F20A23A9D3005C63A2 /* RequirementParserTokenTypes.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RequirementParserTokenTypes.hpp; sourceTree = "<group>"; };
C2D383F30A23A9D3005C63A2 /* RequirementParserTokenTypes.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = RequirementParserTokenTypes.txt; sourceTree = "<group>"; };
- C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSCommonPriv.h; sourceTree = "<group>"; };
+ C2D8A07D0AE7F6E300F68F79 /* cfmunge.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cfmunge.cpp; sourceTree = "<group>"; };
+ C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cfmunge.h; sourceTree = "<group>"; };
C2E2873C0B5D8D80009336A0 /* SecCodeHostLib.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SecCodeHostLib.c; sourceTree = "<group>"; };
- C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCodePriv.h; sourceTree = "<group>"; };
- C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRequirementPriv.h; sourceTree = "<group>"; };
- C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecStaticCodePriv.h; sourceTree = "<group>"; };
C2E911E00ADEBE3200275CB2 /* resources.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = resources.cpp; sourceTree = "<group>"; };
C2E911E10ADEBE3200275CB2 /* resources.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = resources.h; sourceTree = "<group>"; };
C2EF100E0A49BD89005A44BB /* renum.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = renum.cpp; sourceTree = "<group>"; };
C2F6566D0BCBFB250078779E /* cserror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cserror.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
+/* Begin PBXFrameworkTarget section */
+ 4C56351D0540A55300DCF0C8 /* security_codesigning */ = {
+ isa = PBXFrameworkTarget;
+ buildConfigurationList = C263E67109A2971B000043F1 /* Build configuration list for PBXFrameworkTarget "security_codesigning" */;
+ buildPhases = (
+ 4C5635180540A55300DCF0C8 /* Headers */,
+ 4CCB00500580097400981D43 /* CopyFiles */,
+ 4CCB00510580097600981D43 /* CopyFiles */,
+ 4CCB00520580097800981D43 /* CopyFiles */,
+ C26C39D3068368EC00ED5782 /* CopyFiles */,
+ );
+ dependencies = (
+ );
+ name = security_codesigning;
+ productInstallPath = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ productName = security_codesigning;
+ productReference = 4C56351E0540A55300DCF0C8 /* security_codesigning.framework */;
+ productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict/>
+</plist>
+";
+ };
+/* End PBXFrameworkTarget section */
+
/* Begin PBXFrameworksBuildPhase section */
4CA1FEBB052A3C8100F22E42 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
C2C1DF640A2E45F500D1B02B /* Code Classes */,
C2C1DF610A2E459E00D1B02B /* Disk Representations */,
C2BC1F370B580DAE003EC9DC /* Static Support */,
- C26AC6FF0DAEB2D0005BFB40 /* DTrace */,
C2CCF0360A3F524B0085795A /* Local Utilities */,
C2CC31160B852554005FA59D /* Security Plugins */,
);
name = "Signing Operations";
sourceTree = "<group>";
};
- C26AC6FF0DAEB2D0005BFB40 /* DTrace */ = {
- isa = PBXGroup;
- children = (
- C26AC6FD0DAEB2C4005BFB40 /* security_codesigning.d */,
- );
- name = DTrace;
- sourceTree = "<group>";
- };
C2A4A43E0B7BABFD004AAC3F /* Pieces */ = {
isa = PBXGroup;
children = (
children = (
C2D383180A237F47005C63A2 /* CodeSigning.h */,
C2D3831C0A237F47005C63A2 /* CSCommon.h */,
- C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */,
C2D3831E0A237F47005C63A2 /* SecCode.h */,
- C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */,
C2D3831D0A237F47005C63A2 /* SecCode.cpp */,
C2D383220A237F47005C63A2 /* SecStaticCode.h */,
- C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */,
C2D383210A237F47005C63A2 /* SecStaticCode.cpp */,
C2D383260A237F47005C63A2 /* SecRequirement.h */,
- C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */,
C2D383250A237F47005C63A2 /* SecRequirement.cpp */,
C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */,
C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */,
C2D3832F0A237F47005C63A2 /* kerneldiskrep.cpp */,
C2C3BC5E0BA1D6FE00E869D1 /* cfmdiskrep.h */,
C2C3BC5D0BA1D6FE00E869D1 /* cfmdiskrep.cpp */,
+ C25942430BA7095000877E56 /* foreigndiskrep.h */,
+ C25942420BA7095000877E56 /* foreigndiskrep.cpp */,
C2BD519B0A9392FD000FE43D /* machorep.h */,
C2BD519A0A9392FD000FE43D /* machorep.cpp */,
- C2A436140F2133B2007A41A6 /* slcrep.h */,
- C2A436130F2133B2007A41A6 /* slcrep.cpp */,
C2C3BCD20BA1E47E00E869D1 /* singlediskrep.h */,
C2C3BCD10BA1E47E00E869D1 /* singlediskrep.cpp */,
- C28342EC0E36719D00E54360 /* detachedrep.h */,
- C28342EB0E36719D00E54360 /* detachedrep.cpp */,
);
name = "Disk Representations";
sourceTree = "<group>";
C2CCF0360A3F524B0085795A /* Local Utilities */ = {
isa = PBXGroup;
children = (
- C28342E50E366E6800E54360 /* csdatabase.h */,
- C28342E40E366E6800E54360 /* csdatabase.cpp */,
C2F6566D0BCBFB250078779E /* cserror.h */,
C2F6566C0BCBFB250078779E /* cserror.cpp */,
C2E911E10ADEBE3200275CB2 /* resources.h */,
C2E911E00ADEBE3200275CB2 /* resources.cpp */,
C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */,
C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */,
+ C2CCF0300A3F523D0085795A /* macho++.h */,
+ C2CCF02F0A3F523D0085795A /* macho++.cpp */,
+ C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */,
+ C2D8A07D0AE7F6E300F68F79 /* cfmunge.cpp */,
C2EF100F0A49BD89005A44BB /* renum.h */,
C2EF100E0A49BD89005A44BB /* renum.cpp */,
C2A976A90B8A2E36008B4EA0 /* csutilities.h */,
C2D383F90A23A9D9005C63A2 /* cstemp */ = {
isa = PBXGroup;
children = (
- C2C4F4EE0E0980C700137848 /* codesigning_dtrace.h */,
C2D383EF0A23A9D3005C63A2 /* RequirementLexer.hpp */,
C2D383EE0A23A9D3005C63A2 /* RequirementLexer.cpp */,
C2D383F10A23A9D3005C63A2 /* RequirementParser.hpp */,
C2D383F00A23A9D3005C63A2 /* RequirementParser.cpp */,
- C2B9F1D20D51646600CAB713 /* RequirementKeywords.h */,
C2D383F20A23A9D3005C63A2 /* RequirementParserTokenTypes.hpp */,
C2D383F30A23A9D3005C63A2 /* RequirementParserTokenTypes.txt */,
C26B45C00B8A9C00003C0ACA /* ucspc */,
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- C2E8AF2A0DE25D11000F6D3B /* SecCodePriv.h in Headers */,
- C2E8AF2B0DE25D11000F6D3B /* SecStaticCodePriv.h in Headers */,
- C2E8AF2C0DE25D11000F6D3B /* SecRequirementPriv.h in Headers */,
- C2D213870D9844F700E76E7D /* resources.h in Headers */,
- C2C315D70D9319E800E7AA0C /* csutilities.h in Headers */,
+ C2A36B4B0D906C08003412BA /* resources.h in Headers */,
C2F656930BCBFFF40078779E /* cserror.h in Headers */,
C2A487540B79150C00849490 /* SecIntegrity.h in Headers */,
C2A487530B7914F400849490 /* SecCodeHostLib.h in Headers */,
C297DF250B014BB300E94EE0 /* SecCodeSigner.h in Headers */,
+ C2D8A0980AE7F74500F68F79 /* cfmunge.h in Headers */,
C2D3836F0A237F47005C63A2 /* cs.h in Headers */,
C2D383820A237F47005C63A2 /* Code.h in Headers */,
C2D383860A237F47005C63A2 /* StaticCode.h in Headers */,
C2D3836C0A237F47005C63A2 /* CodeSigning.h in Headers */,
C2D3836D0A237F47005C63A2 /* SecCodeHost.h in Headers */,
C2D383700A237F47005C63A2 /* CSCommon.h in Headers */,
- C2D50CE20E155AE60059A195 /* CSCommonPriv.h in Headers */,
C2D383720A237F47005C63A2 /* SecCode.h in Headers */,
C2D383740A237F47005C63A2 /* cskernel.h in Headers */,
C2D383760A237F47005C63A2 /* SecStaticCode.h in Headers */,
C2093AC80BB0967D00EB8599 /* reqreader.h in Headers */,
C2C1DFBE0A2F80EB00D1B02B /* reqinterp.h in Headers */,
C2C1DFC60A2F820500D1B02B /* reqmaker.h in Headers */,
+ C2CCF0340A3F523D0085795A /* macho++.h in Headers */,
C2EF10130A49BD89005A44BB /* renum.h in Headers */,
C2BD519F0A9392FD000FE43D /* machorep.h in Headers */,
C2CC31050B8523AD005FA59D /* SecIntegrityLib.h in Headers */,
- C28342E60E366E6800E54360 /* csdatabase.h in Headers */,
- C28342ED0E36719D00E54360 /* detachedrep.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- C26FF62F0E5B376B00F640A0 /* CodeSigning.h in Headers */,
- C26FF6300E5B376B00F640A0 /* CSCommon.h in Headers */,
- C26FF6310E5B376B00F640A0 /* CSCommonPriv.h in Headers */,
- C26FF6320E5B376B00F640A0 /* SecCode.h in Headers */,
- C26FF6330E5B376B00F640A0 /* SecCodePriv.h in Headers */,
- C26FF6340E5B376B00F640A0 /* SecStaticCode.h in Headers */,
- C26FF6350E5B376B00F640A0 /* SecStaticCodePriv.h in Headers */,
- C26FF6360E5B376B00F640A0 /* SecRequirement.h in Headers */,
- C26FF6370E5B376B00F640A0 /* SecRequirementPriv.h in Headers */,
- C26FF6380E5B376B00F640A0 /* SecCodeSigner.h in Headers */,
- C26FF6390E5B376B00F640A0 /* SecCodeHost.h in Headers */,
- C26FF63A0E5B376B00F640A0 /* SecIntegrity.h in Headers */,
- C26FF62D0E5B375A00F640A0 /* SecIntegrityLib.h in Headers */,
- C26FF62E0E5B375A00F640A0 /* SecCodeHostLib.h in Headers */,
- C2A436160F2133B2007A41A6 /* slcrep.h in Headers */,
+ C2CC31060B8523F8005FA59D /* SecIntegrityLib.h in Headers */,
+ C2A487550B79152A00849490 /* SecIntegrity.h in Headers */,
+ C2A487560B79152A00849490 /* SecCodeHostLib.h in Headers */,
+ C2D3839A0A238132005C63A2 /* CodeSigning.h in Headers */,
+ C2D383460A237F47005C63A2 /* CSCommon.h in Headers */,
+ C2D383480A237F47005C63A2 /* SecCode.h in Headers */,
+ C2D3834C0A237F47005C63A2 /* SecStaticCode.h in Headers */,
+ C2D383500A237F47005C63A2 /* SecRequirement.h in Headers */,
+ C2C931B50AB8BA8200F83950 /* SecCodeHost.h in Headers */,
+ C2C1DFC40A2F820500D1B02B /* reqmaker.h in Headers */,
+ C2093AA90BB0948000EB8599 /* reqreader.h in Headers */,
+ C2C1DFBC0A2F80EB00D1B02B /* reqinterp.h in Headers */,
+ C2EF10110A49BD89005A44BB /* renum.h in Headers */,
+ C21EA3DE0AD2F81300E6E31C /* SecCodeSigner.h in Headers */,
+ C236E3D80AD59446000F5140 /* signer.h in Headers */,
+ C236E3DC0AD595C2000F5140 /* signerutils.h in Headers */,
+ C259DFD70AD6D9BA00C9ACC6 /* sigblob.h in Headers */,
+ C2E911E30ADEBE3200275CB2 /* resources.h in Headers */,
+ C2D8A0800AE7F6E300F68F79 /* cfmunge.h in Headers */,
+ C2A976AB0B8A2E36008B4EA0 /* csutilities.h in Headers */,
+ C2C3BC600BA1D6FE00E869D1 /* cfmdiskrep.h in Headers */,
+ C2C3BCD40BA1E47E00E869D1 /* singlediskrep.h in Headers */,
+ C25942450BA7095000877E56 /* foreigndiskrep.h in Headers */,
+ C2F6566F0BCBFB250078779E /* cserror.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
};
/* End PBXHeadersBuildPhase section */
-/* Begin PBXNativeTarget section */
- 4C56351D0540A55300DCF0C8 /* security_codesigning */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = C263E67109A2971B000043F1 /* Build configuration list for PBXNativeTarget "security_codesigning" */;
- buildPhases = (
- 4C5635180540A55300DCF0C8 /* Headers */,
- 4CCB00500580097400981D43 /* CopyFiles */,
- 4CCB00510580097600981D43 /* CopyFiles */,
- 4CCB00520580097800981D43 /* CopyFiles */,
- C26C39D3068368EC00ED5782 /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- C26AC70F0DAEB400005BFB40 /* PBXTargetDependency */,
- );
- name = security_codesigning;
- productInstallPath = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- productName = security_codesigning;
- productReference = 4C56351E0540A55300DCF0C8 /* security_codesigning.framework */;
- productType = "com.apple.product-type.framework";
- };
+/* Begin PBXLibraryTarget section */
4CA1FEBD052A3C8100F22E42 /* libsecurity_codesigning */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = C263E67509A2971B000043F1 /* Build configuration list for PBXNativeTarget "libsecurity_codesigning" */;
+ isa = PBXLibraryTarget;
+ buildConfigurationList = C263E67509A2971B000043F1 /* Build configuration list for PBXLibraryTarget "libsecurity_codesigning" */;
buildPhases = (
4CA1FEB9052A3C8100F22E42 /* Headers */,
4CA1FEBA052A3C8100F22E42 /* Sources */,
4C789C16055AF56700B6FC95 /* ShellScript */,
4CD0D468055B0D40001715CB /* ShellScript */,
);
- buildRules = (
- );
dependencies = (
4C7502910540C69C00056564 /* PBXTargetDependency */,
C21E3F8B0A23AE10006558D6 /* PBXTargetDependency */,
name = libsecurity_codesigning;
productName = libsecurity_codesigning;
productReference = 4CA1FEBE052A3C8100F22E42 /* security_codesigning */;
- productType = "com.apple.product-type.library.static";
};
+/* End PBXLibraryTarget section */
+
+/* Begin PBXNativeTarget section */
C2BC1F250B580D3A003EC9DC /* libintegrity */ = {
isa = PBXNativeTarget;
buildConfigurationList = C2BC1F270B580D3F003EC9DC /* Build configuration list for PBXNativeTarget "libintegrity" */;
C2D383B80A23A8C4005C63A2 /* Requirements Language */,
C2BC1F250B580D3A003EC9DC /* libintegrity */,
C2BC1F2E0B580D4B003EC9DC /* libcodehost */,
- C26AC7090DAEB3A7005BFB40 /* DTrace */,
);
};
/* End PBXProject section */
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "for variant in ${BUILD_VARIANTS}\ndo\n\tpostfix=`echo _${variant} | sed 's/_normal//'`\n\tditto -V \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}${postfix}\" \"${SYMROOT}/${PRODUCT_NAME}${postfix}\"\n\tln -fs \"../../../${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework/Versions/A\n\tln -fs \"Versions/Current/${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework\ndone";
+ shellScript = "for variant in ${BUILD_VARIANTS}\ndo\n\tpostfix=`echo _${variant} | sed 's/_normal//'`\n\tln -fs \"../../../${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework/Versions/A\n\tln -fs \"Versions/Current/${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework\ndone";
};
4CD0D468055B0D40001715CB /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
shellPath = /bin/sh;
shellScript = "for variant in ${BUILD_VARIANTS}\ndo\n\tpostfix=`echo _${variant} | sed 's/_normal//'`\n\tcp -p \"${SYMROOT}/${PRODUCT_NAME}${postfix}\" \"${DSTROOT}/usr/local/SecurityPieces/Components/Security/${PRODUCT_NAME}.framework/Versions/A\"\n\tranlib \"${DSTROOT}/usr/local/SecurityPieces/Components/Security/${PRODUCT_NAME}.framework/Versions/A/${PRODUCT_NAME}${postfix}\"\n\tln -fs \"Versions/Current/${PRODUCT_NAME}${postfix}\" \"${DSTROOT}/usr/local/SecurityPieces/Components/Security/${PRODUCT_NAME}.framework\"\ndone";
};
- C26AC7080DAEB3A7005BFB40 /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/lib/security_codesigning.d",
- );
- outputPaths = (
- "$(TEMPDIR)/codesigning_dtrace.h",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "mkdir -p $TEMPDIR\n/usr/sbin/dtrace -h -C -s $SRCROOT/lib/security_codesigning.d -o $TEMPDIR/codesigning_dtrace.h\n";
- showEnvVarsInLog = 0;
- };
C26B45C30B8A9C1A003C0ACA /* Prepare ucspc */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
"$(TEMPDIR)/RequirementLexer.hpp",
"$(TEMPDIR)/RequirementLexer.cpp",
"$(TEMPDIR)/RequirementParser.hpp",
- "$(TEMPDIR)/RequirementKeywords.h",
"$(TEMPDIR)/RequirementParser.cpp",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
- shellScript = "antlr=/usr/local/bin/antlr.jar\nDEBUG=\"\"\nmkdir -p $TEMPDIR\nrm -f $TEMPDIR/Requirement{Parser,Lexer}*\njava -cp \"$antlr\" antlr.Tool -o $TEMPDIR $DEBUG requirements.grammar\nsed -n 's/^.*=\\(\".*\"\\)=.*$/ \\1,/p' $TEMPDIR/RequirementParserTokenTypes.txt >$TEMPDIR/RequirementKeywords.h\n";
+ shellScript = "antlr=/usr/local/bin/antlr.jar\nDEBUG=\"\"\nmkdir -p $TEMPDIR\nrm -f $TEMPDIR/Requirement{Parser,Lexer}*\njava -cp \"$antlr\" antlr.Tool -o $TEMPDIR $DEBUG requirements.grammar\n";
};
/* End PBXShellScriptBuildPhase section */
C2D3835D0A237F47005C63A2 /* reqparser.cpp in Sources */,
C2C1DF140A2E3D7200D1B02B /* requirement.cpp in Sources */,
C2D383610A237F47005C63A2 /* Requirements.cpp in Sources */,
+ C2D383630A237F47005C63A2 /* security_codesigning.exp in Sources */,
C21CFC5F0A250D1C006CD5B1 /* reqdumper.cpp in Sources */,
C2C1DFBB0A2F80EB00D1B02B /* reqinterp.cpp in Sources */,
C2C1DFC30A2F820500D1B02B /* reqmaker.cpp in Sources */,
C224635F0B8620F800626F1B /* RequirementParser.cpp in Sources */,
C22463600B8620F800626F1B /* RequirementLexer.cpp in Sources */,
C22463610B86210100626F1B /* antlrplugin.cpp in Sources */,
+ C2CCF0310A3F523D0085795A /* macho++.cpp in Sources */,
C2EF10100A49BD89005A44BB /* renum.cpp in Sources */,
C2BD519C0A9392FD000FE43D /* machorep.cpp in Sources */,
C2C931B40AB8BA1200F83950 /* SecCodeHost.cpp in Sources */,
C236E3DB0AD595C2000F5140 /* signerutils.cpp in Sources */,
C259DFD60AD6D9BA00C9ACC6 /* sigblob.cpp in Sources */,
C2E911E20ADEBE3200275CB2 /* resources.cpp in Sources */,
+ C2D8A07F0AE7F6E300F68F79 /* cfmunge.cpp in Sources */,
C2A976AA0B8A2E36008B4EA0 /* csutilities.cpp in Sources */,
C2C3BC5F0BA1D6FE00E869D1 /* cfmdiskrep.cpp in Sources */,
C2C3BCD30BA1E47E00E869D1 /* singlediskrep.cpp in Sources */,
+ C25942440BA7095000877E56 /* foreigndiskrep.cpp in Sources */,
C2093AA80BB0948000EB8599 /* reqreader.cpp in Sources */,
C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */,
- C28342E70E366E6800E54360 /* csdatabase.cpp in Sources */,
- C28342EE0E36719D00E54360 /* detachedrep.cpp in Sources */,
- C2A436150F2133B2007A41A6 /* slcrep.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
target = C2BC1F250B580D3A003EC9DC /* libintegrity */;
targetProxy = C250F6C40B5EF4E40076098F /* PBXContainerItemProxy */;
};
- C26AC70F0DAEB400005BFB40 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = C26AC7090DAEB3A7005BFB40 /* DTrace */;
- targetProxy = C26AC70E0DAEB400005BFB40 /* PBXContainerItemProxy */;
- };
C2E287410B5D8F97009336A0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4CA1FEBD052A3C8100F22E42 /* libsecurity_codesigning */;
isa = XCBuildConfiguration;
buildSettings = {
BUILD_VARIANTS = debug;
- EXECUTABLE_PREFIX = "";
- EXECUTABLE_SUFFIX = "";
FRAMEWORK_VERSION = A;
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- INFOPLIST_FILE = "Info-security_codesigning.plist";
INSTALL_PATH = /usr/local/SecurityPieces/Components/Security;
PRODUCT_NAME = security_codesigning;
WRAPPER_EXTENSION = framework;
C263E67309A2971B000043F1 /* Deployment */ = {
isa = XCBuildConfiguration;
buildSettings = {
- EXECUTABLE_PREFIX = "";
- EXECUTABLE_SUFFIX = "";
FRAMEWORK_VERSION = A;
- INFOPLIST_FILE = "Info-security_codesigning.plist";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
INSTALL_PATH = /usr/local/SecurityPieces/Components/Security;
PRODUCT_NAME = security_codesigning;
WRAPPER_EXTENSION = framework;
C263E67409A2971B000043F1 /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
- EXECUTABLE_PREFIX = "";
- EXECUTABLE_SUFFIX = "";
FRAMEWORK_VERSION = A;
- INFOPLIST_FILE = "Info-security_codesigning.plist";
INSTALL_PATH = /usr/local/SecurityPieces/Components/Security;
PRODUCT_NAME = security_codesigning;
WRAPPER_EXTENSION = framework;
isa = XCBuildConfiguration;
buildSettings = {
BUILD_VARIANTS = debug;
- CURRENT_PROJECT_VERSION = 36885;
- EXECUTABLE_PREFIX = "";
- EXECUTABLE_SUFFIX = "";
+ CURRENT_PROJECT_VERSION = 36924;
FRAMEWORK_SEARCH_PATHS = (
/usr/local/SecurityPieces/Frameworks,
/usr/local/SecurityPieces/Components/Security,
);
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
HEADER_SEARCH_PATHS = (
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/Headers",
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
- "$(TEMPDIR)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
);
LIBRARY_STYLE = "\U0001STATIC";
OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
- OTHER_LDFLAGS_debug = "";
+ OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
- PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
+ PRIVATE_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/PrivateHeaders/Security";
PRODUCT_NAME = security_codesigning;
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
+ PUBLIC_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/Headers/Security";
VERSIONING_SYSTEM = "apple-generic";
WARNING_CFLAGS = (
"-Wmost",
normal,
debug,
);
- CURRENT_PROJECT_VERSION = 36885;
- EXECUTABLE_PREFIX = "";
- EXECUTABLE_SUFFIX = "";
+ CURRENT_PROJECT_VERSION = 36924;
FRAMEWORK_SEARCH_PATHS = (
/usr/local/SecurityPieces/Frameworks,
/usr/local/SecurityPieces/Components/Security,
);
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
HEADER_SEARCH_PATHS = (
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/Headers",
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
- "$(TEMPDIR)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
);
LIBRARY_STYLE = STATIC;
OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
- OTHER_LDFLAGS_debug = "";
+ OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
- PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
+ PRIVATE_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/PrivateHeaders/Security";
PRODUCT_NAME = security_codesigning;
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
+ PUBLIC_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/Headers/Security";
VERSIONING_SYSTEM = "apple-generic";
WARNING_CFLAGS = (
"-Wmost",
normal,
debug,
);
- CURRENT_PROJECT_VERSION = 36885;
- EXECUTABLE_PREFIX = "";
- EXECUTABLE_SUFFIX = "";
+ CURRENT_PROJECT_VERSION = 36924;
FRAMEWORK_SEARCH_PATHS = (
/usr/local/SecurityPieces/Frameworks,
/usr/local/SecurityPieces/Components/Security,
HEADER_SEARCH_PATHS = (
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/Headers",
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
- "$(TEMPDIR)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
);
LIBRARY_STYLE = STATIC;
OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
- OTHER_LDFLAGS_debug = "";
+ OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
- PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
+ PRIVATE_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/PrivateHeaders/Security";
PRODUCT_NAME = security_codesigning;
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
+ PUBLIC_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/Headers/Security";
VERSIONING_SYSTEM = "apple-generic";
WARNING_CFLAGS = (
"-Wmost",
};
name = Default;
};
- C26AC70A0DAEB3A8005BFB40 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = DTrace;
- };
- name = Development;
- };
- C26AC70B0DAEB3A8005BFB40 /* Deployment */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- PRODUCT_NAME = DTrace;
- ZERO_LINK = NO;
- };
- name = Deployment;
- };
- C26AC70C0DAEB3A8005BFB40 /* Default */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = DTrace;
- };
- name = Default;
- };
C2BC1F280B580D3F003EC9DC /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = /usr/local/lib;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/lib;
PREBINDING = NO;
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/lib;
PREBINDING = NO;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = /usr/local/lib;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/lib;
LIBRARY_SEARCH_PATHS = (
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/lib;
LIBRARY_SEARCH_PATHS = (
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
PRODUCT_NAME = "Requirements Language";
ZERO_LINK = NO;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
PRODUCT_NAME = Everything;
ZERO_LINK = NO;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- C263E67109A2971B000043F1 /* Build configuration list for PBXNativeTarget "security_codesigning" */ = {
+ C263E67109A2971B000043F1 /* Build configuration list for PBXFrameworkTarget "security_codesigning" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C263E67209A2971B000043F1 /* Development */,
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
- C263E67509A2971B000043F1 /* Build configuration list for PBXNativeTarget "libsecurity_codesigning" */ = {
+ C263E67509A2971B000043F1 /* Build configuration list for PBXLibraryTarget "libsecurity_codesigning" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C263E67609A2971B000043F1 /* Development */,
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
- C26AC70D0DAEB3C6005BFB40 /* Build configuration list for PBXAggregateTarget "DTrace" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- C26AC70A0DAEB3A8005BFB40 /* Development */,
- C26AC70B0DAEB3A8005BFB40 /* Deployment */,
- C26AC70C0DAEB3A8005BFB40 /* Default */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Default;
- };
C2BC1F270B580D3F003EC9DC /* Build configuration list for PBXNativeTarget "libintegrity" */ = {
isa = XCConfigurationList;
buildConfigurations = (
+++ /dev/null
-#
-# Suggested internal host requirement for (only) ppc Mach-O code
-#
-anchor apple and identifier com.apple.translate // Rosetta
--- /dev/null
+#
+# Suggested internal requirements for ppc (only) Mach-O code
+#
+host => anchor apple and identifier com.apple.translate // Rosetta
--- /dev/null
+anchor apple and (identifier com.apple.translate or identifier com.apple.LaunchCFMApp)
/*
- * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
memcpy(hash, hexString(s).data(), SHA1::digestLength);
}
- static const char *matchPrefix(const string &key, const char *prefix)
+ void RequirementParser::certMatchOperation(Maker &maker, int slot, string key)
{
- unsigned pLength = strlen(prefix);
- if (!key.compare(0, pLength, prefix, 0, pLength))
- return key.c_str() + pLength;
- else
- return NULL;
- }
-
- void RequirementParser::certMatchOperation(Maker &maker, int32_t slot, string key)
- {
- if (matchPrefix(key, "subject.")) {
+ if (!key.compare(0, 8, "subject.", 0, 8)) {
maker.put(opCertField);
maker.put(slot);
maker.put(key);
- } else if (const char *oids = matchPrefix(key, "field.")) {
- maker.put(opCertGeneric);
- maker.put(slot);
- CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
- maker.putData(oid.data(), oid.length());
- } else if (const char *oids = matchPrefix(key, "extension.")) {
+ } else if (!key.compare(0, 6, "field.", 0, 6)) {
maker.put(opCertGeneric);
maker.put(slot);
- CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
+ CssmAutoData oid(Allocator::standard()); oid.fromOid(key.c_str() + 6);
maker.putData(oid.data(), oid.length());
} else {
throw antlr::SemanticException(key + ": unrecognized certificate field");
private:
static string hexString(const string &s);
static void hashString(const string &s, SHA1::Digest hash);
- void certMatchOperation(Maker &maker, int32_t slot, string key);
+ void certMatchOperation(Maker &maker, int slot, string key);
}
//
expr[Maker &maker]
{ Maker::Label label(maker); }
- : term[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } term[maker] )*
+ : term[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } term[maker] )*
;
term[Maker &maker]
{ Maker::Label label(maker); }
- : primary[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } primary[maker] )*
+ : primary[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } primary[maker] )*
;
primary[Maker &maker]
{ maker.put(opAppleGenericAnchor); }
| ( "certificate" | "cert" | "anchor" ) "trusted"
{ maker.trustedAnchor(); }
- | ( "certificate" | "cert" ) { int32_t slot; } slot=certSlot
+ | ( "certificate" | "cert" ) { int slot; } slot=certSlot
( certslotspec[maker, slot] | "trusted" { maker.trustedAnchor(slot); } )
| "anchor" certslotspec[maker, Requirement::anchorCert]
;
{ maker.put(opAppleGenericAnchor); }
;
-certslotspec[Maker &maker, int32_t slot] { string key; }
+certslotspec[Maker &maker, int slot] { string key; }
: eql { SHA1::Digest digest; } certificateDigest[digest]
{ maker.anchor(slot, digest); }
| key=bracketKey
;
//
-// A certSlot identifies one certificate from the certificate chain
+// A certSlot identifiers one certificate from the certificate chain
//
-certSlot returns [int32_t slot = 0]
+certSlot returns [int slot]
: s:INTEGER // counting from the anchor up
{ slot = atol(s->getText().c_str()); }
| NEG ss:INTEGER // counting from the leaf down