2 * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // Code - SecCode API objects
28 #include "StaticCode.h"
29 #include <Security/SecCodeHost.h>
31 #include <security_utilities/cfmunge.h>
32 #include <security_utilities/debugging.h>
35 namespace CodeSigning
{
41 SecCode::SecCode(SecCode
*host
)
42 : mHost(host
), mIdentified(false)
44 CODESIGN_DYNAMIC_CREATE(this, host
);
49 // Clean up a SecCode object
51 SecCode::~SecCode() throw()
57 // CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
58 // and falls back on comparing canonical paths if (both are) not.
60 bool SecCode::equal(SecCFObject
&secOther
)
62 SecCode
*other
= static_cast<SecCode
*>(&secOther
);
63 CFDataRef mine
= this->cdHash();
64 CFDataRef his
= other
->cdHash();
66 return mine
&& his
&& CFEqual(mine
, his
);
68 return this->staticCode()->equal(*other
->staticCode());
71 CFHashCode
SecCode::hash()
73 if (CFDataRef h
= this->cdHash())
76 return this->staticCode()->hash();
81 // Yield the host Code
83 SecCode
*SecCode::host() const
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.
94 SecStaticCode
*SecCode::staticCode()
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.
110 CFDataRef
SecCode::cdHash()
116 return mCDHash
; // can be NULL (host has no dynamic identity for guest)
121 // Retrieve current dynamic status.
123 SecCodeStatus
SecCode::status()
126 return kSecCodeStatusValid
; // root of trust, presumed valid
128 return this->host()->getGuestStatus(this);
131 void SecCode::status(SecCodeStatusOperation operation
, CFDictionaryRef arguments
)
134 MacOSError::throwMe(errSecCSHostProtocolStateError
);
136 this->host()->changeGuestStatus(this, operation
, arguments
);
141 // By default, we have no guests
143 SecCode
*SecCode::locateGuest(CFDictionaryRef
)
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.)
153 void SecCode::identify()
155 mStaticCode
.take(host()->identifyGuest(this, &mCDHash
.aref()));
160 // The default implementation cannot map guests to disk
162 SecStaticCode
*SecCode::identifyGuest(SecCode
*, CFDataRef
*)
164 MacOSError::throwMe(errSecCSNoSuchCode
);
169 // Master validation function.
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.
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.
179 void SecCode::checkValidity(SecCSFlags flags
)
181 if (this->isRoot()) {
182 // the root-of-trust is valid by definition
183 CODESIGN_EVAL_DYNAMIC_ROOT();
186 DTRACK(CODESIGN_EVAL_DYNAMIC
, this, (char*)this->staticCode()->mainExecutablePath().c_str());
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.
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.)
198 // check my host first, recursively
199 this->host()->checkValidity(flags
);
201 SecStaticCode
*myDisk
= this->staticCode();
202 SecStaticCode
*hostDisk
= this->host()->staticCode();
204 // check my static state
205 myDisk
->validateDirectory();
207 // check my own dynamic state
208 if (!(this->host()->getGuestStatus(this) & kSecCodeStatusValid
))
209 MacOSError::throwMe(errSecCSGuestInvalid
);
211 // check that static and dynamic views are consistent
212 if (this->cdHash() && !CFEqual(this->cdHash(), myDisk
->cdHash()))
213 MacOSError::throwMe(errSecCSStaticCodeChanged
);
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
);
224 // By default, we track no validity for guests (we don't have any)
226 uint32_t SecCode::getGuestStatus(SecCode
*guest
)
228 MacOSError::throwMe(errSecCSNoSuchCode
);
231 void SecCode::changeGuestStatus(SecCode
*guest
, SecCodeStatusOperation operation
, CFDictionaryRef arguments
)
233 MacOSError::throwMe(errSecCSNoSuchCode
);
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.
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.
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.
251 SecCode
*SecCode::autoLocateGuest(CFDictionaryRef attributes
, SecCSFlags flags
)
253 // special case: with no attributes at all, return the root of trust
254 if (CFDictionaryGetCount(attributes
) == 0)
255 return KernelCode::active()->retain();
257 // main logic: we need a pid, and we'll take a canonical guest id as an option
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
))
272 if (!CFDictionaryGetValue(attributes
, kSecGuestAttributeCanonical
)) {
273 // only "soft" attributes, and no hosting is happening. Return the (non-)host itself
277 MacOSError::throwMe(errSecCSNoSuchCode
);
281 } // end namespace CodeSigning
282 } // end namespace Security