]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/TrustRevocation.cpp
Security-58286.251.4.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / TrustRevocation.cpp
1 /*
2 * Copyright (c) 2002-2004,2011-2012,2014-2017 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 * TrustRevocation.cpp - private revocation policy manipulation
26 */
27
28 #include <security_keychain/Trust.h>
29 #include <security_utilities/cfutilities.h>
30 #include <security_utilities/simpleprefs.h>
31 #include <CoreFoundation/CFData.h>
32 #include "SecBridge.h"
33 #include <Security/cssmapplePriv.h>
34 #include <Security/oidsalg.h>
35
36 /*
37 * These may go into an SPI header for the SecTrust object.
38 */
39 typedef enum {
40 /* this revocation policy disabled */
41 kSecDisabled,
42 /* try, but tolerate inability to complete */
43 kSecBestAttempt,
44 /* require successful revocation check if certificate indicates
45 * the policy is supported */
46 kSecRequireIfPresentInCertificate,
47 /* require for every cert */
48 kSecRequireForAllCertificates
49 } SecRevocationPolicyStyle;
50
51 using namespace KeychainCore;
52
53 /*
54 * Given an app-specified array of Policies, determine if at least one of them
55 * matches the given policy OID.
56 */
57 bool Trust::policySpecified(CFArrayRef policies, const CSSM_OID &inOid)
58 {
59 if(policies == NULL) {
60 return false;
61 }
62 CFIndex numPolicies = CFArrayGetCount(policies);
63 for(CFIndex dex=0; dex<numPolicies; dex++) {
64 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex);
65 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol));
66 const CssmOid &oid = pol->oid();
67 if(oid == CssmOid::overlay(inOid)) {
68 return true;
69 }
70 }
71 return false;
72 }
73
74 /*
75 * Given an app-specified array of Policies, determine if at least one of them
76 * is an explicit revocation policy.
77 */
78 bool Trust::revocationPolicySpecified(CFArrayRef policies)
79 {
80 if(policies == NULL) {
81 return false;
82 }
83 CFIndex numPolicies = CFArrayGetCount(policies);
84 for(CFIndex dex=0; dex<numPolicies; dex++) {
85 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex);
86 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol));
87 const CssmOid &oid = pol->oid();
88 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) {
89 return true;
90 }
91 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 /*
99 * Replace a unified revocation policy instance in the mPolicies array
100 * with specific instances of the OCSP and/or CRL policies which the TP
101 * module understands. Returns a (possibly) modified copy of the mPolicies
102 * array, which the caller is responsible for releasing.
103 */
104 CFMutableArrayRef Trust::convertRevocationPolicy(
105 uint32 &numAdded,
106 Allocator &alloc)
107 {
108 numAdded = 0;
109 if (!mPolicies) {
110 return NULL;
111 }
112 CFIndex numPolicies = CFArrayGetCount(mPolicies);
113 CFAllocatorRef allocator = CFGetAllocator(mPolicies);
114 CFMutableArrayRef policies = CFArrayCreateMutableCopy(allocator, numPolicies, mPolicies);
115 SecPolicyRef revPolicy = NULL;
116 for(CFIndex dex=0; dex<numPolicies; dex++) {
117 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex);
118 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol));
119 const CssmOid &oid = pol->oid();
120 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION)) {
121 CFRetain(secPol);
122 if (revPolicy)
123 CFRelease(revPolicy);
124 revPolicy = secPol;
125 CFArrayRemoveValueAtIndex(policies, dex--);
126 numPolicies--;
127 }
128 }
129 if(!revPolicy) {
130 CFRelease(policies);
131 return NULL;
132 }
133
134 SecPointer<Policy> ocspPolicy;
135 SecPointer<Policy> crlPolicy;
136
137 // fetch policy value
138 CFOptionFlags policyFlags = kSecRevocationUseAnyAvailableMethod;
139 CSSM_DATA policyValue = { 0, NULL };
140 try {
141 policyValue = Policy::required(revPolicy)->value();
142 }
143 catch (...) {
144 policyValue.Data = NULL;
145 }
146 if (policyValue.Data) {
147 policyFlags = (CFOptionFlags) *((CFOptionFlags*)policyValue.Data);
148 }
149 if (mNetworkPolicy == useNetworkDisabled) {
150 policyFlags = 0 | kSecRevocationNetworkAccessDisabled;
151 }
152 CFRelease(revPolicy); // all done with this policy reference
153
154 if (policyFlags & kSecRevocationOCSPMethod) {
155 /* cook up a new Policy object */
156 ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP));
157 CSSM_APPLE_TP_OCSP_OPT_FLAGS ocspFlags = CSSM_TP_ACTION_OCSP_SUFFICIENT;
158 if (policyFlags & kSecRevocationRequirePositiveResponse) {
159 ocspFlags |= CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT;
160 }
161 CSSM_APPLE_TP_OCSP_OPTIONS opts;
162 memset(&opts, 0, sizeof(opts));
163 opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
164 opts.Flags = ocspFlags;
165
166 /* Policy manages its own copy of this data */
167 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts};
168 ocspPolicy->value() = optData;
169
170 /* Policies array retains the Policy object */
171 CFArrayAppendValue(policies, ocspPolicy->handle(false));
172 numAdded++;
173 }
174 if (policyFlags & kSecRevocationCRLMethod) {
175 /* cook up a new Policy object */
176 crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL));
177 CSSM_APPLE_TP_CRL_OPT_FLAGS crlFlags = 0;
178 if (policyFlags & kSecRevocationRequirePositiveResponse) {
179 crlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT;
180 }
181 CSSM_APPLE_TP_CRL_OPTIONS opts;
182 memset(&opts, 0, sizeof(opts));
183 opts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
184 opts.CrlFlags = crlFlags;
185
186 /* Policy manages its own copy of this data */
187 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts};
188 crlPolicy->value() = optData;
189
190 /* Policies array retains the Policy object */
191 CFArrayAppendValue(policies, crlPolicy->handle(false));
192 numAdded++;
193 }
194 return policies;
195 }
196
197 static SecRevocationPolicyStyle parseRevStyle(CFStringRef val)
198 {
199 if(CFEqual(val, kSecRevocationOff)) {
200 return kSecDisabled;
201 }
202 else if(CFEqual(val, kSecRevocationBestAttempt)) {
203 return kSecBestAttempt;
204 }
205 else if(CFEqual(val, kSecRevocationRequireIfPresent)) {
206 return kSecRequireIfPresentInCertificate;
207 }
208 else if(CFEqual(val, kSecRevocationRequireForAll)) {
209 return kSecRequireForAllCertificates;
210 }
211 else {
212 return kSecDisabled;
213 }
214 }
215
216 CFDictionaryRef Trust::defaultRevocationSettings()
217 {
218 /*
219 defaults read ~/Library/Preferences/com.apple.security.revocation
220 {
221 CRLStyle = BestAttempt;
222 CRLSufficientPerCert = 1;
223 OCSPStyle = BestAttempt;
224 OCSPSufficientPerCert = 1;
225 RevocationFirst = OCSP;
226 }
227 */
228 const void *keys[] = {
229 kSecRevocationCrlStyle,
230 kSecRevocationCRLSufficientPerCert,
231 kSecRevocationOcspStyle,
232 kSecRevocationOCSPSufficientPerCert,
233 kSecRevocationWhichFirst
234 };
235 const void *values[] = {
236 kSecRevocationBestAttempt,
237 kCFBooleanTrue,
238 kSecRevocationBestAttempt,
239 kCFBooleanTrue,
240 kSecRevocationOcspFirst
241 };
242
243 return CFDictionaryCreate(kCFAllocatorDefault, keys,
244 values, sizeof(keys) / sizeof(*keys),
245 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
246 }
247
248 CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
249 bool ocspEnabledOnBestAttempt,
250 bool crlEnabledOnBestAttempt,
251 uint32 &numAdded,
252 Allocator &alloc)
253 {
254 numAdded = 0;
255
256 Dictionary* pd = NULL;
257 CFDictionaryRef tempDict = defaultRevocationSettings();
258 if (tempDict == NULL) {
259 return NULL;
260 }
261 pd = new Dictionary(tempDict);
262 CFRelease(tempDict);
263
264 auto_ptr<Dictionary> prefsDict(pd);
265
266 bool doOcsp = false;
267 bool doCrl = false;
268 CFStringRef val;
269 SecRevocationPolicyStyle ocspStyle = kSecBestAttempt;
270 SecRevocationPolicyStyle crlStyle = kSecBestAttempt;
271 SecPointer<Policy> ocspPolicy;
272 SecPointer<Policy> crlPolicy;
273
274 /* Are any revocation policies enabled? */
275 val = prefsDict->getStringValue(kSecRevocationOcspStyle);
276 if(val != NULL) {
277 ocspStyle = parseRevStyle(val);
278 if(ocspStyle != kSecDisabled) {
279 doOcsp = true;
280 }
281 if(ocspStyle == kSecBestAttempt) {
282 doOcsp = ocspEnabledOnBestAttempt;
283 }
284 }
285 val = prefsDict->getStringValue(kSecRevocationCrlStyle);
286 if(val != NULL) {
287 crlStyle = parseRevStyle(val);
288 if(crlStyle != kSecDisabled) {
289 doCrl = true;
290 }
291 if(crlStyle == kSecBestAttempt) {
292 doCrl = crlEnabledOnBestAttempt;
293 }
294 }
295
296 if(!doCrl && !doOcsp) {
297 return NULL;
298 }
299
300 /* which policy first? */
301 bool ocspFirst = true; // default if both present
302 if(doCrl && doOcsp) {
303 val = prefsDict->getStringValue(kSecRevocationWhichFirst);
304 if((val != NULL) && CFEqual(val, kSecRevocationCrlFirst)) {
305 ocspFirst = false;
306 }
307 }
308
309 /* Must have at least one caller-specified policy
310 * (if they didn't specify any, it's a no-op evaluation, and if they wanted
311 * revocation checking only, that policy would already be in mPolicies) */
312 if (!mPolicies || !CFArrayGetCount(mPolicies))
313 return NULL;
314
315 /* We're adding something to mPolicies, so make a copy we can work with */
316 CFMutableArrayRef policies = CFArrayCreateMutableCopy(NULL, 0, mPolicies);
317 if(policies == NULL) {
318 throw std::bad_alloc();
319 }
320
321 if(doOcsp) {
322 /* Cook up a new Policy object */
323 ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP));
324 CSSM_APPLE_TP_OCSP_OPTIONS opts;
325 memset(&opts, 0, sizeof(opts));
326 opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
327
328 /* Now fill in the OCSP-related blanks */
329 switch(ocspStyle) {
330 case kSecDisabled:
331 assert(0);
332 break;
333 case kSecBestAttempt:
334 /* default, nothing to set */
335 break;
336 case kSecRequireIfPresentInCertificate:
337 opts.Flags |= CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT;
338 break;
339 case kSecRequireForAllCertificates:
340 opts.Flags |= CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT;
341 break;
342 }
343
344 if(prefsDict->getBoolValue(kSecRevocationOCSPSufficientPerCert)) {
345 opts.Flags |= CSSM_TP_ACTION_OCSP_SUFFICIENT;
346 }
347
348 val = prefsDict->getStringValue(kSecOCSPLocalResponder);
349 if(val != NULL) {
350 CFDataRef cfData = CFStringCreateExternalRepresentation(NULL,
351 val, kCFStringEncodingUTF8, 0);
352 CFIndex len = CFDataGetLength(cfData);
353 opts.LocalResponder = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA));
354 opts.LocalResponder->Data = (uint8 *)alloc.malloc(len);
355 opts.LocalResponder->Length = len;
356 memmove(opts.LocalResponder->Data, CFDataGetBytePtr(cfData), len);
357 CFRelease(cfData);
358 }
359
360 /* Policy manages its own copy of this data */
361 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts};
362 ocspPolicy->value() = optData;
363 numAdded++;
364 }
365
366 if(doCrl) {
367 /* Cook up a new Policy object */
368 crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL));
369 CSSM_APPLE_TP_CRL_OPTIONS opts;
370 memset(&opts, 0, sizeof(opts));
371 opts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
372
373 /* Now fill in the CRL-related blanks */
374 opts.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET; // default true
375 switch(crlStyle) {
376 case kSecDisabled:
377 assert(0);
378 break;
379 case kSecBestAttempt:
380 /* default, nothing to set */
381 break;
382 case kSecRequireIfPresentInCertificate:
383 opts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT;
384 break;
385 case kSecRequireForAllCertificates:
386 opts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_PER_CERT;
387 break;
388 }
389 if(prefsDict->getBoolValue(kSecRevocationCRLSufficientPerCert)) {
390 opts.CrlFlags |= CSSM_TP_ACTION_CRL_SUFFICIENT;
391 }
392
393 /* Policy manages its own copy of this data */
394 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts};
395 crlPolicy->value() = optData;
396 numAdded++;
397 }
398
399 /* append in order */
400 if(doOcsp) {
401 if(doCrl) {
402 if(ocspFirst) {
403 /* these SecCFObject go away when the policies array does */
404 CFArrayAppendValue(policies, ocspPolicy->handle(false));
405 CFArrayAppendValue(policies, crlPolicy->handle(false));
406 }
407 else {
408 CFArrayAppendValue(policies, crlPolicy->handle(false));
409 CFArrayAppendValue(policies, ocspPolicy->handle(false));
410 }
411 }
412 else {
413 CFArrayAppendValue(policies, ocspPolicy->handle(false));
414 }
415
416 }
417 else if(doCrl) {
418 CFArrayAppendValue(policies, crlPolicy->handle(false));
419 }
420 return policies;
421 }
422
423 /*
424 * Called when we created the last numAdded Policies in the specified Policy array
425 * (only frees the policy data associated with the extra policies that we inserted;
426 * this does not free the policies array itself.)
427 */
428 void Trust::freeAddedRevocationPolicyData(
429 CFArrayRef policies,
430 uint32 numAdded,
431 Allocator &alloc)
432 {
433 uint32 numPolicies = (uint32)CFArrayGetCount(policies);
434 if(numPolicies < numAdded) {
435 /* should never happen - throw? */
436 assert(0);
437 return;
438 }
439 for(unsigned dex=numPolicies-numAdded; dex<numPolicies; dex++) {
440 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex);
441 //SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol));
442 Policy *pol = Policy::required(secPol);
443 const CssmOid &oid = pol->oid(); // required
444 const CssmData &optData = pol->value(); // optional
445
446 if(optData.Data) {
447 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) {
448 /* currently no CRL-specific policy data */
449 }
450 else if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
451 CSSM_APPLE_TP_OCSP_OPTIONS *opts = (CSSM_APPLE_TP_OCSP_OPTIONS *)optData.Data;
452 if(opts->LocalResponder != NULL) {
453 if(opts->LocalResponder->Data != NULL) {
454 alloc.free(opts->LocalResponder->Data);
455 }
456 alloc.free(opts->LocalResponder);
457 }
458 }
459 // managed by Policy alloc.free(optData.Data);
460 }
461 }
462 }
463
464 /*
465 * Comparator function to correctly order revocation policies.
466 */
467 static CFComparisonResult compareRevocationPolicies(
468 const void *policy1,
469 const void *policy2,
470 void *context)
471 {
472 SecPointer<Policy> pol1 = Policy::required(SecPolicyRef(policy1));
473 SecPointer<Policy> pol2 = Policy::required(SecPolicyRef(policy2));
474 const CssmOid &oid1 = pol1->oid();
475 const CssmOid &oid2 = pol2->oid();
476 if(oid1 == oid2) {
477 return kCFCompareEqualTo;
478 }
479 bool ocspFirst = true;
480 if(context != NULL && CFEqual((CFBooleanRef)context, kCFBooleanFalse)) {
481 ocspFirst = false;
482 }
483 const CssmOid lastRevocationOid = (ocspFirst) ?
484 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL) :
485 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP);
486 const CssmOid firstRevocationOid = (ocspFirst) ?
487 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP) :
488 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL);
489 if(oid1 == lastRevocationOid) {
490 /* should be ordered last, after all other policies */
491 return kCFCompareGreaterThan;
492 }
493 if(oid1 == firstRevocationOid) {
494 /* should be ordered after any policy except lastRevocationOid */
495 if(oid2 == lastRevocationOid) {
496 return kCFCompareLessThan;
497 }
498 return kCFCompareGreaterThan;
499 }
500 /* normal policy in first position, anything else in second position */
501 return kCFCompareLessThan;
502 }
503
504 /*
505 * This method reorders any revocation policies which may be present
506 * in the provided array so they are at the end and evaluated last.
507 */
508 void Trust::orderRevocationPolicies(
509 CFMutableArrayRef policies)
510 {
511 if(!policies || CFGetTypeID(policies) != CFArrayGetTypeID()) {
512 return;
513 }
514 /* check revocation prefs to determine which policy goes first */
515 CFBooleanRef ocspFirst = kCFBooleanTrue;
516 #if POLICIES_DEBUG
517 CFShow(policies); // before sort
518 CFArraySortValues(policies, CFRangeMake(0, CFArrayGetCount(policies)), compareRevocationPolicies, (void*)ocspFirst);
519 CFShow(policies); // after sort, to see what changed
520 // check that policy order is what we expect
521 CFIndex numPolicies = CFArrayGetCount(policies);
522 for(CFIndex dex=0; dex<numPolicies; dex++) {
523 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex);
524 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol));
525 const CssmOid &oid = pol->oid();
526 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
527 CFStringRef s = CFStringCreateWithFormat(NULL, NULL, CFSTR("idx %d = OCSP"), dex);
528 CFShow(s);
529 CFRelease(s);
530 }
531 else if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) {
532 CFStringRef s = CFStringCreateWithFormat(NULL, NULL, CFSTR("idx %d = CRL"), dex);
533 CFShow(s);
534 CFRelease(s);
535 }
536 else {
537 CFStringRef s = CFStringCreateWithFormat(NULL, NULL, CFSTR("idx %d = normal"), dex);
538 CFShow(s);
539 CFRelease(s);
540 }
541 }
542 #else
543 CFArraySortValues(policies, CFRangeMake(0, CFArrayGetCount(policies)), compareRevocationPolicies, (void*)ocspFirst);
544 #endif
545 }
546
547 /*
548 * This method returns a copy of the mPolicies array which ensures that
549 * revocation checking (preferably OCSP, otherwise CRL) will be attempted.
550 *
551 * If OCSP is already in the mPolicies array, this makes sure the
552 * CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT and CSSM_TP_ACTION_OCSP_SUFFICIENT
553 * flags are set. If it's not already in the array, a new policy object is added.
554 *
555 * If CRL is already in the mPolicies array, this makes sure the
556 * CSSM_TP_ACTION_FETCH_CRL_FROM_NET and CSSM_TP_ACTION_CRL_SUFFICIENT flags are
557 * set. If it's not already in the array, a new policy object is added.
558 *
559 * Caller is responsible for releasing the returned policies array.
560 */
561 CFMutableArrayRef Trust::forceRevocationPolicies(
562 bool ocspEnabled,
563 bool crlEnabled,
564 uint32 &numAdded,
565 Allocator &alloc,
566 bool requirePerCert)
567 {
568 SecPointer<Policy> ocspPolicy;
569 SecPointer<Policy> crlPolicy;
570 CSSM_APPLE_TP_OCSP_OPT_FLAGS ocspFlags;
571 CSSM_APPLE_TP_CRL_OPT_FLAGS crlFlags;
572 bool hasOcspPolicy = false;
573 bool hasCrlPolicy = false;
574 numAdded = 0;
575
576 ocspFlags = CSSM_TP_ACTION_OCSP_SUFFICIENT;
577 crlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET | CSSM_TP_ACTION_CRL_SUFFICIENT;
578 if (requirePerCert) {
579 ocspFlags |= CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT;
580 crlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT;
581 }
582
583 CFIndex numPolicies = (mPolicies) ? CFArrayGetCount(mPolicies) : 0;
584 for(CFIndex dex=0; dex<numPolicies; dex++) {
585 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(mPolicies, dex);
586 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol));
587 const CssmOid &oid = pol->oid();
588 const CssmData &optData = pol->value();
589 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
590 // make sure OCSP options are set correctly
591 CSSM_APPLE_TP_OCSP_OPTIONS *opts = (CSSM_APPLE_TP_OCSP_OPTIONS *)optData.Data;
592 if (opts) {
593 opts->Flags |= ocspFlags;
594 } else {
595 CSSM_APPLE_TP_OCSP_OPTIONS newOpts;
596 memset(&newOpts, 0, sizeof(newOpts));
597 newOpts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
598 newOpts.Flags = ocspFlags;
599 CSSM_DATA optData = {sizeof(newOpts), (uint8 *)&newOpts};
600 pol->value() = optData;
601 }
602 hasOcspPolicy = true;
603 }
604 else if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) {
605 // make sure CRL options are set correctly
606 CSSM_APPLE_TP_CRL_OPTIONS *opts = (CSSM_APPLE_TP_CRL_OPTIONS *)optData.Data;
607 if (opts) {
608 opts->CrlFlags |= crlFlags;
609 } else {
610 CSSM_APPLE_TP_CRL_OPTIONS newOpts;
611 memset(&newOpts, 0, sizeof(newOpts));
612 newOpts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
613 newOpts.CrlFlags = crlFlags;
614 CSSM_DATA optData = {sizeof(newOpts), (uint8 *)&newOpts};
615 pol->value() = optData;
616 }
617 hasCrlPolicy = true;
618 }
619 }
620
621 /* We're potentially adding something to mPolicies, so make a copy we can work with */
622 CFMutableArrayRef policies = CFArrayCreateMutableCopy(NULL, 0, mPolicies);
623 if(policies == NULL) {
624 throw std::bad_alloc();
625 }
626
627 if(!hasOcspPolicy && ocspEnabled) {
628 /* Cook up a new Policy object */
629 ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP));
630 CSSM_APPLE_TP_OCSP_OPTIONS opts;
631 memset(&opts, 0, sizeof(opts));
632 opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
633 opts.Flags = ocspFlags;
634
635 /* Policy manages its own copy of the options data */
636 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts};
637 ocspPolicy->value() = optData;
638
639 /* Policies array retains the Policy object */
640 CFArrayAppendValue(policies, ocspPolicy->handle(false));
641 numAdded++;
642 }
643
644 if(!hasCrlPolicy && crlEnabled) {
645 /* Cook up a new Policy object */
646 crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL));
647 CSSM_APPLE_TP_CRL_OPTIONS opts;
648 memset(&opts, 0, sizeof(opts));
649 opts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
650 opts.CrlFlags = crlFlags;
651
652 /* Policy manages its own copy of this data */
653 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts};
654 crlPolicy->value() = optData;
655
656 /* Policies array retains the Policy object */
657 CFArrayAppendValue(policies, crlPolicy->handle(false));
658 numAdded++;
659 }
660
661 return policies;
662 }