]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/Code.cpp
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / Code.cpp
1 /*
2 * Copyright (c) 2006-2007,2011,2013 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 // Code - SecCode API objects
26 //
27 #include "Code.h"
28 #include "StaticCode.h"
29 #include <Security/SecCodeHost.h>
30 #include "cskernel.h"
31 #include <security_utilities/cfmunge.h>
32 #include <security_utilities/debugging.h>
33 #include "SecInternalReleasePriv.h"
34
35 namespace Security {
36 namespace CodeSigning {
37
38
39 //
40 // Construction
41 //
42 SecCode::SecCode(SecCode *host)
43 : mHost(host), mIdentified(false)
44 {
45 CODESIGN_DYNAMIC_CREATE(this, host);
46 }
47
48
49 //
50 // Clean up a SecCode object
51 //
52 SecCode::~SecCode() throw()
53 try {
54 } catch (...) {
55 return;
56 }
57
58
59 //
60 // CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
61 // and falls back on comparing canonical paths if (both are) not.
62 //
63 bool SecCode::equal(SecCFObject &secOther)
64 {
65 SecCode *other = static_cast<SecCode *>(&secOther);
66 CFDataRef mine = this->cdHash();
67 CFDataRef his = other->cdHash();
68 if (mine || his)
69 return mine && his && CFEqual(mine, his);
70 else
71 return this->staticCode()->equal(*other->staticCode());
72 }
73
74 CFHashCode SecCode::hash()
75 {
76 if (CFDataRef h = this->cdHash())
77 return CFHash(h);
78 else
79 return this->staticCode()->hash();
80 }
81
82
83 //
84 // Yield the host Code
85 //
86 SecCode *SecCode::host() const
87 {
88 return mHost;
89 }
90
91
92 //
93 // Yield the static code. This is cached.
94 // The caller does not own the object returned; it lives (at least) as long
95 // as the SecCode it was derived from.
96 //
97 SecStaticCode *SecCode::staticCode()
98 {
99 if (!mIdentified) {
100 this->identify();
101 mIdentified = true;
102 }
103 assert(mStaticCode);
104 return mStaticCode;
105 }
106
107
108 //
109 // Yield the CodeDirectory hash as presented by our host.
110 // This usually is the same as the hash of staticCode().codeDirectory(), but might not
111 // if files are changing on disk while code is running.
112 //
113 CFDataRef SecCode::cdHash()
114 {
115 if (!mIdentified) {
116 this->identify();
117 mIdentified = true;
118 }
119 return mCDHash; // can be NULL (host has no dynamic identity for guest)
120 }
121
122
123 //
124 // Retrieve current dynamic status.
125 //
126 SecCodeStatus SecCode::status()
127 {
128 if (this->isRoot())
129 return kSecCodeStatusValid; // root of trust, presumed valid
130 else
131 return this->host()->getGuestStatus(this);
132 }
133
134 void SecCode::status(SecCodeStatusOperation operation, CFDictionaryRef arguments)
135 {
136 if (this->isRoot())
137 MacOSError::throwMe(errSecCSHostProtocolStateError);
138 else
139 this->host()->changeGuestStatus(this, operation, arguments);
140 }
141
142
143 //
144 // By default, we have no guests
145 //
146 SecCode *SecCode::locateGuest(CFDictionaryRef)
147 {
148 return NULL;
149 }
150
151
152 //
153 // By default, we self-identify by asking our host to identify us.
154 // (This is currently only overridden in the root-of-trust (kernel) implementation.)
155 //
156 void SecCode::identify()
157 {
158 mStaticCode.take(host()->identifyGuest(this, &mCDHash.aref()));
159 }
160
161
162 //
163 // The default implementation cannot map guests to disk
164 //
165 SecStaticCode *SecCode::identifyGuest(SecCode *, CFDataRef *)
166 {
167 MacOSError::throwMe(errSecCSNoSuchCode);
168 }
169
170
171 //
172 // Master validation function.
173 //
174 // This is the most important function in all of Code Signing. It performs
175 // dynamic validation on running code. Despite its simple structure, it does
176 // everything that's needed to establish whether a Code is currently valid...
177 // with a little help from StaticCode, format drivers, type drivers, and so on.
178 //
179 // This function validates internal requirements in the hosting chain. It does
180 // not validate external requirements - the caller needs to do that with a separate call.
181 //
182 void SecCode::checkValidity(SecCSFlags flags)
183 {
184 if (this->isRoot()) {
185 // the root-of-trust is valid by definition
186 CODESIGN_EVAL_DYNAMIC_ROOT(this);
187 return;
188 }
189 DTRACK(CODESIGN_EVAL_DYNAMIC, this, (char*)this->staticCode()->mainExecutablePath().c_str());
190
191 //
192 // Do not reorder the operations below without thorough cogitation. There are
193 // interesting dependencies and significant performance issues. There is also
194 // client code that relies on errors being noticed in a particular order.
195 //
196 // For the most part, failure of (reliable) identity will cause exceptions to be
197 // thrown, and success is indicated by survival. If you make it to the end,
198 // you have won the validity race. (Good rat.)
199 //
200
201 // check my host first, recursively
202 this->host()->checkValidity(flags);
203
204 SecStaticCode *myDisk = this->staticCode();
205 myDisk->setValidationFlags(flags);
206 SecStaticCode *hostDisk = this->host()->staticCode();
207
208 // check my static state
209 myDisk->validateNonResourceComponents(); // also validates the CodeDirectory
210 if (flags & kSecCSStrictValidate)
211 myDisk->diskRep()->strictValidate(myDisk->codeDirectory(), DiskRep::ToleratedErrors(), flags);
212
213 // check my own dynamic state
214 SecCodeStatus dynamic_status = this->host()->getGuestStatus(this);
215 bool isValid = (dynamic_status & kSecCodeStatusValid) != 0;
216 if (!isValid) {
217 bool isDebugged = (dynamic_status & kSecCodeStatusDebugged) != 0;
218 bool isPlatform = (dynamic_status & kSecCodeStatusPlatform) != 0;
219 bool isInternal = SecIsInternalRelease();
220
221 if (!isDebugged || (isPlatform && !isInternal)) {
222 // fatal if the code is invalid and not being debugged, but
223 // never let platform code be debugged except on internal systems.
224 MacOSError::throwMe(errSecCSGuestInvalid);
225 }
226 }
227
228 // check that static and dynamic views are consistent
229 if (this->cdHash() && !CFEqual(this->cdHash(), myDisk->cdHash()))
230 MacOSError::throwMe(errSecCSStaticCodeChanged);
231
232 // check host/guest constraints
233 if (!this->host()->isRoot()) { // not hosted by root of trust
234 myDisk->validateRequirements(kSecHostRequirementType, hostDisk, errSecCSHostReject);
235 hostDisk->validateRequirements(kSecGuestRequirementType, myDisk);
236 }
237 }
238
239
240 //
241 // By default, we track no validity for guests (we don't have any)
242 //
243 uint32_t SecCode::getGuestStatus(SecCode *guest)
244 {
245 MacOSError::throwMe(errSecCSNoSuchCode);
246 }
247
248 void SecCode::changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
249 {
250 MacOSError::throwMe(errSecCSNoSuchCode);
251 }
252
253
254 //
255 // Given a bag of attribute values, automagically come up with a SecCode
256 // without any other information.
257 // This is meant to be the "just do what makes sense" generic call, for callers
258 // who don't want to engage in the fascinating dance of manual guest enumeration.
259 //
260 // Note that we expect the logic embedded here to change over time (in backward
261 // compatible fashion, one hopes), and that it's all right to use heuristics here
262 // as long as it's done sensibly.
263 //
264 // Be warned that the present logic is quite a bit ad-hoc, and will likely not
265 // handle arbitrary combinations of proxy hosting, dynamic hosting, and dedicated
266 // hosting all that well.
267 //
268 SecCode *SecCode::autoLocateGuest(CFDictionaryRef attributes, SecCSFlags flags)
269 {
270 #if TARGET_OS_OSX
271 // special case: with no attributes at all, return the root of trust
272 if (CFDictionaryGetCount(attributes) == 0)
273 return KernelCode::active()->retain();
274
275 // main logic: we need a pid or audit trailer; everything else goes to the guests
276 if (CFDictionaryGetValue(attributes, kSecGuestAttributePid) == NULL
277 && CFDictionaryGetValue(attributes, kSecGuestAttributeAudit) == NULL)
278 CSError::throwMe(errSecCSUnsupportedGuestAttributes, kSecCFErrorGuestAttributes, attributes);
279 if (SecCode *process =
280 KernelCode::active()->locateGuest(attributes)) {
281 SecPointer<SecCode> code;
282 code.take(process); // locateGuest gave us a retained object
283 if (code->staticCode()->flag(kSecCodeSignatureHost)) {
284 // might be a code host. Let's find out
285 CFRef<CFMutableDictionaryRef> rest = makeCFMutableDictionary(attributes);
286 CFDictionaryRemoveValue(rest, kSecGuestAttributePid);
287 CFDictionaryRemoveValue(rest, kSecGuestAttributeAudit);
288 if (SecCode *guest = code->locateGuest(rest))
289 return guest;
290 }
291 if (!CFDictionaryGetValue(attributes, kSecGuestAttributeCanonical)) {
292 // only "soft" attributes, and no hosting is happening. Return the (non-)host itself
293 return code.yield();
294 }
295 }
296 #endif // TARGET_OS_OSX
297 MacOSError::throwMe(errSecCSNoSuchCode);
298 }
299
300
301 } // end namespace CodeSigning
302 } // end namespace Security