]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/csutilities.cpp
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / csutilities.cpp
1 /*
2 * Copyright (c) 2006-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 // csutilities - miscellaneous utilities for the code signing implementation
26 //
27
28 #include "csutilities.h"
29 #include <libDER/DER_Encode.h>
30 #include <libDER/DER_Keys.h>
31 #include <libDER/asn1Types.h>
32 #include <libDER/oids.h>
33 #include <security_asn1/SecAsn1Coder.h>
34 #include <security_asn1/SecAsn1Templates.h>
35 #include <Security/SecCertificatePriv.h>
36 #include <Security/SecCertificate.h>
37 #include <utilities/SecAppleAnchorPriv.h>
38 #include <utilities/SecInternalReleasePriv.h>
39 #include "requirement.h"
40 #include <security_utilities/hashing.h>
41 #include <security_utilities/debugging.h>
42 #include <security_utilities/errors.h>
43 #include <sys/utsname.h>
44
45 extern "C" {
46
47 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
48 an absoluteTime if the date was valid and properly decoded. Return
49 NULL_TIME otherwise. */
50 CFAbsoluteTime SecAbsoluteTimeFromDateContent(DERTag tag, const uint8_t *bytes,
51 size_t length);
52
53 }
54
55 namespace Security {
56 namespace CodeSigning {
57
58
59 //
60 // Test for the canonical Apple CA certificate
61 //
62 bool isAppleCA(SecCertificateRef cert)
63 {
64 SecAppleTrustAnchorFlags flags = 0;
65 if (SecIsInternalRelease())
66 flags |= kSecAppleTrustAnchorFlagsIncludeTestAnchors;
67 return SecIsAppleTrustAnchor(cert, flags);
68 }
69
70
71 //
72 // Calculate the canonical hash of a certificate, given its raw (DER) data.
73 //
74 void hashOfCertificate(const void *certData, size_t certLength, SHA1::Digest digest)
75 {
76 SHA1 hasher;
77 hasher(certData, certLength);
78 hasher.finish(digest);
79 }
80
81
82 //
83 // Ditto, given a SecCertificateRef
84 //
85 void hashOfCertificate(SecCertificateRef cert, SHA1::Digest digest)
86 {
87 assert(cert);
88 #if TARGET_OS_OSX
89 CSSM_DATA certData;
90 MacOSError::check(SecCertificateGetData(cert, &certData));
91 hashOfCertificate(certData.Data, certData.Length, digest);
92 #else
93 hashOfCertificate(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert), digest);
94 #endif
95 }
96
97
98 //
99 // One-stop hash-certificate-and-compare
100 //
101 bool verifyHash(SecCertificateRef cert, const Hashing::Byte *digest)
102 {
103 SHA1::Digest dig;
104 hashOfCertificate(cert, dig);
105 return !memcmp(dig, digest, SHA1::digestLength);
106 }
107
108 #if TARGET_OS_OSX
109 //
110 // Check to see if a certificate contains a particular field, by OID. This works for extensions,
111 // even ones not recognized by the local CL. It does not return any value, only presence.
112 //
113 bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid)
114 {
115 assert(cert);
116 CSSM_DATA *value;
117 switch (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &oid, &value)) {
118 case errSecSuccess:
119 MacOSError::check(SecCertificateReleaseFirstFieldValue(cert, &oid, value));
120 return true; // extension found by oid
121 case errSecUnknownTag:
122 break; // oid not recognized by CL - continue below
123 default:
124 MacOSError::throwMe(rc); // error: fail
125 }
126
127 // check the CL's bag of unrecognized extensions
128 CSSM_DATA **values;
129 bool found = false;
130 if (SecCertificateCopyFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, &values))
131 return false; // no unrecognized extensions - no match
132 if (values)
133 for (CSSM_DATA **p = values; *p; p++) {
134 const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)(*p)->Data;
135 if (oid == ext->extnId) {
136 found = true;
137 break;
138 }
139 }
140 MacOSError::check(SecCertificateReleaseFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, values));
141 return found;
142 }
143
144
145 //
146 // Retrieve X.509 policy extension OIDs, if any.
147 // This currently ignores policy qualifiers.
148 //
149 bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid)
150 {
151 bool matched = false;
152 assert(cert);
153 CSSM_DATA *data;
154 if (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_CertificatePolicies, &data))
155 MacOSError::throwMe(rc);
156 if (data && data->Data && data->Length == sizeof(CSSM_X509_EXTENSION)) {
157 const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)data->Data;
158 assert(ext->format == CSSM_X509_DATAFORMAT_PARSED);
159 const CE_CertPolicies *policies = (const CE_CertPolicies *)ext->value.parsedValue;
160 if (policies)
161 for (unsigned int n = 0; n < policies->numPolicies; n++) {
162 const CE_PolicyInformation &cp = policies->policies[n];
163 if (cp.certPolicyId == policyOid) {
164 matched = true;
165 break;
166 }
167 }
168 }
169 SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_PolicyConstraints, data);
170 return matched;
171 }
172
173
174 CFDateRef certificateCopyFieldDate(SecCertificateRef cert, const CSSM_OID &policyOid)
175 {
176 CFDataRef oidData = NULL;
177 CFDateRef value = NULL;
178 CFDataRef data = NULL;
179 SecAsn1CoderRef coder = NULL;
180 CSSM_DATA str = { 0 };
181 CFAbsoluteTime time = 0.0;
182 OSStatus status = 0;
183 bool isCritical;
184
185 oidData = CFDataCreateWithBytesNoCopy(NULL, policyOid.Data, policyOid.Length,
186 kCFAllocatorNull);
187
188 if (oidData == NULL) {
189 goto out;
190 }
191
192 data = SecCertificateCopyExtensionValue(cert, oidData, &isCritical);
193
194 if (data == NULL) {
195 goto out;
196 }
197
198 status = SecAsn1CoderCreate(&coder);
199 if (status != 0) {
200 goto out;
201 }
202
203 // We currently only support UTF8 strings.
204 status = SecAsn1Decode(coder, CFDataGetBytePtr(data), CFDataGetLength(data),
205 kSecAsn1UTF8StringTemplate, &str);
206 if (status != 0) {
207 goto out;
208 }
209
210 time = SecAbsoluteTimeFromDateContent(ASN1_GENERALIZED_TIME,
211 str.Data, str.Length);
212
213 if (time == 0.0) {
214 goto out;
215 }
216
217 value = CFDateCreate(NULL, time);
218 out:
219 if (coder) {
220 SecAsn1CoderRelease(coder);
221 }
222 if (data) {
223 CFRelease(data);
224 }
225 if (oidData) {
226 CFRelease(oidData);
227 }
228
229 return value;
230 }
231 #endif
232
233 //
234 // Copyfile
235 //
236 Copyfile::Copyfile()
237 {
238 if (!(mState = copyfile_state_alloc()))
239 UnixError::throwMe();
240 }
241
242 void Copyfile::set(uint32_t flag, const void *value)
243 {
244 check(::copyfile_state_set(mState, flag, value));
245 }
246
247 void Copyfile::get(uint32_t flag, void *value)
248 {
249 check(::copyfile_state_set(mState, flag, value));
250 }
251
252 void Copyfile::operator () (const char *src, const char *dst, copyfile_flags_t flags)
253 {
254 check(::copyfile(src, dst, mState, flags));
255 }
256
257 void Copyfile::check(int rc)
258 {
259 if (rc < 0)
260 UnixError::throwMe();
261 }
262
263
264 //
265 // MessageTracer support
266 //
267 MessageTrace::MessageTrace(const char *domain, const char *signature)
268 {
269 mAsl = asl_new(ASL_TYPE_MSG);
270 if (domain)
271 asl_set(mAsl, "com.apple.message.domain", domain);
272 if (signature)
273 asl_set(mAsl, "com.apple.message.signature", signature);
274 }
275
276 void MessageTrace::add(const char *key, const char *format, ...)
277 {
278 va_list args;
279 va_start(args, format);
280 char value[200];
281 vsnprintf(value, sizeof(value), format, args);
282 va_end(args);
283 asl_set(mAsl, (string("com.apple.message.") + key).c_str(), value);
284 }
285
286 void MessageTrace::send(const char *format, ...)
287 {
288 va_list args;
289 va_start(args, format);
290 asl_vlog(NULL, mAsl, ASL_LEVEL_NOTICE, format, args);
291 va_end(args);
292 }
293
294
295
296 // Resource limited async workers for doing work on nested bundles
297 LimitedAsync::LimitedAsync(bool async)
298 {
299 // validate multiple resources concurrently if bundle resides on solid-state media
300
301 // How many async workers to spin off. If zero, validating only happens synchronously.
302 long async_workers = 0;
303
304 long ncpu = sysconf(_SC_NPROCESSORS_ONLN);
305
306 if (async && ncpu > 0)
307 async_workers = ncpu - 1; // one less because this thread also validates
308
309 mResourceSemaphore = new Dispatch::Semaphore(async_workers);
310 }
311
312 LimitedAsync::LimitedAsync(LimitedAsync &limitedAsync)
313 {
314 mResourceSemaphore = new Dispatch::Semaphore(*limitedAsync.mResourceSemaphore);
315 }
316
317 LimitedAsync::~LimitedAsync()
318 {
319 delete mResourceSemaphore;
320 }
321
322 bool LimitedAsync::perform(Dispatch::Group &groupRef, void (^block)()) {
323 __block Dispatch::SemaphoreWait wait(*mResourceSemaphore, DISPATCH_TIME_NOW);
324
325 if (wait.acquired()) {
326 dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
327
328 groupRef.enqueue(defaultQueue, ^{
329 // Hold the semaphore count until the worker is done validating.
330 Dispatch::SemaphoreWait innerWait(wait);
331 block();
332 });
333 return true;
334 } else {
335 block();
336 return false;
337 }
338 }
339
340 } // end namespace CodeSigning
341 } // end namespace Security