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