1/*
2 * Copyright (c) 2002-2004,2011-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#include <Security/SecTrustedApplicationPriv.h>
25#include <security_keychain/TrustedApplication.h>
26#include <security_keychain/Certificate.h>
27#include <securityd_client/ssclient.h>		// for code equivalence SPIs
28
29#include "SecBridge.h"
30
31
32
33#pragma clang diagnostic push
34#pragma clang diagnostic ignored "-Wunused-function"
35static inline CssmData cfData(CFDataRef data)
36{
37    return CssmData(const_cast<UInt8 *>(CFDataGetBytePtr(data)),
38        CFDataGetLength(data));
39}
40#pragma clang diagnostic pop
41
42
43CFTypeID
44SecTrustedApplicationGetTypeID(void)
45{
46	BEGIN_SECAPI
47
48	return gTypes().TrustedApplication.typeID;
49
50	END_SECAPI1(_kCFRuntimeNotATypeID)
51}
52
53
54OSStatus
55SecTrustedApplicationCreateFromPath(const char *path, SecTrustedApplicationRef *appRef)
56{
57	BEGIN_SECAPI
58	SecPointer<TrustedApplication> app =
59		path ? new TrustedApplication(path) : new TrustedApplication;
60	Required(appRef) = app->handle();
61	END_SECAPI
62}
63
64OSStatus SecTrustedApplicationCopyData(SecTrustedApplicationRef appRef,
65	CFDataRef *dataRef)
66{
67	BEGIN_SECAPI
68	const char *path = TrustedApplication::required(appRef)->path();
69	Required(dataRef) = CFDataCreate(NULL, (const UInt8 *)path, strlen(path) + 1);
70	END_SECAPI
71}
72
73OSStatus SecTrustedApplicationSetData(SecTrustedApplicationRef appRef,
74	CFDataRef dataRef)
75{
76	BEGIN_SECAPI
77	if (!dataRef)
78		return errSecParam;
79	TrustedApplication::required(appRef)->data(dataRef);
80	END_SECAPI
81}
82
83
84OSStatus
85SecTrustedApplicationValidateWithPath(SecTrustedApplicationRef appRef, const char *path)
86{
87	BEGIN_SECAPI
88	TrustedApplication &app = *TrustedApplication::required(appRef);
89	if (!app.verifyToDisk(path))
90		return CSSMERR_CSP_VERIFY_FAILED;
91	END_SECAPI
92}
93
94
95//
96// Convert from/to external data representation
97//
98OSStatus SecTrustedApplicationCopyExternalRepresentation(
99	SecTrustedApplicationRef appRef,
100	CFDataRef *externalRef)
101{
102	BEGIN_SECAPI
103	TrustedApplication &app = *TrustedApplication::required(appRef);
104	Required(externalRef) = app.externalForm();
105	END_SECAPI
106}
107
108OSStatus SecTrustedApplicationCreateWithExternalRepresentation(
109	CFDataRef externalRef,
110	SecTrustedApplicationRef *appRef)
111{
112	BEGIN_SECAPI
113	Required(appRef) = (new TrustedApplication(externalRef))->handle();
114	END_SECAPI
115}
116
117
118OSStatus
119SecTrustedApplicationMakeEquivalent(SecTrustedApplicationRef oldRef,
120	SecTrustedApplicationRef newRef, UInt32 flags)
121{
122	BEGIN_SECAPI
123	if (flags & ~kSecApplicationValidFlags)
124		return errSecParam;
125	SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
126	TrustedApplication *oldApp = TrustedApplication::required(oldRef);
127	TrustedApplication *newApp = TrustedApplication::required(newRef);
128	ss.addCodeEquivalence(oldApp->legacyHash(), newApp->legacyHash(), oldApp->path(),
129		flags & kSecApplicationFlagSystemwide);
130	END_SECAPI
131}
132
133OSStatus
134SecTrustedApplicationRemoveEquivalence(SecTrustedApplicationRef appRef, UInt32 flags)
135{
136	BEGIN_SECAPI
137	if (flags & ~kSecApplicationValidFlags)
138		return errSecParam;
139	SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
140	TrustedApplication *app = TrustedApplication::required(appRef);
141	ss.removeCodeEquivalence(app->legacyHash(), app->path(),
142		flags & kSecApplicationFlagSystemwide);
143	END_SECAPI
144}
145
146
147/*
148 * Check to see if an application at a given path is a candidate for
149 * pre-emptive code equivalency establishment
150 */
151OSStatus
152SecTrustedApplicationIsUpdateCandidate(const char *installroot, const char *path)
153{
154    BEGIN_SECAPI
155
156	// strip installroot
157	if (installroot) {
158		size_t rootlen = strlen(installroot);
159		if (!strncmp(installroot, path, rootlen))
160			path += rootlen - 1;	// keep the slash
161	}
162
163	// look up in database
164	static ModuleNexus<PathDatabase> paths;
165	static ModuleNexus<RecursiveMutex> mutex;
166	StLock<Mutex>_(mutex());
167
168	if (!paths()[path])
169		return CSSMERR_DL_RECORD_NOT_FOUND;	// whatever
170    END_SECAPI
171}
172
173
174/*
175 * Point the system at another system root for equivalence use.
176 * This is for system update installers (only)!
177 */
178OSStatus
179SecTrustedApplicationUseAlternateSystem(const char *systemRoot)
180{
181	BEGIN_SECAPI
182	Required(systemRoot);
183	SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
184	ss.setAlternateSystemRoot(systemRoot);
185	END_SECAPI
186}
187
188
189/*
190 * Gateway between traditional SecTrustedApplicationRefs and the Code Signing
191 * subsystem. Invisible to the naked eye, as of 10.5 (Leopard), these reference
192 * may contain Cod e Signing Requirement objects (SecRequirementRefs). For backward
193 * compatibility, these are handled implicitly at the SecAccess/SecACL layer.
194 * However, Those Who Know can bridge the gap for additional functionality.
195 */
196OSStatus SecTrustedApplicationCreateFromRequirement(const char *description,
197	SecRequirementRef requirement, SecTrustedApplicationRef *appRef)
198{
199	BEGIN_SECAPI
200	if (description == NULL)
201		description = "csreq://";	// default to "generic requirement"
202	SecPointer<TrustedApplication> app = new TrustedApplication(description, requirement);
203	Required(appRef) = app->handle();
204	END_SECAPI
205}
206
207OSStatus SecTrustedApplicationCopyRequirement(SecTrustedApplicationRef appRef,
208	SecRequirementRef *requirement)
209{
210	BEGIN_SECAPI
211	Required(requirement) = TrustedApplication::required(appRef)->requirement();
212	if (*requirement)
213		CFRetain(*requirement);
214	END_SECAPI
215}
216
217
218/*
219 * Create an application group reference.
220 */
221OSStatus SecTrustedApplicationCreateApplicationGroup(const char *groupName,
222	SecCertificateRef anchor, SecTrustedApplicationRef *appRef)
223{
224	BEGIN_SECAPI
225
226	CFRef<SecRequirementRef> req;
227	MacOSError::check(SecRequirementCreateGroup(CFTempString(groupName), anchor,
228		kSecCSDefaultFlags, &req.aref()));
229	string description = string("group://") + groupName;
230	if (anchor) {
231		Certificate *cert = Certificate::required(anchor);
232		const CssmData &hash = cert->publicKeyHash();
233		description = description + "?cert=" + cfString(cert->commonName())
234			+ "&hash=" + hash.toHex();
235	}
236	SecPointer<TrustedApplication> app = new TrustedApplication(description, req);
237	Required(appRef) = app->handle();
238
239	END_SECAPI
240}
241