]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrustSettings.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrustSettings.c
1 /*
2 * Copyright (c) 2007-2008,2010,2012-2015 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 * SecTrustSettings.c - Implement trust settings for certificates
26 */
27
28 #include "SecTrustSettings.h"
29 #include "SecTrustSettingsPriv.h"
30 #include <Security/SecCertificatePriv.h>
31 #include <AssertMacros.h>
32 #include <pthread.h>
33 #include <utilities/debugging.h>
34 #include "SecBasePriv.h"
35 #include <Security/SecInternal.h>
36 #include <CoreFoundation/CFRuntime.h>
37 #include <utilities/SecCFWrappers.h>
38
39 #define trustSettingsDbg(args...) secdebug("trustSettings", ## args)
40 #define trustSettingsEvalDbg(args...) secdebug("trustSettingsEval", ## args)
41
42 // MARK: -
43 // MARK: Static Functions
44
45 /* Return a CFDataRef representation of a (hex)string. */
46 static CFDataRef SecCopyDataFromHexString(CFStringRef string) {
47 CFMutableDataRef data;
48 CFIndex ix, length;
49 UInt8 *bytes;
50
51 length = string ? CFStringGetLength(string) : 0;
52 if (length & 1) {
53 secwarning("Odd length string: %@ returning NULL", string);
54 return NULL;
55 }
56
57 data = CFDataCreateMutable(kCFAllocatorDefault, length / 2);
58 CFDataSetLength(data, length / 2);
59 bytes = CFDataGetMutableBytePtr(data);
60
61 CFStringInlineBuffer buf;
62 CFRange range = { 0, length };
63 CFStringInitInlineBuffer(string, &buf, range);
64 UInt8 lastv = 0;
65 for (ix = 0; ix < length; ++ix) {
66 UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, ix);
67 UInt8 v;
68 if ('0' <= c && c <= '9')
69 v = c - '0';
70 else if ('A' <= c && c <= 'F')
71 v = c = 'A' + 10;
72 else if ('a' <= c && c <= 'a')
73 v = c = 'a' + 10;
74 else {
75 secwarning("Non hex string: %@ returning NULL", string);
76 CFRelease(data);
77 return NULL;
78 }
79 if (ix & 1) {
80 *bytes++ = (lastv << 4) + v;
81 } else {
82 lastv = v;
83 }
84 }
85
86 return data;
87 }
88
89 #if 0
90 /*
91 * Obtain a string representing a cert's SHA1 digest. This string is
92 * the key used to look up per-cert trust settings in a TrustSettings record.
93 */
94 static CFStringRef SecTrustSettingsCertHashStrFromCert(
95 SecCertificateRef certRef)
96 {
97 if (certRef == NULL) {
98 return NULL;
99 }
100
101 if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
102 /* use this string instead of the cert hash as the dictionary key */
103 secdebug("trustsettings","DefaultSetting");
104 return kSecTrustRecordDefaultRootCert;
105 }
106
107 CFDataRef digest = SecCertificateGetSHA1Digest(certRef);
108 return CFDataCopyHexString(digest);
109 }
110 #endif
111
112 // MARK: -
113 // MARK: SecTrustSettings
114 /********************************************************
115 ************** SecTrustSettings object *****************
116 ********************************************************/
117
118 struct __SecTrustSettings {
119 CFRuntimeBase _base;
120
121 /* the overall parsed TrustSettings - may be NULL if this is trimmed */
122 CFDictionaryRef _propList;
123
124 /* and the main thing we work with, the dictionary of per-cert trust settings */
125 CFMutableDictionaryRef _trustDict;
126
127 /* version number of mPropDict */
128 SInt32 _dictVersion;
129
130 SecTrustSettingsDomain _domain;
131 bool _dirty; /* we've changed _trustDict since creation */
132 };
133
134 static CFStringRef SecTrustSettingsCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
135 SecTrustSettingsRef ts = (SecTrustSettingsRef)cf;
136 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
137 CFSTR("<SecTrustSettings: %p>"), ts);
138 }
139
140 static void SecTrustSettingsDestroy(CFTypeRef cf) {
141 SecTrustSettingsRef ts = (SecTrustSettingsRef) cf;
142 CFReleaseSafe(ts->_propList);
143 CFReleaseSafe(ts->_trustDict);
144 }
145
146 /* SecTrustSettings API functions. */
147 CFGiblisFor(SecTrustSettings)
148
149 /* Make sure a presumed CFNumber can be converted to a 32-bit number */
150 static bool tsIsGoodCfNum(CFNumberRef cfn, SInt32 *num)
151 {
152 /* by convention */
153 if (cfn == NULL) {
154 *num = 0;
155 return true;
156 }
157 require(CFGetTypeID(cfn) == CFNumberGetTypeID(), errOut);
158 return CFNumberGetValue(cfn, kCFNumberSInt32Type, num);
159 errOut:
160 return false;
161 }
162
163 static bool validateUsageConstraint(const void *value) {
164 CFDictionaryRef ucDict = (CFDictionaryRef)value;
165 require(CFGetTypeID(ucDict) == CFDictionaryGetTypeID(), errOut);
166
167 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(ucDict,
168 kSecTrustSettingsPolicy);
169 require(certPolicy && CFGetTypeID(certPolicy) == CFDataGetTypeID(), errOut);
170
171 CFStringRef certApp = (CFStringRef)CFDictionaryGetValue(ucDict,
172 kSecTrustSettingsApplication);
173 require(certApp && CFGetTypeID(certApp) == CFStringGetTypeID(), errOut);
174
175 CFStringRef policyStr = (CFStringRef)CFDictionaryGetValue(ucDict,
176 kSecTrustSettingsPolicyString);
177 require(policyStr && CFGetTypeID(policyStr) == CFStringGetTypeID(), errOut);
178
179 SInt32 dummy;
180 CFNumberRef allowedError = (CFNumberRef)CFDictionaryGetValue(ucDict,
181 kSecTrustSettingsAllowedError);
182 require(tsIsGoodCfNum(allowedError, &dummy), errOut);
183
184 CFNumberRef trustSettingsResult = (CFNumberRef)CFDictionaryGetValue(ucDict,
185 kSecTrustSettingsResult);
186 require(tsIsGoodCfNum(trustSettingsResult, &dummy), errOut);
187
188 CFNumberRef keyUsage = (CFNumberRef)CFDictionaryGetValue(ucDict,
189 kSecTrustSettingsKeyUsage);
190 require(tsIsGoodCfNum(keyUsage, &dummy), errOut);
191
192 return true;
193 errOut:
194 return false;
195 }
196
197 static bool validateTrustSettingsArray(CFArrayRef usageConstraints) {
198 CFIndex ix, numConstraints = CFArrayGetCount(usageConstraints);
199 bool result = true;
200 for (ix = 0; ix < numConstraints; ++ix) {
201 if (!validateUsageConstraint(CFArrayGetValueAtIndex(usageConstraints, ix)))
202 result = false;
203 }
204 return result;
205 }
206
207 struct trustListContext {
208 CFMutableDictionaryRef dict;
209 SInt32 version;
210 bool trim;
211 OSStatus status;
212 };
213
214 static void trustListApplierFunction(const void *key, const void *value, void *context) {
215 CFStringRef digest = (CFStringRef)key;
216 CFDictionaryRef certDict = (CFDictionaryRef)value;
217 struct trustListContext *tlc = (struct trustListContext *)context;
218 CFDataRef newKey = NULL;
219 CFMutableDictionaryRef newDict = NULL;
220
221 /* Get the key. */
222 require(digest && CFGetTypeID(digest) == CFStringGetTypeID(), errOut);
223 /* Convert it to a CFDataRef. */
224 require(newKey = SecCopyDataFromHexString(digest), errOut);
225
226 /* get per-cert dictionary */
227 require(certDict && CFGetTypeID(certDict) == CFDictionaryGetTypeID(), errOut);
228
229 /* Create the to be inserted dictionary. */
230 require(newDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
231 tlc->trim ? 1 : 4, &kCFTypeDictionaryKeyCallBacks,
232 &kCFTypeDictionaryValueCallBacks), errOut);
233
234 /* The certDict dictionary should have exactly four entries.
235 If we're trimming, all we need is the actual trust settings. */
236
237 /* issuer */
238 CFDataRef issuer = (CFDataRef)CFDictionaryGetValue(certDict,
239 kTrustRecordIssuer);
240 require(issuer && CFGetTypeID(issuer) == CFDataGetTypeID(), errOut);
241
242 /* serial number */
243 CFDataRef serial = (CFDataRef)CFDictionaryGetValue(certDict,
244 kTrustRecordSerialNumber);
245 require(serial && CFGetTypeID(serial) == CFDataGetTypeID(), errOut);
246
247 /* modification date */
248 CFDateRef modDate = (CFDateRef)CFDictionaryGetValue(certDict,
249 kTrustRecordModDate);
250 require(modDate && CFGetTypeID(modDate) == CFDateGetTypeID(), errOut);
251
252 /* If we are not trimming we copy these extra values as well. */
253 if (!tlc->trim) {
254 CFDictionaryAddValue(newDict, kTrustRecordIssuer, issuer);
255 CFDictionaryAddValue(newDict, kTrustRecordSerialNumber, serial);
256 CFDictionaryAddValue(newDict, kTrustRecordModDate, modDate);
257 }
258
259 /* The actual trust settings */
260 CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict,
261 kTrustRecordTrustSettings);
262 /* optional; this cert's entry is good */
263 if(trustSettings) {
264 require(CFGetTypeID(trustSettings) == CFArrayGetTypeID(), errOut);
265
266 /* Now validate the usageConstraint array contents */
267 require(validateTrustSettingsArray(trustSettings), errOut);
268
269 /* Add the trustSettings to the dict. */
270 CFDictionaryAddValue(newDict, kTrustRecordTrustSettings, trustSettings);
271 }
272
273 CFDictionaryAddValue(tlc->dict, newKey, newDict);
274 CFRelease(newKey);
275 CFRelease(newDict);
276
277 return;
278 errOut:
279 CFReleaseSafe(newKey);
280 CFReleaseSafe(newDict);
281 tlc->status = errSecInvalidTrustSettings;
282 }
283
284 static OSStatus SecTrustSettingsValidate(SecTrustSettingsRef ts, bool trim) {
285 /* top level dictionary */
286 require(ts->_propList, errOut);
287 require(CFGetTypeID(ts->_propList) == CFDictionaryGetTypeID(), errOut);
288
289 /* That dictionary has two entries */
290 CFNumberRef cfVers = (CFNumberRef)CFDictionaryGetValue(ts->_propList, kTrustRecordVersion);
291 require(cfVers != NULL && CFGetTypeID(cfVers) == CFNumberGetTypeID(), errOut);
292 require(CFNumberGetValue(cfVers, kCFNumberSInt32Type, &ts->_dictVersion), errOut);
293 require((ts->_dictVersion <= kSecTrustRecordVersionCurrent) &&
294 (ts->_dictVersion != kSecTrustRecordVersionInvalid), errOut);
295
296 /* other backwards-compatibility handling done later, if needed, per _dictVersion */
297
298 require(ts->_trustDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
299 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
300
301 CFDictionaryRef trustList = (CFDictionaryRef)CFDictionaryGetValue(
302 ts->_propList, kTrustRecordTrustList);
303 require(trustList != NULL &&
304 CFGetTypeID(trustList) == CFDictionaryGetTypeID(), errOut);
305
306 /* Convert the per-cert entries from on disk to in memory format. */
307 struct trustListContext context = {
308 ts->_trustDict, ts->_dictVersion, trim, errSecSuccess
309 };
310 CFDictionaryApplyFunction(trustList, trustListApplierFunction, &context);
311
312 if (trim) {
313 /* we don't need the top-level dictionary any more */
314 CFRelease(ts->_propList);
315 ts->_propList = NULL;
316 }
317
318 return context.status;
319
320 errOut:
321 return errSecInvalidTrustSettings;
322 }
323
324 OSStatus SecTrustSettingsCreateFromExternal(SecTrustSettingsDomain domain,
325 CFDataRef external, SecTrustSettingsRef *ts) {
326 CFAllocatorRef allocator = kCFAllocatorDefault;
327 CFIndex size = sizeof(struct __SecTrustSettings);
328 SecTrustSettingsRef result;
329
330 require(result = (SecTrustSettingsRef)_CFRuntimeCreateInstance(allocator,
331 SecTrustSettingsGetTypeID(), size - sizeof(CFRuntimeBase), 0), errOut);
332
333 CFErrorRef error = NULL;
334 CFPropertyListRef plist = CFPropertyListCreateWithData(kCFAllocatorDefault,
335 external, kCFPropertyListImmutable, NULL, &error);
336 if (!plist) {
337 secwarning("SecTrustSettingsCreateFromExternal: %@", error);
338 CFReleaseSafe(error);
339 CFReleaseSafe(result);
340 goto errOut;
341 }
342
343 result->_propList = plist;
344 result->_trustDict = NULL;
345 SecTrustSettingsValidate(result, false);
346
347 *ts = result;
348
349 return errSecSuccess;
350
351 errOut:
352 return errSecInvalidTrustSettings;
353 }
354
355 SecTrustSettingsRef SecTrustSettingsCreate(SecTrustSettingsDomain domain,
356 bool create, bool trim) {
357 CFAllocatorRef allocator = kCFAllocatorDefault;
358 CFIndex size = sizeof(struct __SecTrustSettings);
359 SecTrustSettingsRef result =
360 (SecTrustSettingsRef)_CFRuntimeCreateInstance(allocator,
361 SecTrustSettingsGetTypeID(), size - sizeof(CFRuntimeBase), 0);
362 if (!result)
363 return NULL;
364
365 //result->_data = NULL;
366
367 return result;
368 }
369
370 CFDataRef SecTrustSettingsCopyExternal(SecTrustSettingsRef ts) {
371 /* Transform the internal represantation of the trustSettings to an
372 external form. */
373 // @@@ SecTrustSettingsUpdatePropertyList(SecTrustSettingsRef ts);
374 CFDataRef xmlData;
375 verify(xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
376 ts->_propList));
377 return xmlData;
378 }
379
380 void SecTrustSettingsSet(SecCertificateRef certRef,
381 CFTypeRef trustSettingsDictOrArray) {
382 }
383
384
385
386 // MARK: -
387 // MARK: SPI functions
388
389
390 /*
391 * Fundamental routine used by TP to ascertain status of one cert.
392 *
393 * Returns true in *foundMatchingEntry if a trust setting matching
394 * specific constraints was found for the cert. Returns true in
395 * *foundAnyEntry if any entry was found for the cert, even if it
396 * did not match the specified constraints. The TP uses this to
397 * optimize for the case where a cert is being evaluated for
398 * one type of usage, and then later for another type. If
399 * foundAnyEntry is false, the second evaluation need not occur.
400 *
401 * Returns the domain in which a setting was found in *foundDomain.
402 *
403 * Allowed errors applying to the specified cert evaluation
404 * are returned in a mallocd array in *allowedErrors and must
405 * be freed by caller.
406 *
407 * The design of the entire TrustSettings module is centered around
408 * optimizing the performance of this routine (security concerns
409 * aside, that is). It's why the per-cert dictionaries are stored
410 * as a dictionary, keyed off of the cert hash. It's why TrustSettings
411 * are cached in memory by tsGetGlobalTrustSettings(), and why those
412 * cached TrustSettings objects are 'trimmed' of dictionary fields
413 * which are not needed to verify a cert.
414 *
415 * The API functions which are used to manipulate Trust Settings
416 * are called infrequently and need not be particularly fast since
417 * they result in user interaction for authentication. Thus they do
418 * not use cached TrustSettings as this function does.
419 */
420 OSStatus SecTrustSettingsEvaluateCertificate(
421 SecCertificateRef certificate,
422 SecPolicyRef policy,
423 SecTrustSettingsKeyUsage keyUsage, /* optional */
424 bool isSelfSignedCert, /* for checking default setting */
425 /* RETURNED values */
426 SecTrustSettingsDomain *foundDomain,
427 CFArrayRef *allowedErrors, /* RETURNED */
428 SecTrustSettingsResult *resultType, /* RETURNED */
429 bool *foundMatchingEntry,/* RETURNED */
430 bool *foundAnyEntry) /* RETURNED */
431 {
432 #if 0
433 BEGIN_RCSAPI
434
435 StLock<Mutex> _(sutCacheLock());
436
437 TS_REQUIRED(certHashStr)
438 TS_REQUIRED(foundDomain)
439 TS_REQUIRED(allowedErrors)
440 TS_REQUIRED(numAllowedErrors)
441 TS_REQUIRED(resultType)
442 TS_REQUIRED(foundMatchingEntry)
443 TS_REQUIRED(foundMatchingEntry)
444
445 /* ensure a NULL_terminated string */
446 auto_array<char> polStr;
447 if(policyString != NULL) {
448 polStr.allocate(policyStringLen + 1);
449 memmove(polStr.get(), policyString, policyStringLen);
450 if(policyString[policyStringLen - 1] != '\0') {
451 (polStr.get())[policyStringLen] = '\0';
452 }
453 }
454
455 /* initial condition - this can grow if we inspect multiple TrustSettings */
456 *allowedErrors = NULL;
457 *numAllowedErrors = 0;
458
459 /*
460 * This loop relies on the ordering of the SecTrustSettingsDomain enum:
461 * search user first, then admin, then system.
462 */
463 assert(kSecTrustSettingsDomainAdmin == (kSecTrustSettingsDomainUser + 1));
464 assert(kSecTrustSettingsDomainSystem == (kSecTrustSettingsDomainAdmin + 1));
465 bool foundAny = false;
466 for(unsigned domain=kSecTrustSettingsDomainUser;
467 domain<=kSecTrustSettingsDomainSystem;
468 domain++) {
469 TrustSettings *ts = tsGetGlobalTrustSettings(domain);
470 if(ts == NULL) {
471 continue;
472 }
473
474 /* validate cert returns true if matching entry was found */
475 bool foundAnyHere = false;
476 bool found = ts->evaluateCert(certHashStr, policyOID,
477 polStr.get(), keyUsage, isRootCert,
478 allowedErrors, numAllowedErrors, resultType, &foundAnyHere);
479
480 if(found) {
481 /*
482 * Note this, even though we may overwrite it later if this
483 * is an Unspecified entry and we find a definitive entry
484 * later
485 */
486 *foundDomain = domain;
487 }
488 if(found && (*resultType != kSecTrustSettingsResultUnspecified)) {
489 trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain);
490 *foundAnyEntry = true;
491 *foundMatchingEntry = true;
492 return errSecSuccess;
493 }
494 foundAny |= foundAnyHere;
495 }
496 trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND");
497 *foundAnyEntry = foundAny;
498 *foundMatchingEntry = false;
499 return errSecSuccess;
500 END_RCSAPI
501 #endif
502 return errSecSuccess;
503 }
504
505 /*
506 * Add a cert's TrustSettings to a non-persistent TrustSettings record.
507 * No locking or cache flushing here; it's all local to the TrustSettings
508 * we construct here.
509 */
510 #if SECTRUST_OSX
511 // There is already a SecTrustSettingsSetTrustSettingsExternal API on OS X
512 // with different arguments, so give this one an _ios extension.
513 OSStatus SecTrustSettingsSetTrustSettingsExternal_ios(
514 #else
515 OSStatus SecTrustSettingsSetTrustSettingsExternal(
516 #endif
517 CFDataRef settingsIn, /* optional */
518 SecCertificateRef certRef, /* optional */
519 CFTypeRef trustSettingsDictOrArray, /* optional */
520 CFDataRef *settingsOut) /* RETURNED */
521 {
522 SecTrustSettingsRef ts = NULL;
523 OSStatus status;
524
525 require_noerr(status = SecTrustSettingsCreateFromExternal(
526 kSecTrustSettingsDomainMemory, settingsIn, &ts), errOut);
527 SecTrustSettingsSet(certRef, trustSettingsDictOrArray);
528 *settingsOut = SecTrustSettingsCopyExternal(ts);
529
530 errOut:
531 CFReleaseSafe(ts);
532 return status;
533 }