/ OSX / libsecurity_codesigning / lib / SecCode.cpp
SecCode.cpp
  1  /*
  2   * Copyright (c) 2006-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  // SecCode - API frame for SecCode objects.
 26  //
 27  // Note that some SecCode* functions take SecStaticCodeRef arguments in order to
 28  // accept either static or dynamic code references, operating on the respective
 29  // StaticCode. Those functions are in SecStaticCode.cpp, not here, despite their name.
 30  //
 31  #include "cs.h"
 32  #include "Code.h"
 33  #include "cskernel.h"
 34  #include <security_utilities/cfmunge.h>
 35  #include <security_utilities/logging.h>
 36  #include <xpc/private.h>
 37  
 38  using namespace CodeSigning;
 39  
 40  
 41  //
 42  // CFError user info keys
 43  //
 44  const CFStringRef kSecCFErrorArchitecture =		CFSTR("SecCSArchitecture");
 45  const CFStringRef kSecCFErrorPattern =			CFSTR("SecCSPattern");
 46  const CFStringRef kSecCFErrorResourceSeal =		CFSTR("SecCSResourceSeal");
 47  const CFStringRef kSecCFErrorResourceAdded =		CFSTR("SecCSResourceAdded");
 48  const CFStringRef kSecCFErrorResourceAltered =	CFSTR("SecCSResourceAltered");
 49  const CFStringRef kSecCFErrorResourceMissing =	CFSTR("SecCSResourceMissing");
 50  const CFStringRef kSecCFErrorResourceSideband =	CFSTR("SecCSResourceHasSidebandData");
 51  const CFStringRef kSecCFErrorInfoPlist =			CFSTR("SecCSInfoPlist");
 52  const CFStringRef kSecCFErrorGuestAttributes =	CFSTR("SecCSGuestAttributes");
 53  const CFStringRef kSecCFErrorRequirementSyntax = CFSTR("SecRequirementSyntax");
 54  const CFStringRef kSecCFErrorPath =				CFSTR("SecComponentPath");
 55  
 56  
 57  //
 58  // CF-standard type code functions
 59  //
 60  CFTypeID SecCodeGetTypeID(void)
 61  {
 62  	BEGIN_CSAPI
 63  	return gCFObjects().Code.typeID;
 64      END_CSAPI1(_kCFRuntimeNotATypeID)
 65  }
 66  
 67  
 68  //
 69  // Get a reference to the calling code.
 70  //
 71  OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
 72  {
 73  	BEGIN_CSAPI
 74  
 75  	checkFlags(flags);
 76  	CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
 77  		kSecGuestAttributePid, CFTempNumber(getpid()).get());
 78  	CodeSigning::Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
 79  
 80  	END_CSAPI
 81  }
 82  
 83  
 84  //
 85  // Get the dynamic status of a code.
 86  //
 87  OSStatus SecCodeGetStatus(SecCodeRef codeRef, SecCSFlags flags, SecCodeStatus *status)
 88  {
 89  	BEGIN_CSAPI
 90  
 91  	checkFlags(flags);
 92  	CodeSigning::Required(status) = SecCode::required(codeRef)->status();
 93  
 94  	END_CSAPI
 95  }
 96  
 97  
 98  //
 99  // Change the dynamic status of a code
100  //
101  OSStatus SecCodeSetStatus(SecCodeRef codeRef, SecCodeStatusOperation operation,
102  	CFDictionaryRef arguments, SecCSFlags flags)
103  {
104  	BEGIN_CSAPI
105  
106  	checkFlags(flags);
107  	SecCode::required(codeRef)->status(operation, arguments);
108  
109  	END_CSAPI
110  }
111  
112  
113  //
114  // Get the StaticCode for an Code
115  //
116  OSStatus SecCodeCopyStaticCode(SecCodeRef codeRef, SecCSFlags flags, SecStaticCodeRef *staticCodeRef)
117  {
118  	BEGIN_CSAPI
119  
120  	checkFlags(flags, kSecCSUseAllArchitectures);
121  	SecPointer<SecStaticCode> staticCode = SecCode::required(codeRef)->staticCode();
122  	if (flags & kSecCSUseAllArchitectures)
123  		if (Universal* macho = staticCode->diskRep()->mainExecutableImage())	// Mach-O main executable
124  			if (macho->narrowed()) {
125  				// create a new StaticCode comprising the whole fat file
126  				RefPointer<DiskRep> rep = DiskRep::bestGuess(staticCode->diskRep()->mainExecutablePath());
127  				staticCode = new SecStaticCode(rep);
128  			}
129  	CodeSigning::Required(staticCodeRef) = staticCode ? staticCode->handle() : NULL;
130  
131  	END_CSAPI
132  }
133  
134  
135  //
136  // Get the host for an Code
137  //
138  OSStatus SecCodeCopyHost(SecCodeRef guestRef, SecCSFlags flags, SecCodeRef *hostRef)
139  {
140  	BEGIN_CSAPI
141  
142  	checkFlags(flags);
143  	SecPointer<SecCode> host = SecCode::required(guestRef)->host();
144  	CodeSigning::Required(hostRef) = host ? host->handle() : NULL;
145  
146  	END_CSAPI
147  }
148  
149  
150  //
151  // Find a guest by attribute(s)
152  //
153  const CFStringRef kSecGuestAttributeCanonical =		CFSTR("canonical");
154  const CFStringRef kSecGuestAttributeHash =			CFSTR("codedirectory-hash");
155  const CFStringRef kSecGuestAttributeMachPort =		CFSTR("mach-port");
156  const CFStringRef kSecGuestAttributePid =			CFSTR("pid");
157  const CFStringRef kSecGuestAttributeAudit =			CFSTR("audit");
158  const CFStringRef kSecGuestAttributeDynamicCode =	CFSTR("dynamicCode");
159  const CFStringRef kSecGuestAttributeDynamicCodeInfoPlist = CFSTR("dynamicCodeInfoPlist");
160  const CFStringRef kSecGuestAttributeArchitecture =	CFSTR("architecture");
161  const CFStringRef kSecGuestAttributeSubarchitecture = CFSTR("subarchitecture");
162  
163  #if TARGET_OS_OSX
164  OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef hostRef,
165  	CFDictionaryRef attributes,	SecCSFlags flags, SecCodeRef *guestRef)
166  {
167  	BEGIN_CSAPI
168  
169  	checkFlags(flags);
170  	if (hostRef) {
171  		if (SecCode *guest = SecCode::required(hostRef)->locateGuest(attributes))
172  			CodeSigning::Required(guestRef) = guest->handle(false);
173  		else
174  			return errSecCSNoSuchCode;
175  	} else
176  		CodeSigning::Required(guestRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
177  
178  	END_CSAPI
179  }
180  
181  
182  //
183  // Deprecated since 10.6, DO NOT USE. This can be raced.
184  // Use SecCodeCreateWithAuditToken instead.
185  //
186  OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *processRef)
187  {
188  	BEGIN_CSAPI
189  
190  	checkFlags(flags);
191  	if (SecCode *guest = KernelCode::active()->locateGuest(CFTemp<CFDictionaryRef>("{%O=%d}", kSecGuestAttributePid, pid)))
192  		CodeSigning::Required(processRef) = guest->handle(false);
193  	else
194  		return errSecCSNoSuchCode;
195  
196  	END_CSAPI
197  }
198  
199  //
200  // Shorthand for getting the SecCodeRef for a UNIX process
201  //
202  OSStatus SecCodeCreateWithAuditToken(const audit_token_t *audit,
203  									 SecCSFlags flags, SecCodeRef *processRef)
204  {
205  	BEGIN_CSAPI
206  	
207  	checkFlags(flags);
208  	CFRef<CFDataRef> auditData = makeCFData(audit, sizeof(audit_token_t));
209  	if (SecCode *guest = KernelCode::active()->locateGuest(CFTemp<CFDictionaryRef>("{%O=%O}", kSecGuestAttributeAudit, auditData.get()))) {
210  		CodeSigning::Required(processRef) = guest->handle(false);
211  	} else {
212  		return errSecCSNoSuchCode;
213  	}
214  	
215  	END_CSAPI
216  }
217  
218  OSStatus SecCodeCreateWithXPCMessage(xpc_object_t message, SecCSFlags flags,
219  									 SecCodeRef * __nonnull CF_RETURNS_RETAINED target)
220  {
221  	BEGIN_CSAPI
222  
223  	checkFlags(flags);
224  
225  	if (xpc_get_type(message) != XPC_TYPE_DICTIONARY) {
226  		return errSecCSInvalidObjectRef;
227  	}
228  	
229  	xpc_connection_t connection = xpc_dictionary_get_remote_connection(message);
230  	if (connection == NULL) {
231  		return errSecCSInvalidObjectRef;
232  	}
233  
234  	audit_token_t t = {0};
235  	xpc_connection_get_audit_token(connection, &t);
236  
237  	return SecCodeCreateWithAuditToken(&t, flags, target);
238  
239  	END_CSAPI
240  }
241  
242  #endif // TARGET_OS_OSX
243  
244  
245  //
246  // Check validity of an Code
247  //
248  OSStatus SecCodeCheckValidity(SecCodeRef codeRef, SecCSFlags flags,
249  	SecRequirementRef requirementRef)
250  {
251  	return SecCodeCheckValidityWithErrors(codeRef, flags, requirementRef, NULL);
252  }
253  
254  OSStatus SecCodeCheckValidityWithErrors(SecCodeRef codeRef, SecCSFlags flags,
255  	SecRequirementRef requirementRef, CFErrorRef *errors)
256  {
257  	BEGIN_CSAPI
258  
259  	checkFlags(flags,
260  		  kSecCSConsiderExpiration
261  		| kSecCSStrictValidate
262  		| kSecCSStrictValidateStructure
263  		| kSecCSRestrictSidebandData
264  		| kSecCSEnforceRevocationChecks
265  		| kSecCSAllowNetworkAccess
266  		| kSecCSNoNetworkAccess
267  	);
268  	SecPointer<SecCode> code = SecCode::required(codeRef);
269  	code->checkValidity(flags);
270  	if (const SecRequirement *req = SecRequirement::optional(requirementRef))
271  		code->staticCode()->validateRequirement(req->requirement(), errSecCSReqFailed);
272  
273  	END_CSAPI_ERRORS
274  }
275  
276  
277  //
278  // Collect suitably laundered information about the code signature of a SecStaticCode
279  // and return it as a CFDictionary.
280  //
281  // This API contracts to return a few pieces of information even for unsigned
282  // code. This means that a SecStaticCodeRef is usable as a basic indentifier
283  // (i.e. handle) for any code out there.
284  //
285  const CFStringRef kSecCodeInfoCertificates =	CFSTR("certificates");
286  const CFStringRef kSecCodeInfoChangedFiles =	CFSTR("changed-files");
287  const CFStringRef kSecCodeInfoCMS =				CFSTR("cms");
288  const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement");
289  const CFStringRef kSecCodeInfoEntitlements =	CFSTR("entitlements");
290  const CFStringRef kSecCodeInfoEntitlementsDict =	CFSTR("entitlements-dict");
291  const CFStringRef kSecCodeInfoFlags =			CFSTR("flags");
292  const CFStringRef kSecCodeInfoFormat =			CFSTR("format");
293  const CFStringRef kSecCodeInfoDigestAlgorithm =	CFSTR("digest-algorithm");
294  const CFStringRef kSecCodeInfoDigestAlgorithms = CFSTR("digest-algorithms");
295  const CFStringRef kSecCodeInfoPlatformIdentifier = CFSTR("platform-identifier");
296  const CFStringRef kSecCodeInfoIdentifier =		CFSTR("identifier");
297  const CFStringRef kSecCodeInfoImplicitDesignatedRequirement = CFSTR("implicit-requirement");
298  const CFStringRef kSecCodeInfoMainExecutable =	CFSTR("main-executable");
299  const CFStringRef kSecCodeInfoPList =			CFSTR("info-plist");
300  const CFStringRef kSecCodeInfoRequirements =	CFSTR("requirements");
301  const CFStringRef kSecCodeInfoRequirementData =	CFSTR("requirement-data");
302  const CFStringRef kSecCodeInfoSource =			CFSTR("source");
303  const CFStringRef kSecCodeInfoStatus =			CFSTR("status");
304  const CFStringRef kSecCodeInfoTeamIdentifier =  CFSTR("teamid");
305  const CFStringRef kSecCodeInfoTime =			CFSTR("signing-time");
306  const CFStringRef kSecCodeInfoTimestamp =		CFSTR("signing-timestamp");
307  const CFStringRef kSecCodeInfoTrust =			CFSTR("trust");
308  const CFStringRef kSecCodeInfoUnique =			CFSTR("unique");
309  const CFStringRef kSecCodeInfoCdHashes =        CFSTR("cdhashes");
310  const CFStringRef kSecCodeInfoCdHashesFull =	CFSTR("cdhashes-full");
311  const CFStringRef kSecCodeInfoRuntimeVersion = 	CFSTR("runtime-version");
312  
313  const CFStringRef kSecCodeInfoCodeDirectory =	CFSTR("CodeDirectory");
314  const CFStringRef kSecCodeInfoCodeOffset =		CFSTR("CodeOffset");
315  const CFStringRef kSecCodeInfoDiskRepInfo =     CFSTR("DiskRepInfo");
316  const CFStringRef kSecCodeInfoResourceDirectory = CFSTR("ResourceDirectory");
317  const CFStringRef kSecCodeInfoNotarizationDate = CFSTR("NotarizationDate");
318  const CFStringRef kSecCodeInfoCMSDigestHashType = CFSTR("CMSDigestHashType");
319  const CFStringRef kSecCodeInfoCMSDigest =        CFSTR("CMSDigest");
320  const CFStringRef kSecCodeInfoSignatureVersion = CFSTR("SignatureVersion");
321  
322  /* DiskInfoRepInfo types */
323  const CFStringRef kSecCodeInfoDiskRepVersionPlatform =	 	CFSTR("VersionPlatform");
324  const CFStringRef kSecCodeInfoDiskRepVersionMin =        	CFSTR("VersionMin");
325  const CFStringRef kSecCodeInfoDiskRepVersionSDK =        	CFSTR("VersionSDK");
326  const CFStringRef kSecCodeInfoDiskRepNoLibraryValidation = 	CFSTR("NoLibraryValidation");
327  
328  
329  OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flags,
330  	CFDictionaryRef *infoRef)
331  {
332  	BEGIN_CSAPI
333  
334  	checkFlags(flags,
335  		  kSecCSInternalInformation
336  		| kSecCSSigningInformation
337  		| kSecCSRequirementInformation
338  		| kSecCSDynamicInformation
339  		| kSecCSContentInformation
340  		| kSecCSSkipResourceDirectory
341  		| kSecCSCalculateCMSDigest);
342  
343  	SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
344  	CFRef<CFDictionaryRef> info = code->signingInformation(flags);
345  
346  	if (flags & kSecCSDynamicInformation)
347  		if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef))
348  			info.take(cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(), kSecCodeInfoStatus, dcode->status()));
349  
350  	CodeSigning::Required(infoRef) = info.yield();
351  
352  	END_CSAPI
353  }