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