/ OSX / libsecurity_codesigning / lib / CodeSigner.cpp
CodeSigner.cpp
  1  /*
  2   * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
  3   * 
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  //
 25  // CodeSigner - SecCodeSigner API objects
 26  //
 27  #include "CodeSigner.h"
 28  #include "signer.h"
 29  #include "csdatabase.h"
 30  #include "drmaker.h"
 31  #include "csutilities.h"
 32  #include <security_utilities/unix++.h>
 33  #include <security_utilities/unixchild.h>
 34  #include <Security/SecCertificate.h>
 35  #include <Security/SecCertificatePriv.h>
 36  #include <vector>
 37  #include <errno.h>
 38  
 39  namespace Security {
 40  
 41  __SEC_CFTYPE(SecIdentity)
 42  
 43  namespace CodeSigning {
 44  
 45  using namespace UnixPlusPlus;
 46  
 47  
 48  //
 49  // A helper for parsing out a CFDictionary signing-data specification
 50  //
 51  class SecCodeSigner::Parser : CFDictionary {
 52  public:
 53  	Parser(SecCodeSigner &signer, CFDictionaryRef parameters);
 54  	
 55  	bool getBool(CFStringRef key) const
 56  	{
 57  		if (CFBooleanRef flag = get<CFBooleanRef>(key))
 58  			return flag == kCFBooleanTrue;
 59  		else
 60  			return false;
 61  	}
 62  
 63  	uint32_t parseRuntimeVersion(std::string& runtime)
 64  	{
 65  		uint32_t version = 0;
 66  		char* cursor = const_cast<char*>(runtime.c_str());
 67  		char* end = cursor + runtime.length();
 68  		char* nxt = NULL;
 69  		long component = 0;
 70  		int component_shift = 16;
 71  
 72  		// x should convert to 0x00XX0000
 73  		// x.y should convert to 0x00XXYY00
 74  		// x.y.z should covert to 0x00XXYYZZ
 75  		// 0, 0.0, and 0.0.0 are rejected
 76  		// anything else should be rejected
 77  		while (cursor < end) {
 78  			nxt = NULL;
 79  			errno = 0;
 80  			component = strtol(cursor, &nxt, 10);
 81  			if (cursor == nxt ||
 82  				(errno != 0) ||
 83  				(component < 0 || component > UINT8_MAX)) {
 84  				secdebug("signer", "Runtime version: %s is invalid", runtime.c_str());
 85  				MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
 86  			}
 87  			version |= (component & 0xff) << component_shift;
 88  			component_shift -= 8;
 89  
 90  			if (*nxt == '\0') {
 91  				break;
 92  			}
 93  
 94  			if (*nxt != '.' || component_shift < 0 || (nxt + 1) == end) {
 95  				// Catch a trailing "."
 96  				secdebug("signer", "Runtime version: %s is invalid", runtime.c_str());
 97  				MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
 98  			}
 99  			cursor = nxt + 1;
100  		}
101  
102  		if (version == 0) {
103  			secdebug("signer","Runtime version: %s is a version of zero", runtime.c_str());
104  			MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
105  		}
106  
107  		return version;
108  	}
109  };
110  
111  
112  //
113  // Construct a SecCodeSigner
114  //
115  SecCodeSigner::SecCodeSigner(SecCSFlags flags)
116  	: mOpFlags(flags), mLimitedAsync(NULL), mRuntimeVersionOverride(0)
117  {
118  }
119  
120  
121  //
122  // Clean up a SecCodeSigner
123  //
124  SecCodeSigner::~SecCodeSigner() _NOEXCEPT
125  try {
126  	delete mLimitedAsync;
127  } catch (...) {
128  	return;
129  }
130  
131  
132  //
133  // Parse an input parameter dictionary and set ready-to-use parameters
134  //
135  void SecCodeSigner::parameters(CFDictionaryRef paramDict)
136  {
137  	Parser(*this, paramDict);
138  	if (!valid())
139  		MacOSError::throwMe(errSecCSInvalidObjectRef);
140  }
141  
142  //
143  // Retrieve the team ID from the signing certificate if and only if
144  // it is an apple developer signing cert
145  //
146  std::string SecCodeSigner::getTeamIDFromSigner(CFArrayRef certs)
147  {
148  	if (mSigner && mSigner != SecIdentityRef(kCFNull)) {
149  		CFRef<SecCertificateRef> signerCert;
150  		MacOSError::check(SecIdentityCopyCertificate(mSigner, &signerCert.aref()));
151  
152  		/* Make sure the certificate looks like an Apple certificate, because we do not
153  			extract the team ID from a non Apple certificate */
154  		if (SecStaticCode::isAppleDeveloperCert(certs)) {
155  			CFRef<CFStringRef> teamIDFromCert;
156  
157  			MacOSError::check(SecCertificateCopySubjectComponent(signerCert.get(), &CSSMOID_OrganizationalUnitName, &teamIDFromCert.aref()));
158  
159  			if (teamIDFromCert)
160  				return cfString(teamIDFromCert);
161  		}
162  	}
163  
164  	return "";
165  }
166  
167  //
168  // Roughly check for validity.
169  // This isn't thorough; it just sees if if looks like we've set up the object appropriately.
170  //
171  bool SecCodeSigner::valid() const
172  {
173  	if (mOpFlags & (kSecCSRemoveSignature | kSecCSEditSignature)) {
174  		return true;
175  	}
176  	return mSigner;
177  }
178  
179  
180  //
181  // Sign code
182  //
183  void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
184  {
185  	//Never preserve a linker signature.
186  	if (code->isSigned() &&
187  		(flags & kSecCSSignPreserveSignature) &&
188  		!code->flag(kSecCodeSignatureLinkerSigned)) {
189  		return;
190  	}
191  	code->setValidationFlags(flags);
192  	Signer operation(*this, code);
193  	if ((flags | mOpFlags) & kSecCSRemoveSignature) {
194  		secinfo("signer", "%p will remove signature from %p", this, code);
195  		operation.remove(flags);
196  	} else if ((flags | mOpFlags) & kSecCSEditSignature) {
197  		secinfo("signer", "%p will edit signature of %p", this, code);
198  		operation.edit(flags);
199  	} else {
200  		if (!valid())
201  			MacOSError::throwMe(errSecCSInvalidObjectRef);
202  		secinfo("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
203  		operation.sign(flags);
204  	}
205  	code->resetValidity();
206  }
207  
208  
209  //
210  // ReturnDetachedSignature is called by writers or editors that try to return
211  // detached signature data (rather than annotate the target).
212  //
213  void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
214  {
215  	assert(mDetached);
216  	if (CFGetTypeID(mDetached) == CFURLGetTypeID()) {
217  		// URL to destination file
218  		AutoFileDesc fd(cfString(CFURLRef(mDetached.get())), O_WRONLY | O_CREAT | O_TRUNC);
219  		fd.writeAll(*blob);
220  	} else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) {
221  		CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
222  			(const UInt8 *)blob, blob->length());
223  	} else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
224  		SignatureDatabaseWriter db;
225  		db.storeCode(blob, signer.path().c_str());
226  	} else
227  		assert(false);
228  }
229  
230  
231  //
232  // The actual parsing operation is done in the Parser class.
233  //
234  // Note that we need to copy or retain all incoming data. The caller has no requirement
235  // to keep the parameters dictionary around.
236  //
237  SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
238  	: CFDictionary(parameters, errSecCSBadDictionaryFormat)
239  {
240  	CFNumberRef editCpuType = get<CFNumberRef>(kSecCodeSignerEditCpuType);
241  	CFNumberRef editCpuSubtype = get<CFNumberRef>(kSecCodeSignerEditCpuSubtype);
242  	if (editCpuType != NULL && editCpuSubtype != NULL) {
243  		state.mEditArch = Architecture(cfNumber<uint32_t>(editCpuType),
244  									   cfNumber<uint32_t>(editCpuSubtype));
245  	}
246  	
247  	state.mEditCMS = get<CFDataRef>(kSecCodeSignerEditCMS);
248  	
249  	state.mDryRun = getBool(kSecCodeSignerDryRun);
250  	
251  	state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
252  	
253  	state.mPreserveAFSC = getBool(kSecCodeSignerPreserveAFSC);
254  	
255  	if (state.mOpFlags & kSecCSEditSignature) {
256  		return;
257  		/* Everything below this point is irrelevant for
258  		 * Signature Editing, which does not create any
259  		 * parts of the signature, only replaces them.
260  		 */
261  	}
262  
263  	// the signer may be an identity or null
264  	state.mSigner = SecIdentityRef(get<CFTypeRef>(kSecCodeSignerIdentity));
265  	if (state.mSigner)
266  		if (CFGetTypeID(state.mSigner) != SecIdentityGetTypeID() && !CFEqual(state.mSigner, kCFNull))
267  			MacOSError::throwMe(errSecCSInvalidObjectRef);
268  
269  	// the flags need some augmentation
270  	if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) {
271  		state.mCdFlagsGiven = true;
272  		state.mCdFlags = cfNumber<uint32_t>(flags);
273  	} else
274  		state.mCdFlagsGiven = false;
275  	
276  	// digest algorithms are specified as a numeric code
277  	if (CFCopyRef<CFTypeRef> digestAlgorithms = get<CFTypeRef>(kSecCodeSignerDigestAlgorithm)) {
278  		CFRef<CFArrayRef> array = cfArrayize(digestAlgorithms);
279  		CFToVector<CodeDirectory::HashAlgorithm, CFNumberRef, cfNumber<CodeDirectory::HashAlgorithm> > digests(array);
280  		std::copy(digests.begin(), digests.end(), std::inserter(state.mDigestAlgorithms, state.mDigestAlgorithms.begin()));
281  	}
282  
283  	if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
284  		state.mCMSSize = cfNumber<size_t>(cmsSize);
285  	else
286  		state.mCMSSize = 18000;	// big enough for now, not forever.
287  
288  	// metadata preservation options
289  	if (CFNumberRef preserve = get<CFNumberRef>(kSecCodeSignerPreserveMetadata)) {
290  		state.mPreserveMetadata = cfNumber<uint32_t>(preserve);
291  	} else
292  		state.mPreserveMetadata = 0;
293  
294  	// signing time can be a CFDateRef or null
295  	if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime)) {
296  		if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull)
297  			state.mSigningTime = CFDateRef(time);
298  		else
299  			MacOSError::throwMe(errSecCSInvalidObjectRef);
300  	}
301  	
302  	if (CFStringRef ident = get<CFStringRef>(kSecCodeSignerIdentifier))
303  		state.mIdentifier = cfString(ident);
304  	
305  	if (CFStringRef teamid = get<CFStringRef>(kSecCodeSignerTeamIdentifier))
306  		state.mTeamID = cfString(teamid);
307  	
308  	if (CFNumberRef platform = get<CFNumberRef>(kSecCodeSignerPlatformIdentifier)) {
309  		int64_t ident = cfNumber<int64_t>(platform);
310  		if (ident < 0 || ident > maxPlatform)	// overflow
311  			MacOSError::throwMe(errSecCSInvalidPlatform);
312  		state.mPlatform = ident;
313  	}
314  	
315  	if (CFStringRef prefix = get<CFStringRef>(kSecCodeSignerIdentifierPrefix))
316  		state.mIdentifierPrefix = cfString(prefix);
317  	
318  	// Requirements can be binary or string (to be compiled).
319  	// We must pass them along to the signer for possible text substitution
320  	if (CFTypeRef reqs = get<CFTypeRef>(kSecCodeSignerRequirements)) {
321  		if (CFGetTypeID(reqs) == CFDataGetTypeID() || CFGetTypeID(reqs) == CFStringGetTypeID())
322  			state.mRequirements = reqs;
323  		else
324  			MacOSError::throwMe(errSecCSInvalidObjectRef);
325  	} else
326  		state.mRequirements = NULL;
327  	
328  	state.mNoMachO = getBool(CFSTR("no-macho"));
329  	
330  	state.mPageSize = get<CFNumberRef>(kSecCodeSignerPageSize);
331  	
332  	// detached can be (destination) file URL or (mutable) Data to be appended-to
333  	if ((state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached))) {
334  		CFTypeID type = CFGetTypeID(state.mDetached);
335  		if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
336  			MacOSError::throwMe(errSecCSInvalidObjectRef);
337  	}
338  	
339  	state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules);
340  	
341  	state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
342  	state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
343  	
344  	if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) {
345  		state.mWantTimeStamp = timestampRequest == kCFBooleanTrue;
346  	} else {	// pick default
347  		state.mWantTimeStamp = false;
348  		if (state.mSigner && state.mSigner != SecIdentityRef(kCFNull)) {
349  			CFRef<SecCertificateRef> signerCert;
350  			MacOSError::check(SecIdentityCopyCertificate(state.mSigner, &signerCert.aref()));
351  			if (certificateHasField(signerCert, devIdLeafMarkerOID))
352  				state.mWantTimeStamp = true;
353  		}
354  	}
355  	state.mTimestampAuthentication = get<SecIdentityRef>(kSecCodeSignerTimestampAuthentication);
356  	state.mTimestampService = get<CFURLRef>(kSecCodeSignerTimestampServer);
357  	state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates);
358  
359  	if (CFStringRef runtimeVersionOverride = get<CFStringRef>(kSecCodeSignerRuntimeVersion)) {
360  		std::string runtime = cfString(runtimeVersionOverride);
361  		if (runtime.empty()) {
362  			MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
363  		}
364  		state.mRuntimeVersionOverride = parseRuntimeVersion(runtime);
365  	}
366  	
367  	// Don't add the adhoc flag, even if no signer identity was specified.
368  	// Useful for editing in the CMS at a later point.
369  	state.mOmitAdhocFlag = getBool(kSecCodeSignerOmitAdhocFlag);
370  }
371  
372  
373  } // end namespace CodeSigning
374  } // end namespace Security