]> git.saurik.com Git - apple/security.git/blame - securityd/src/codesigdb.cpp
Security-58286.200.222.tar.gz
[apple/security.git] / securityd / src / codesigdb.cpp
CommitLineData
d8f41ccd 1/*
fa7225c8
A
2 * Copyright (c) 2003-2009,2012,2016 Apple Inc. All Rights Reserved.
3 *
d8f41ccd 4 * @APPLE_LICENSE_HEADER_START@
fa7225c8 5 *
d8f41ccd
A
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.
fa7225c8 12 *
d8f41ccd
A
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.
fa7225c8 20 *
d8f41ccd
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// codesigdb - code-hash equivalence database
27//
28#include "codesigdb.h"
29#include "process.h"
30#include "server.h"
31#include "agentquery.h"
32#include <security_utilities/memutils.h>
33#include <security_utilities/logging.h>
34#include <Security/SecRequirementPriv.h>
35
36
d8f41ccd
A
37//
38// Construct a CodeSignatures objects
39//
5c19dc3a 40CodeSignatures::CodeSignatures()
d8f41ccd 41{
d8f41ccd
A
42}
43
44CodeSignatures::~CodeSignatures()
45{
46}
47
d8f41ccd
A
48//
49// (Re)open the equivalence database.
50// This is useful to switch to database in another volume.
51//
52void CodeSignatures::open(const char *path)
53{
d8f41ccd
A
54}
55
56
57//
58// Basic Identity objects
59//
60CodeSignatures::Identity::Identity() : mState(untried)
61{ }
62
63CodeSignatures::Identity::~Identity()
64{ }
65
d8f41ccd
A
66//
67// Verify signature matches.
68// This ends up getting called when a CodeSignatureAclSubject is validated.
69// The OSXVerifier describes what we require of the client code; the process represents
70// the requesting client; and the context gives us access to the ACL and its environment
fa7225c8 71// in case we want to, well, creatively rewrite it for some reason.
d8f41ccd
A
72//
73bool CodeSignatures::verify(Process &process,
74 const OSXVerifier &verifier, const AclValidationContext &context)
75{
fa7225c8 76 secinfo("codesign", "start verify");
d8f41ccd
A
77
78 StLock<Mutex> _(process);
d8f41ccd
A
79 if (SecRequirementRef requirement = verifier.requirement()) {
80 // If the ACL contains a code signature (requirement), we won't match against unsigned code at all.
81 // The legacy hash is ignored (it's for use by pre-Leopard systems).
fa7225c8 82 secinfo("codesign", "CS requirement present; ignoring legacy hashes");
d8f41ccd 83 Server::active().longTermActivity();
fa7225c8 84 switch (OSStatus rc = process.checkValidity(kSecCSDefaultFlags, requirement)) {
d8f41ccd 85 case noErr:
fa7225c8 86 secinfo("codesign", "CS verify passed");
d8f41ccd
A
87 return true;
88 case errSecCSUnsigned:
fa7225c8 89 secinfo("codesign", "CS verify against unsigned binary failed");
d8f41ccd
A
90 return false;
91 default:
fa7225c8 92 secinfo("codesign", "CS verify failed OSStatus=%d", int32_t(rc));
d8f41ccd
A
93 return false;
94 }
95 }
fa7225c8 96 switch (matchSignedClientToLegacyACL(process, verifier, context)) {
d8f41ccd
A
97 case noErr: // handled, allow access
98 return true;
5c19dc3a 99 case errSecCSUnsigned: { // unsigned client, complete legacy case
fa7225c8 100 secinfo("codesign", "no CS requirement - using legacy hash");
5c19dc3a 101
fa7225c8
A
102 /*
103 * We should stop supporting this case for binaries
5c19dc3a
A
104 * built for modern OS/SDK, user should ad-hoc sign
105 * their binaries in that case.
106 *
107 * <rdar://problem/20546287>
108 */
109 Identity &clientIdentity = process;
110 try {
111 if (clientIdentity.getHash() == CssmData::wrap(verifier.legacyHash(), SHA1::digestLength)) {
fa7225c8 112 secinfo("codesign", "direct match: pass");
5c19dc3a
A
113 return true;
114 }
115 } catch (...) {
fa7225c8 116 secinfo("codesign", "exception getting client code hash: fail");
5c19dc3a
A
117 return false;
118 }
119 return false;
120 }
d8f41ccd
A
121 default: // client unsuitable, reject this match
122 return false;
123 }
124}
125
d8f41ccd
A
126//
127// See if we can rewrite the ACL from legacy to Code Signing form without losing too much security.
128// Returns true if the present validation should succeed (we probably rewrote the ACL).
129// Returns false if the present validation shouldn't succeed based on what we did here (we may still
130// have rewritten the ACL, in principle).
131//
132// Note that these checks add nontrivial overhead to ACL processing. We want to eventually phase
133// this out, or at least make it an option that doesn't run all the time - perhaps an "extra legacy
134// effort" per-client mode bit.
135//
136static string trim(string s, char delimiter)
137{
138 string::size_type p = s.rfind(delimiter);
139 if (p != string::npos)
140 s = s.substr(p + 1);
141 return s;
142}
143
144static string trim(string s, char delimiter, string suffix)
145{
146 s = trim(s, delimiter);
fa7225c8 147 size_t preLength = s.length() - suffix.length();
d8f41ccd
A
148 if (preLength > 0 && s.substr(preLength) == suffix)
149 s = s.substr(0, preLength);
150 return s;
151}
152
153OSStatus CodeSignatures::matchSignedClientToLegacyACL(Process &process,
fa7225c8 154 const OSXVerifier &verifier, const AclValidationContext &context)
d8f41ccd
A
155{
156 //
157 // Check whether we seem to be matching a legacy .Mac ACL against a member of the .Mac group
158 //
159 if (SecurityServerAcl::looksLikeLegacyDotMac(context)) {
160 Server::active().longTermActivity();
161 CFRef<SecRequirementRef> dotmac;
162 MacOSError::check(SecRequirementCreateGroup(CFSTR("dot-mac"), NULL, kSecCSDefaultFlags, &dotmac.aref()));
fa7225c8
A
163 if (process.checkValidity(kSecCSDefaultFlags, dotmac) == noErr) {
164 secinfo("codesign", "client is a dot-mac application; update the ACL accordingly");
d8f41ccd
A
165
166 // create a suitable AclSubject (this is the above-the-API-line way)
167 CFRef<CFDataRef> reqdata;
168 MacOSError::check(SecRequirementCopyData(dotmac, kSecCSDefaultFlags, &reqdata.aref()));
169 RefPointer<CodeSignatureAclSubject> subject = new CodeSignatureAclSubject(NULL, "group://dot-mac");
170 subject->add((const BlobCore *)CFDataGetBytePtr(reqdata));
171
172 // add it to the ACL and pass the access check (we just quite literally did it above)
173 SecurityServerAcl::addToStandardACL(context, subject);
174 return noErr;
175 }
176 }
177
178 //
179 // Get best names for the ACL (legacy) subject and the (signed) client
180 //
181 CFRef<CFDictionaryRef> info;
fa7225c8 182 MacOSError::check(process.copySigningInfo(kSecCSSigningInformation, &info.aref()));
d8f41ccd
A
183 CFStringRef signingIdentity = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoIdentifier));
184 if (!signingIdentity) // unsigned
185 return errSecCSUnsigned;
186
187 string bundleName; // client
188 if (CFDictionaryRef infoList = CFDictionaryRef(CFDictionaryGetValue(info, kSecCodeInfoPList)))
189 if (CFStringRef name = CFStringRef(CFDictionaryGetValue(infoList, kCFBundleNameKey)))
190 bundleName = trim(cfString(name), '.');
191 if (bundleName.empty()) // fall back to signing identifier
192 bundleName = trim(cfString(signingIdentity), '.');
193
194 string aclName = trim(verifier.path(), '/', ".app"); // ACL
fa7225c8
A
195
196 secinfo("codesign", "matching signed client \"%s\" against legacy ACL \"%s\"",
d8f41ccd 197 bundleName.c_str(), aclName.c_str());
fa7225c8 198
d8f41ccd
A
199 //
200 // Check whether we're matching a signed APPLE application against a legacy ACL by the same name
201 //
202 if (bundleName == aclName) {
203 const unsigned char reqData[] = { // "anchor apple", version 1 blob, embedded here
204 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10,
205 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03
206 };
207 CFRef<SecRequirementRef> apple;
208 MacOSError::check(SecRequirementCreateWithData(CFTempData(reqData, sizeof(reqData)),
209 kSecCSDefaultFlags, &apple.aref()));
210 Server::active().longTermActivity();
fa7225c8 211 switch (OSStatus rc = process.checkValidity(kSecCSDefaultFlags, apple)) {
d8f41ccd
A
212 case noErr:
213 {
fa7225c8
A
214 secinfo("codesign", "withstands strict scrutiny; quietly adding new ACL");
215 RefPointer<AclSubject> subject = process.copyAclSubject();
d8f41ccd
A
216 SecurityServerAcl::addToStandardACL(context, subject);
217 return noErr;
218 }
219 default:
fa7225c8 220 secinfo("codesign", "validation fails with rc=%d, rejecting", int32_t(rc));
d8f41ccd
A
221 return rc;
222 }
d8f41ccd
A
223 }
224
225 // not close enough to even ask - this can't match
226 return errSecCSReqFailed;
227}