/ OSX / libsecurity_codesigning / lib / SecStaticCode.cpp
SecStaticCode.cpp
  1  /*
  2   * Copyright (c) 2006-2007,2011-2015 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  // SecStaticCode - API frame for SecStaticCode objects
 26  //
 27  #include "cs.h"
 28  #include "StaticCode.h"
 29  #include <security_utilities/cfmunge.h>
 30  #include <security_utilities/logging.h>
 31  #include <fcntl.h>
 32  #include <dirent.h>
 33  
 34  using namespace CodeSigning;
 35  
 36  
 37  //
 38  // CF-standard type code function
 39  //
 40  CFTypeID SecStaticCodeGetTypeID(void)
 41  {
 42  	BEGIN_CSAPI
 43  	return gCFObjects().StaticCode.typeID;
 44      END_CSAPI1(_kCFRuntimeNotATypeID)
 45  }
 46  
 47  
 48  //
 49  // Create an StaticCode directly from disk path.
 50  //
 51  OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCodeRef)
 52  {
 53  	BEGIN_CSAPI
 54  
 55  	checkFlags(flags, kSecCSForceOnlineNotarizationCheck);
 56  	CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str()), flags))->handle();
 57  
 58  	END_CSAPI
 59  }
 60  
 61  const CFStringRef kSecCodeAttributeArchitecture =	CFSTR("architecture");
 62  const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture");
 63  const CFStringRef kSecCodeAttributeBundleVersion =	CFSTR("bundleversion");
 64  const CFStringRef kSecCodeAttributeUniversalFileOffset =	CFSTR("UniversalFileOffset");
 65  
 66  OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes,
 67  	SecStaticCodeRef *staticCodeRef)
 68  {
 69  	BEGIN_CSAPI
 70  
 71  	checkFlags(flags, kSecCSForceOnlineNotarizationCheck);
 72  	DiskRep::Context ctx;
 73  	std::string version; // holds memory placed into ctx
 74  	if (attributes) {
 75  		std::string archName;
 76  		int archNumber, subarchNumber, offset;
 77  		if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeUniversalFileOffset, &offset)) {
 78  			ctx.offset = offset;
 79  		} else if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) {
 80  			ctx.arch = Architecture(archName.c_str());
 81  		} else if (cfscan(attributes, "{%O=%d,%O=%d}",
 82  				kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber))
 83  			ctx.arch = Architecture(archNumber, subarchNumber);
 84  		else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber))
 85  			ctx.arch = Architecture(archNumber);
 86  		if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version))
 87  			ctx.version = version.c_str();
 88  	}
 89  
 90  	CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx), flags))->handle();
 91  
 92  	END_CSAPI
 93  }
 94  
 95  
 96  //
 97  // Check static validity of a StaticCode
 98  //
 99  OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
100  	SecRequirementRef requirementRef)
101  {
102  	return SecStaticCodeCheckValidityWithErrors(staticCodeRef, flags, requirementRef, NULL);
103  }
104  
105  OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
106  	SecRequirementRef requirementRef, CFErrorRef *errors)
107  {
108  	BEGIN_CSAPI
109  
110  	checkFlags(flags,
111  		  kSecCSReportProgress
112  		| kSecCSCheckAllArchitectures
113  		| kSecCSDoNotValidateExecutable
114  		| kSecCSDoNotValidateResources
115  		| kSecCSConsiderExpiration
116  		| kSecCSEnforceRevocationChecks
117  		| kSecCSNoNetworkAccess
118  		| kSecCSCheckNestedCode
119  		| kSecCSStrictValidate
120  		| kSecCSStrictValidateStructure
121  		| kSecCSRestrictSidebandData
122  		| kSecCSCheckGatekeeperArchitectures
123  		| kSecCSRestrictSymlinks
124  		| kSecCSRestrictToAppLike
125  		| kSecCSUseSoftwareSigningCert
126  		| kSecCSValidatePEH
127  		| kSecCSSingleThreaded
128  		| kSecCSApplyEmbeddedPolicy
129  		| kSecCSSkipRootVolumeExceptions
130  		| kSecCSSkipXattrFiles
131  		| kSecCSAllowNetworkAccess
132  	);
133  
134  	if (errors)
135  		flags |= kSecCSFullReport;	// internal-use flag
136  
137  #if !TARGET_OS_OSX
138  	flags |= kSecCSApplyEmbeddedPolicy;
139  #endif
140  
141  	SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
142  	code->setValidationFlags(flags);
143  	const SecRequirement *req = SecRequirement::optional(requirementRef);
144  	DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
145  	code->staticValidate(flags, req);
146  
147      // Everything checked out correctly but we need to make sure that when
148      // we validated the code directory, we trusted the signer.  We defer this
149      // until now because the caller may still trust the signer via a
150      // provisioning profile so if we prematurely throw an error when validating
151      // the directory, we potentially skip resource validation even though the
152      // caller will go on to trust the signature
153      // <rdar://problem/6075501> Applications that are validated against a provisioning profile do not have their resources checked
154      if ((flags & kSecCSApplyEmbeddedPolicy) && code->trustedSigningCertChain() == false) {
155          return CSError::cfError(errors, errSecCSSignatureUntrusted);
156      }
157  
158  
159  	END_CSAPI_ERRORS
160  }
161  
162  OSStatus SecStaticCodeValidateResourceWithErrors(SecStaticCodeRef staticCodeRef, CFURLRef resourcePath, SecCSFlags flags, CFErrorRef *errors)
163  {
164  	BEGIN_CSAPI
165  
166  	checkFlags(flags,
167  		  kSecCSCheckAllArchitectures
168  		| kSecCSConsiderExpiration
169  		| kSecCSEnforceRevocationChecks
170  		| kSecCSNoNetworkAccess
171  		| kSecCSStrictValidate
172  		| kSecCSStrictValidateStructure
173  		| kSecCSRestrictSidebandData
174  		| kSecCSCheckGatekeeperArchitectures
175  		| kSecCSSkipRootVolumeExceptions
176  		| kSecCSAllowNetworkAccess
177  		| kSecCSFastExecutableValidation
178  	);
179  
180  	SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
181  	code->setValidationFlags(flags);
182  	code->staticValidateResource(cfString(resourcePath), flags, NULL);
183  
184  	END_CSAPI_ERRORS
185  }
186  
187  //
188  // ====================================================================================
189  //
190  // The following API functions are called SecCode* but accept both SecCodeRef and
191  // SecStaticCodeRef arguments, operating on the implied SecStaticCodeRef as appropriate.
192  // Hence they're here, rather than in SecCode.cpp.
193  //
194  
195  
196  //
197  // Retrieve location information for an StaticCode.
198  //
199  OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURLRef *path)
200  {
201  	BEGIN_CSAPI
202  
203  	checkFlags(flags);
204  	SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef);
205  	CodeSigning::Required(path) = staticCode->copyCanonicalPath();
206  
207  	END_CSAPI
208  }
209  
210  
211  //
212  // Fetch or make up a designated requirement
213  //
214  OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
215  	SecRequirementRef *requirementRef)
216  {
217  	BEGIN_CSAPI
218  
219  	checkFlags(flags);
220  	const Requirement *req =
221  		SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement();
222  	CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle();
223  
224  	END_CSAPI
225  }
226  
227  
228  //
229  // Fetch a particular internal requirement, if present
230  //
231  OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type,
232  	SecCSFlags flags, SecRequirementRef *requirementRef)
233  {
234  	BEGIN_CSAPI
235  
236  	checkFlags(flags);
237  	const Requirement *req =
238  		SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
239  	CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
240  
241  	END_CSAPI
242  }
243  
244  
245  //
246  // Record for future use a detached code signature.
247  //
248  OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef codeRef, CFDataRef signature,
249  	SecCSFlags flags)
250  {
251  	BEGIN_CSAPI
252  
253  	checkFlags(flags);
254  	SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
255  
256  	code->detachedSignature(signature); // ... and pass it to the code
257  	code->resetValidity();
258  
259  	END_CSAPI
260  }
261  
262  
263  //
264  // Attach a code signature to a kernel memory mapping for page-in validation.
265  //
266  OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags)
267  {
268  	BEGIN_CSAPI
269  
270  	checkFlags(flags);
271  	SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
272  	if (const CodeDirectory *cd = code->codeDirectory(false)) {
273  		if (code->isDetached()) {
274  			// Detached signatures need to attach their code directory from memory.
275  			fsignatures args = { static_cast<off_t>(code->diskRep()->signingBase()), (void *)cd, cd->length() };
276  			UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDSIGS, &args));
277  		} else {
278  			// All other signatures can simply point to the signature in the main executable.
279  			Universal *execImage = code->diskRep()->mainExecutableImage();
280  			if (execImage == NULL) {
281  				MacOSError::throwMe(errSecCSNoMainExecutable);
282  			}
283  
284  			unique_ptr<MachO> arch(execImage->architecture());
285  			if (arch.get() == NULL) {
286  				MacOSError::throwMe(errSecCSNoMainExecutable);
287  			}
288  
289  			size_t signatureOffset = arch->signingOffset();
290  			size_t signatureLength = arch->signingLength();
291  			if (signatureOffset == 0) {
292  				MacOSError::throwMe(errSecCSUnsigned);
293  			}
294  
295  			fsignatures args = {
296  				static_cast<off_t>(code->diskRep()->signingBase()),
297  				(void *)signatureOffset,
298  				signatureLength,
299  			};
300  			UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDFILESIGS, &args));
301  		}
302  	} else {
303  		MacOSError::throwMe(errSecCSUnsigned);
304  	}
305  
306  	END_CSAPI
307  }
308  
309  
310  //
311  // Attach a callback block to a code object
312  //
313  OSStatus SecStaticCodeSetCallback(SecStaticCodeRef codeRef, SecCSFlags flags, SecCodeCallback *old, SecCodeCallback monitor)
314  {
315  	BEGIN_CSAPI
316  
317  	checkFlags(flags);
318  	SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
319  	if (old)
320  		*old = code->monitor();
321  	code->setMonitor(monitor);
322  
323  	END_CSAPI
324  }
325  
326  
327  OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef codeRef, CFDictionaryRef conditions)
328  {
329  	BEGIN_CSAPI
330  
331  	checkFlags(0);
332  	SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
333  	code->setValidationModifiers(conditions);
334  
335  	END_CSAPI
336  }
337  
338  
339  //
340  // Set cancellation flag on a static code object.
341  //
342  OSStatus SecStaticCodeCancelValidation(SecStaticCodeRef codeRef, SecCSFlags flags)
343  {
344  	BEGIN_CSAPI
345  
346  	checkFlags(0);
347  	SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
348  	code->cancelValidation();
349  
350  	END_CSAPI
351  }
352  
353  
354  //
355  // Retrieve a component object for a special slot directly.
356  //
357  CFDataRef SecCodeCopyComponent(SecCodeRef codeRef, int slot, CFDataRef hash)
358  {
359  	BEGIN_CSAPI
360  	
361  	SecStaticCode* code = SecStaticCode::requiredStatic(codeRef);
362  	return code->copyComponent(slot, hash);
363  	
364  	END_CSAPI1(NULL)
365  }
366  
367  //
368  // Updates the flags to indicate whether this object wants to enable online notarization checks.
369  //
370  OSStatus SecStaticCodeEnableOnlineNotarizationCheck(SecStaticCodeRef codeRef, Boolean enable)
371  {
372  	BEGIN_CSAPI
373  
374  	SecStaticCode* code = SecStaticCode::requiredStatic(codeRef);
375  	SecCSFlags flags = code->getFlags();
376  	if (enable) {
377  		flags = addFlags(flags, kSecCSForceOnlineNotarizationCheck);
378  	} else {
379  		flags = clearFlags(flags, kSecCSForceOnlineNotarizationCheck);
380  	}
381  	code->setFlags(flags);
382  
383  	END_CSAPI
384  }
385  
386  //
387  // Validate a single plain file's resource seal against a memory copy.
388  // This will fail for any other file type (symlink, directory, nested code, etc. etc.)
389  //
390  OSStatus SecCodeValidateFileResource(SecStaticCodeRef codeRef, CFStringRef relativePath, CFDataRef fileData, SecCSFlags flags)
391  {
392      BEGIN_CSAPI
393      
394      checkFlags(0);
395      if (fileData == NULL)
396          MacOSError::throwMe(errSecCSObjectRequired);
397      SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
398      code->validatePlainMemoryResource(cfString(relativePath), fileData, flags);
399      
400      END_CSAPI
401      
402  }