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 unique_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 }