X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_codesigning/lib/CodeSigner.cpp diff --git a/libsecurity_codesigning/lib/CodeSigner.cpp b/libsecurity_codesigning/lib/CodeSigner.cpp new file mode 100644 index 00000000..e40620b9 --- /dev/null +++ b/libsecurity_codesigning/lib/CodeSigner.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2006-2010 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@ + */ + +// +// CodeSigner - SecCodeSigner API objects +// +#include "CodeSigner.h" +#include "signer.h" +#include "reqparser.h" +#include "renum.h" +#include "csdatabase.h" +#include "drmaker.h" +#include "csutilities.h" +#include +#include +#include +#include + +namespace Security { + +__SEC_CFTYPE(SecIdentity) + +namespace CodeSigning { + +using namespace UnixPlusPlus; + + +// +// A helper for parsing out a CFDictionary signing-data specification +// +class SecCodeSigner::Parser : CFDictionary { +public: + Parser(SecCodeSigner &signer, CFDictionaryRef parameters); + + bool getBool(CFStringRef key) const + { + if (CFBooleanRef flag = get(key)) + return flag == kCFBooleanTrue; + else + return false; + } +}; + + +// +// Construct a SecCodeSigner +// +SecCodeSigner::SecCodeSigner(SecCSFlags flags) + : mOpFlags(flags), mRequirements(NULL), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm) +{ +} + + +// +// Clean up a SecCodeSigner +// +SecCodeSigner::~SecCodeSigner() throw() +try { + ::free((Requirements *)mRequirements); +} catch (...) { + return; +} + + +// +// Parse an input parameter dictionary and set ready-to-use parameters +// +void SecCodeSigner::parameters(CFDictionaryRef 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); + } + 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) +{ + assert(mDetached); + if (CFGetTypeID(mDetached) == CFURLGetTypeID()) { + // URL to destination file + AutoFileDesc fd(cfString(CFURLRef(mDetached.get())), O_WRONLY | O_CREAT | O_TRUNC); + fd.writeAll(*blob); + } else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) { + CFDataAppendBytes(CFMutableDataRef(mDetached.get()), + (const UInt8 *)blob, blob->length()); + } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) { + signatureDatabaseWriter().storeCode(blob, signer.path().c_str()); + } else + assert(false); +} + + +// +// Our DiskRep::signingContext methods communicate with the signing subsystem +// in terms those callers can easily understand. +// +string SecCodeSigner::sdkPath(const std::string &path) const +{ + assert(path[0] == '/'); // need absolute path here + if (mSDKRoot) + return cfString(mSDKRoot) + path; + else + return path; +} + +bool SecCodeSigner::isAdhoc() const +{ + return mSigner == SecIdentityRef(kCFNull); +} + + +// +// The actual parsing operation is done in the Parser class. +// +// Note that we need to copy or retain all incoming data. The caller has no requirement +// to keep the parameters dictionary around. +// +SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters) + : CFDictionary(parameters, errSecCSBadDictionaryFormat) +{ + // the signer may be an identity or null + state.mSigner = SecIdentityRef(get(kSecCodeSignerIdentity)); + if (state.mSigner) + if (CFGetTypeID(state.mSigner) != SecIdentityGetTypeID() && !CFEqual(state.mSigner, kCFNull)) + MacOSError::throwMe(errSecCSInvalidObjectRef); + + // the flags need some augmentation + if (CFNumberRef flags = get(kSecCodeSignerFlags)) { + state.mCdFlagsGiven = true; + state.mCdFlags = cfNumber(flags); + } else + state.mCdFlagsGiven = false; + + // digest algorithms are specified as a numeric code + if (CFNumberRef digestAlgorithm = get(kSecCodeSignerDigestAlgorithm)) + state.mDigestAlgorithm = cfNumber(digestAlgorithm); + + if (CFNumberRef cmsSize = get(CFSTR("cmssize"))) + state.mCMSSize = cfNumber(cmsSize); + else + state.mCMSSize = 9000; // likely big enough + + // signing time can be a CFDateRef or null + if (CFTypeRef time = get(kSecCodeSignerSigningTime)) { + if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull) + state.mSigningTime = CFDateRef(time); + else + MacOSError::throwMe(errSecCSInvalidObjectRef); + } + + if (CFStringRef ident = get(kSecCodeSignerIdentifier)) + state.mIdentifier = cfString(ident); + + if (CFStringRef prefix = get(kSecCodeSignerIdentifierPrefix)) + state.mIdentifierPrefix = cfString(prefix); + + // requirements can be binary or string (to be compiled) + if (CFTypeRef reqs = get(kSecCodeSignerRequirements)) { + if (CFGetTypeID(reqs) == CFDataGetTypeID()) { // binary form + const Requirements *rp = (const Requirements *)CFDataGetBytePtr(CFDataRef(reqs)); + state.mRequirements = rp->clone(); + } else if (CFGetTypeID(reqs) == CFStringGetTypeID()) { // text form + state.mRequirements = parseRequirements(cfString(CFStringRef(reqs))); + } else + MacOSError::throwMe(errSecCSInvalidObjectRef); + } else + state.mRequirements = NULL; + + state.mNoMachO = getBool(CFSTR("no-macho")); + + state.mPageSize = get(kSecCodeSignerPageSize); + + // detached can be (destination) file URL or (mutable) Data to be appended-to + if ((state.mDetached = get(kSecCodeSignerDetached))) { + CFTypeID type = CFGetTypeID(state.mDetached); + if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID()) + MacOSError::throwMe(errSecCSInvalidObjectRef); + } + + state.mDryRun = getBool(kSecCodeSignerDryRun); + + state.mResourceRules = get(kSecCodeSignerResourceRules); + + state.mApplicationData = get(kSecCodeSignerApplicationData); + state.mEntitlementData = get(kSecCodeSignerEntitlements); + + state.mSDKRoot = get(kSecCodeSignerSDKRoot); + + if (CFBooleanRef timestampRequest = get(kSecCodeSignerRequireTimestamp)) { + state.mWantTimeStamp = timestampRequest == kCFBooleanTrue; + } else { // pick default + state.mWantTimeStamp = false; + if (state.mSigner && state.mSigner != SecIdentityRef(kCFNull)) { + CFRef signerCert; + MacOSError::check(SecIdentityCopyCertificate(state.mSigner, &signerCert.aref())); + if (certificateHasField(signerCert, devIdLeafMarkerOID)) + state.mWantTimeStamp = true; + } + } + state.mTimestampAuthentication = get(kSecCodeSignerTimestampAuthentication); + state.mTimestampService = get(kSecCodeSignerTimestampServer); + state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates); +} + + +} // end namespace CodeSigning +} // end namespace Security