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// 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
36using namespace CodeSigning;
37
38
39//
40// CFError user info keys
41//
42const CFStringRef kSecCFErrorArchitecture =		CFSTR("SecCSArchitecture");
43const CFStringRef kSecCFErrorPattern =			CFSTR("SecCSPattern");
44const CFStringRef kSecCFErrorResourceSeal =		CFSTR("SecCSResourceSeal");
45const CFStringRef kSecCFErrorResourceAdded =		CFSTR("SecCSResourceAdded");
46const CFStringRef kSecCFErrorResourceAltered =	CFSTR("SecCSResourceAltered");
47const CFStringRef kSecCFErrorResourceMissing =	CFSTR("SecCSResourceMissing");
48const CFStringRef kSecCFErrorInfoPlist =			CFSTR("SecCSInfoPlist");
49const CFStringRef kSecCFErrorGuestAttributes =	CFSTR("SecCSGuestAttributes");
50const CFStringRef kSecCFErrorRequirementSyntax = CFSTR("SecRequirementSyntax");
51const CFStringRef kSecCFErrorPath =				CFSTR("SecComponentPath");
52
53
54//
55// CF-standard type code functions
56//
57CFTypeID SecCodeGetTypeID(void)
58{
59	BEGIN_CSAPI
60	return gCFObjects().Code.typeID;
61    END_CSAPI1(_kCFRuntimeNotATypeID)
62}
63
64
65//
66// Get a reference to the calling code.
67//
68OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
69{
70	BEGIN_CSAPI
71
72	checkFlags(flags);
73	CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
74		kSecGuestAttributePid, CFTempNumber(getpid()).get());
75	CodeSigning::Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
76
77	END_CSAPI
78}
79
80
81//
82// Get the dynamic status of a code.
83//
84OSStatus SecCodeGetStatus(SecCodeRef codeRef, SecCSFlags flags, SecCodeStatus *status)
85{
86	BEGIN_CSAPI
87
88	checkFlags(flags);
89	CodeSigning::Required(status) = SecCode::required(codeRef)->status();
90
91	END_CSAPI
92}
93
94
95//
96// Change the dynamic status of a code
97//
98OSStatus SecCodeSetStatus(SecCodeRef codeRef, SecCodeStatusOperation operation,
99	CFDictionaryRef arguments, SecCSFlags flags)
100{
101	BEGIN_CSAPI
102
103	checkFlags(flags);
104	SecCode::required(codeRef)->status(operation, arguments);
105
106	END_CSAPI
107}
108
109
110//
111// Get the StaticCode for an Code
112//
113OSStatus SecCodeCopyStaticCode(SecCodeRef codeRef, SecCSFlags flags, SecStaticCodeRef *staticCodeRef)
114{
115	BEGIN_CSAPI
116
117	checkFlags(flags, kSecCSUseAllArchitectures);
118	SecPointer<SecStaticCode> staticCode = SecCode::required(codeRef)->staticCode();
119	if (flags & kSecCSUseAllArchitectures)
120		if (Universal* macho = staticCode->diskRep()->mainExecutableImage())	// Mach-O main executable
121			if (macho->narrowed()) {
122				// create a new StaticCode comprising the whole fat file
123				RefPointer<DiskRep> rep = DiskRep::bestGuess(staticCode->diskRep()->mainExecutablePath());
124				staticCode = new SecStaticCode(rep);
125			}
126	CodeSigning::Required(staticCodeRef) = staticCode ? staticCode->handle() : NULL;
127
128	END_CSAPI
129}
130
131
132//
133// Get the host for an Code
134//
135OSStatus SecCodeCopyHost(SecCodeRef guestRef, SecCSFlags flags, SecCodeRef *hostRef)
136{
137	BEGIN_CSAPI
138
139	checkFlags(flags);
140	SecPointer<SecCode> host = SecCode::required(guestRef)->host();
141	CodeSigning::Required(hostRef) = host ? host->handle() : NULL;
142
143	END_CSAPI
144}
145
146
147//
148// Find a guest by attribute(s)
149//
150const CFStringRef kSecGuestAttributeCanonical =		CFSTR("canonical");
151const CFStringRef kSecGuestAttributeHash =			CFSTR("codedirectory-hash");
152const CFStringRef kSecGuestAttributeMachPort =		CFSTR("mach-port");
153const CFStringRef kSecGuestAttributePid =			CFSTR("pid");
154const CFStringRef kSecGuestAttributeDynamicCode =               CFSTR("dynamicCode");
155const CFStringRef kSecGuestAttributeDynamicCodeInfoPlist =               CFSTR("dynamicCodeInfoPlist");
156const CFStringRef kSecGuestAttributeArchitecture =	CFSTR("architecture");
157const CFStringRef kSecGuestAttributeSubarchitecture = CFSTR("subarchitecture");
158
159OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef hostRef,
160	CFDictionaryRef attributes,	SecCSFlags flags, SecCodeRef *guestRef)
161{
162	BEGIN_CSAPI
163
164	checkFlags(flags);
165	if (hostRef) {
166		if (SecCode *guest = SecCode::required(hostRef)->locateGuest(attributes))
167			CodeSigning::Required(guestRef) = guest->handle(false);
168		else
169			return errSecCSNoSuchCode;
170	} else
171		CodeSigning::Required(guestRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
172
173	END_CSAPI
174}
175
176
177//
178// Shorthand for getting the SecCodeRef for a UNIX process
179//
180OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *processRef)
181{
182	BEGIN_CSAPI
183
184	checkFlags(flags);
185	if (SecCode *guest = KernelCode::active()->locateGuest(CFTemp<CFDictionaryRef>("{%O=%d}", kSecGuestAttributePid, pid)))
186		CodeSigning::Required(processRef) = guest->handle(false);
187	else
188		return errSecCSNoSuchCode;
189
190	END_CSAPI
191}
192
193
194//
195// Check validity of an Code
196//
197OSStatus SecCodeCheckValidity(SecCodeRef codeRef, SecCSFlags flags,
198	SecRequirementRef requirementRef)
199{
200	return SecCodeCheckValidityWithErrors(codeRef, flags, requirementRef, NULL);
201}
202
203OSStatus SecCodeCheckValidityWithErrors(SecCodeRef codeRef, SecCSFlags flags,
204	SecRequirementRef requirementRef, CFErrorRef *errors)
205{
206	BEGIN_CSAPI
207
208	checkFlags(flags,
209		  kSecCSConsiderExpiration
210		| kSecCSEnforceRevocationChecks);
211	SecPointer<SecCode> code = SecCode::required(codeRef);
212	code->checkValidity(flags);
213	if (const SecRequirement *req = SecRequirement::optional(requirementRef))
214		code->staticCode()->validateRequirement(req->requirement(), errSecCSReqFailed);
215
216	END_CSAPI_ERRORS
217}
218
219
220//
221// Collect suitably laundered information about the code signature of a SecStaticCode
222// and return it as a CFDictionary.
223//
224// This API contracts to return a few pieces of information even for unsigned
225// code. This means that a SecStaticCodeRef is usable as a basic indentifier
226// (i.e. handle) for any code out there.
227//
228const CFStringRef kSecCodeInfoCertificates =	CFSTR("certificates");
229const CFStringRef kSecCodeInfoChangedFiles =	CFSTR("changed-files");
230const CFStringRef kSecCodeInfoCMS =				CFSTR("cms");
231const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement");
232const CFStringRef kSecCodeInfoEntitlements =	CFSTR("entitlements");
233const CFStringRef kSecCodeInfoEntitlementsDict =	CFSTR("entitlements-dict");
234const CFStringRef kSecCodeInfoFlags =			CFSTR("flags");
235const CFStringRef kSecCodeInfoFormat =			CFSTR("format");
236const CFStringRef kSecCodeInfoDigestAlgorithm =	CFSTR("digest-algorithm");
237const CFStringRef kSecCodeInfoIdentifier =		CFSTR("identifier");
238const CFStringRef kSecCodeInfoImplicitDesignatedRequirement = CFSTR("implicit-requirement");
239const CFStringRef kSecCodeInfoMainExecutable =	CFSTR("main-executable");
240const CFStringRef kSecCodeInfoPList =			CFSTR("info-plist");
241const CFStringRef kSecCodeInfoRequirements =	CFSTR("requirements");
242const CFStringRef kSecCodeInfoRequirementData =	CFSTR("requirement-data");
243const CFStringRef kSecCodeInfoSource =			CFSTR("source");
244const CFStringRef kSecCodeInfoStatus =			CFSTR("status");
245const CFStringRef kSecCodeInfoTeamIdentifier =  CFSTR("teamid");
246const CFStringRef kSecCodeInfoTime =			CFSTR("signing-time");
247const CFStringRef kSecCodeInfoTimestamp =		CFSTR("signing-timestamp");
248const CFStringRef kSecCodeInfoTrust =			CFSTR("trust");
249const CFStringRef kSecCodeInfoUnique =			CFSTR("unique");
250
251const CFStringRef kSecCodeInfoCodeDirectory =	CFSTR("CodeDirectory");
252const CFStringRef kSecCodeInfoCodeOffset =		CFSTR("CodeOffset");
253const CFStringRef kSecCodeInfoResourceDirectory = CFSTR("ResourceDirectory");
254
255
256OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flags,
257	CFDictionaryRef *infoRef)
258{
259	BEGIN_CSAPI
260
261	checkFlags(flags,
262		  kSecCSInternalInformation
263		| kSecCSSigningInformation
264		| kSecCSRequirementInformation
265		| kSecCSDynamicInformation
266		| kSecCSContentInformation);
267
268	SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
269	CFRef<CFDictionaryRef> info = code->signingInformation(flags);
270
271	if (flags & kSecCSDynamicInformation)
272		if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef))
273			info.take(cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(), kSecCodeInfoStatus, dcode->status()));
274
275	CodeSigning::Required(infoRef) = info.yield();
276
277	END_CSAPI
278}
279