--- /dev/null
+/*
+ * 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 <security_utilities/unix++.h>
+#include <security_utilities/unixchild.h>
+#include <Security/SecCertificate.h>
+#include <vector>
+
+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<CFBooleanRef>(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<CFTypeRef>(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<CFNumberRef>(kSecCodeSignerFlags)) {
+ state.mCdFlagsGiven = true;
+ state.mCdFlags = cfNumber<uint32_t>(flags);
+ } else
+ state.mCdFlagsGiven = false;
+
+ // digest algorithms are specified as a numeric code
+ if (CFNumberRef digestAlgorithm = get<CFNumberRef>(kSecCodeSignerDigestAlgorithm))
+ state.mDigestAlgorithm = cfNumber<unsigned int>(digestAlgorithm);
+
+ if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
+ state.mCMSSize = cfNumber<size_t>(cmsSize);
+ else
+ state.mCMSSize = 9000; // likely big enough
+
+ // signing time can be a CFDateRef or null
+ if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime)) {
+ if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull)
+ state.mSigningTime = CFDateRef(time);
+ else
+ MacOSError::throwMe(errSecCSInvalidObjectRef);
+ }
+
+ if (CFStringRef ident = get<CFStringRef>(kSecCodeSignerIdentifier))
+ state.mIdentifier = cfString(ident);
+
+ if (CFStringRef prefix = get<CFStringRef>(kSecCodeSignerIdentifierPrefix))
+ state.mIdentifierPrefix = cfString(prefix);
+
+ // requirements can be binary or string (to be compiled)
+ if (CFTypeRef reqs = get<CFTypeRef>(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<CFNumberRef>(kSecCodeSignerPageSize);
+
+ // 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())
+ MacOSError::throwMe(errSecCSInvalidObjectRef);
+ }
+
+ state.mDryRun = getBool(kSecCodeSignerDryRun);
+
+ state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules);
+
+ state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
+ state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
+
+ state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
+
+ if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) {
+ state.mWantTimeStamp = timestampRequest == kCFBooleanTrue;
+ } else { // pick default
+ state.mWantTimeStamp = false;
+ if (state.mSigner && state.mSigner != SecIdentityRef(kCFNull)) {
+ CFRef<SecCertificateRef> signerCert;
+ MacOSError::check(SecIdentityCopyCertificate(state.mSigner, &signerCert.aref()));
+ if (certificateHasField(signerCert, devIdLeafMarkerOID))
+ state.mWantTimeStamp = true;
+ }
+ }
+ state.mTimestampAuthentication = get<SecIdentityRef>(kSecCodeSignerTimestampAuthentication);
+ state.mTimestampService = get<CFURLRef>(kSecCodeSignerTimestampServer);
+ state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates);
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security