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