1/* 2 * Copyright (c) 2002-2004 Apple Computer, 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 */ 39typedef 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 51using 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 */ 57bool 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 */ 78bool 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 */ 104CFMutableArrayRef 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 CFIndex policyValue = kSecRevocationUseAnyAvailableMethod; //%%%FIXME 139 CFRelease(revPolicy); // all done with this policy reference 140 if (policyValue & kSecRevocationOCSPMethod) { 141 /* cook up a new Policy object */ 142 ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)); 143 CSSM_APPLE_TP_OCSP_OPT_FLAGS ocspFlags = CSSM_TP_ACTION_OCSP_SUFFICIENT; 144 CSSM_APPLE_TP_OCSP_OPTIONS opts; 145 memset(&opts, 0, sizeof(opts)); 146 opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; 147 opts.Flags = ocspFlags; 148 149 /* Policy manages its own copy of this data */ 150 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; 151 ocspPolicy->value() = optData; 152 153 /* Policies array retains the Policy object */ 154 CFArrayAppendValue(policies, ocspPolicy->handle(false)); 155 numAdded++; 156 } 157 if (policyValue & kSecRevocationCRLMethod) { 158 /* cook up a new Policy object */ 159 crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)); 160 CSSM_APPLE_TP_CRL_OPT_FLAGS crlFlags = 0; 161 CSSM_APPLE_TP_CRL_OPTIONS opts; 162 memset(&opts, 0, sizeof(opts)); 163 opts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; 164 opts.CrlFlags = crlFlags; 165 166 /* Policy manages its own copy of this data */ 167 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; 168 crlPolicy->value() = optData; 169 170 /* Policies array retains the Policy object */ 171 CFArrayAppendValue(policies, crlPolicy->handle(false)); 172 numAdded++; 173 } 174 return policies; 175} 176 177static SecRevocationPolicyStyle parseRevStyle(CFStringRef val) 178{ 179 if(CFEqual(val, kSecRevocationOff)) { 180 return kSecDisabled; 181 } 182 else if(CFEqual(val, kSecRevocationBestAttempt)) { 183 return kSecBestAttempt; 184 } 185 else if(CFEqual(val, kSecRevocationRequireIfPresent)) { 186 return kSecRequireIfPresentInCertificate; 187 } 188 else if(CFEqual(val, kSecRevocationRequireForAll)) { 189 return kSecRequireForAllCertificates; 190 } 191 else { 192 return kSecDisabled; 193 } 194} 195 196CFDictionaryRef Trust::defaultRevocationSettings() 197{ 198 /* 199 defaults read ~/Library/Preferences/com.apple.security.revocation 200 { 201 CRLStyle = BestAttempt; 202 CRLSufficientPerCert = 1; 203 OCSPStyle = BestAttempt; 204 OCSPSufficientPerCert = 1; 205 RevocationFirst = OCSP; 206 } 207 */ 208 const void *keys[] = { 209 kSecRevocationCrlStyle, 210 kSecRevocationCRLSufficientPerCert, 211 kSecRevocationOcspStyle, 212 kSecRevocationOCSPSufficientPerCert, 213 kSecRevocationWhichFirst 214 }; 215 const void *values[] = { 216 kSecRevocationBestAttempt, 217 kCFBooleanTrue, 218 kSecRevocationBestAttempt, 219 kCFBooleanTrue, 220 kSecRevocationOcspFirst 221 }; 222 223 return CFDictionaryCreate(kCFAllocatorDefault, keys, 224 values, sizeof(keys) / sizeof(*keys), 225 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 226} 227 228CFMutableArrayRef Trust::addPreferenceRevocationPolicies( 229 uint32 &numAdded, 230 Allocator &alloc) 231{ 232 numAdded = 0; 233 234 /* any per-user prefs? */ 235 Dictionary* pd = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_User, true); 236 if (pd) 237 { 238 if (!pd->dict()) { 239 delete pd; 240 pd = NULL; 241 } 242 } 243 244 if(pd == NULL) 245 { 246 pd = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_System, true); 247 if (!pd->dict()) { 248 delete pd; 249 pd = NULL; 250 } 251 } 252 253 if(pd == NULL) 254 { 255 CFDictionaryRef tempDict = defaultRevocationSettings(); 256 if (tempDict == NULL) 257 return NULL; 258 259 pd = new Dictionary(tempDict); 260 CFRelease(tempDict); 261 } 262 263 auto_ptr<Dictionary> prefsDict(pd); 264 265 bool doOcsp = false; 266 bool doCrl = false; 267 CFStringRef val; 268 SecRevocationPolicyStyle ocspStyle = kSecBestAttempt; 269 SecRevocationPolicyStyle crlStyle = kSecBestAttempt; 270 SecPointer<Policy> ocspPolicy; 271 SecPointer<Policy> crlPolicy; 272 273 /* Are any revocation policies enabled? */ 274 val = prefsDict->getStringValue(kSecRevocationOcspStyle); 275 if(val != NULL) { 276 ocspStyle = parseRevStyle(val); 277 if(ocspStyle != kSecDisabled) { 278 doOcsp = true; 279 } 280 } 281 val = prefsDict->getStringValue(kSecRevocationCrlStyle); 282 if(val != NULL) { 283 crlStyle = parseRevStyle(val); 284 if(crlStyle != kSecDisabled) { 285 doCrl = true; 286 } 287 } 288 if(!doCrl && !doOcsp) { 289 return NULL; 290 } 291 292 /* which policy first? */ 293 bool ocspFirst = true; // default if both present 294 if(doCrl && doOcsp) { 295 val = prefsDict->getStringValue(kSecRevocationWhichFirst); 296 if((val != NULL) && CFEqual(val, kSecRevocationCrlFirst)) { 297 ocspFirst = false; 298 } 299 } 300 301 /* Must have at least one caller-specified policy 302 * (if they didn't specify any, it's a no-op evaluation, and if they wanted 303 * revocation checking only, that policy would already be in mPolicies) */ 304 if (!mPolicies || !CFArrayGetCount(mPolicies)) 305 return NULL; 306 307 /* We're adding something to mPolicies, so make a copy we can work with */ 308 CFMutableArrayRef policies = CFArrayCreateMutableCopy(NULL, 0, mPolicies); 309 if(policies == NULL) { 310 throw std::bad_alloc(); 311 } 312 313 if(doOcsp) { 314 /* Cook up a new Policy object */ 315 ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)); 316 CSSM_APPLE_TP_OCSP_OPTIONS opts; 317 memset(&opts, 0, sizeof(opts)); 318 opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; 319 320 /* Now fill in the OCSP-related blanks */ 321 switch(ocspStyle) { 322 case kSecDisabled: 323 assert(0); 324 break; 325 case kSecBestAttempt: 326 /* default, nothing to set */ 327 break; 328 case kSecRequireIfPresentInCertificate: 329 opts.Flags |= CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT; 330 break; 331 case kSecRequireForAllCertificates: 332 opts.Flags |= CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT; 333 break; 334 } 335 336 if(prefsDict->getBoolValue(kSecRevocationOCSPSufficientPerCert)) { 337 opts.Flags |= CSSM_TP_ACTION_OCSP_SUFFICIENT; 338 } 339 340 val = prefsDict->getStringValue(kSecOCSPLocalResponder); 341 if(val != NULL) { 342 CFDataRef cfData = CFStringCreateExternalRepresentation(NULL, 343 val, kCFStringEncodingUTF8, 0); 344 CFIndex len = CFDataGetLength(cfData); 345 opts.LocalResponder = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA)); 346 opts.LocalResponder->Data = (uint8 *)alloc.malloc(len); 347 opts.LocalResponder->Length = len; 348 memmove(opts.LocalResponder->Data, CFDataGetBytePtr(cfData), len); 349 CFRelease(cfData); 350 } 351 352 /* Policy manages its own copy of this data */ 353 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; 354 ocspPolicy->value() = optData; 355 numAdded++; 356 } 357 358 if(doCrl) { 359 /* Cook up a new Policy object */ 360 crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)); 361 CSSM_APPLE_TP_CRL_OPTIONS opts; 362 memset(&opts, 0, sizeof(opts)); 363 opts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; 364 365 /* Now fill in the CRL-related blanks */ 366 opts.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET; // default true 367 switch(crlStyle) { 368 case kSecDisabled: 369 assert(0); 370 break; 371 case kSecBestAttempt: 372 /* default, nothing to set */ 373 break; 374 case kSecRequireIfPresentInCertificate: 375 opts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT; 376 break; 377 case kSecRequireForAllCertificates: 378 opts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_PER_CERT; 379 break; 380 } 381 if(prefsDict->getBoolValue(kSecRevocationCRLSufficientPerCert)) { 382 opts.CrlFlags |= CSSM_TP_ACTION_CRL_SUFFICIENT; 383 } 384 385 /* Policy manages its own copy of this data */ 386 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; 387 crlPolicy->value() = optData; 388 numAdded++; 389 } 390 391 /* append in order */ 392 if(doOcsp) { 393 if(doCrl) { 394 if(ocspFirst) { 395 /* these SecCFObject go away when the policies array does */ 396 CFArrayAppendValue(policies, ocspPolicy->handle(false)); 397 CFArrayAppendValue(policies, crlPolicy->handle(false)); 398 } 399 else { 400 CFArrayAppendValue(policies, crlPolicy->handle(false)); 401 CFArrayAppendValue(policies, ocspPolicy->handle(false)); 402 } 403 } 404 else { 405 CFArrayAppendValue(policies, ocspPolicy->handle(false)); 406 } 407 408 } 409 else { 410 assert(doCrl); 411 CFArrayAppendValue(policies, crlPolicy->handle(false)); 412 } 413 return policies; 414} 415 416/* 417 * Called when we created the last numAdded Policies in the specified Policy array 418 * (only frees the policy data associated with the extra policies that we inserted; 419 * this does not free the policies array itself.) 420 */ 421void Trust::freeAddedRevocationPolicyData( 422 CFArrayRef policies, 423 uint32 numAdded, 424 Allocator &alloc) 425{ 426 uint32 numPolicies = (uint32)CFArrayGetCount(policies); 427 if(numPolicies < numAdded) { 428 /* should never happen - throw? */ 429 assert(0); 430 return; 431 } 432 for(unsigned dex=numPolicies-numAdded; dex<numPolicies; dex++) { 433 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex); 434 //SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol)); 435 Policy *pol = Policy::required(secPol); 436 const CssmOid &oid = pol->oid(); // required 437 const CssmData &optData = pol->value(); // optional 438 439 if(optData.Data) { 440 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) { 441 /* currently no CRL-specific policy data */ 442 } 443 else if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) { 444 CSSM_APPLE_TP_OCSP_OPTIONS *opts = (CSSM_APPLE_TP_OCSP_OPTIONS *)optData.Data; 445 if(opts->LocalResponder != NULL) { 446 if(opts->LocalResponder->Data != NULL) { 447 alloc.free(opts->LocalResponder->Data); 448 } 449 alloc.free(opts->LocalResponder); 450 } 451 } 452 // managed by Policy alloc.free(optData.Data); 453 } 454 } 455} 456 457/* 458 * Comparator function to correctly order revocation policies. 459 */ 460static CFComparisonResult compareRevocationPolicies( 461 const void *policy1, 462 const void *policy2, 463 void *context) 464{ 465 SecPointer<Policy> pol1 = Policy::required(SecPolicyRef(policy1)); 466 SecPointer<Policy> pol2 = Policy::required(SecPolicyRef(policy2)); 467 const CssmOid &oid1 = pol1->oid(); 468 const CssmOid &oid2 = pol2->oid(); 469 if(oid1 == oid2) { 470 return kCFCompareEqualTo; 471 } 472 bool ocspFirst = true; 473 if(context != NULL && CFEqual((CFBooleanRef)context, kCFBooleanFalse)) { 474 ocspFirst = false; 475 } 476 const CssmOid lastRevocationOid = (ocspFirst) ? 477 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL) : 478 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP); 479 const CssmOid firstRevocationOid = (ocspFirst) ? 480 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP) : 481 CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL); 482 if(oid1 == lastRevocationOid) { 483 /* should be ordered last, after all other policies */ 484 return kCFCompareGreaterThan; 485 } 486 if(oid1 == firstRevocationOid) { 487 /* should be ordered after any policy except lastRevocationOid */ 488 if(oid2 == lastRevocationOid) { 489 return kCFCompareLessThan; 490 } 491 return kCFCompareGreaterThan; 492 } 493 /* normal policy in first position, anything else in second position */ 494 return kCFCompareLessThan; 495} 496 497/* 498 * This method reorders any revocation policies which may be present 499 * in the provided array so they are at the end and evaluated last. 500 */ 501void Trust::orderRevocationPolicies( 502 CFMutableArrayRef policies) 503{ 504 if(!policies || CFGetTypeID(policies) != CFArrayGetTypeID()) { 505 return; 506 } 507 /* check revocation prefs to determine which policy goes first */ 508 CFBooleanRef ocspFirst = kCFBooleanTrue; 509 Dictionary* pd = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_User, true); 510 if (pd) { 511 if (!pd->dict()) { 512 delete pd; 513 } else { 514 auto_ptr<Dictionary> prefsDict(pd); 515 CFStringRef val = prefsDict->getStringValue(kSecRevocationWhichFirst); 516 if((val != NULL) && CFEqual(val, kSecRevocationCrlFirst)) { 517 ocspFirst = kCFBooleanFalse; 518 } 519 } 520 } 521#if POLICIES_DEBUG 522 CFShow(policies); // before sort 523 CFArraySortValues(policies, CFRangeMake(0, CFArrayGetCount(policies)), compareRevocationPolicies, (void*)ocspFirst); 524 CFShow(policies); // after sort, to see what changed 525 // check that policy order is what we expect 526 CFIndex numPolicies = CFArrayGetCount(policies); 527 for(CFIndex dex=0; dex<numPolicies; dex++) { 528 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex); 529 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol)); 530 const CssmOid &oid = pol->oid(); 531 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) { 532 CFStringRef s = CFStringCreateWithFormat(NULL, NULL, CFSTR("idx %d = OCSP"), dex); 533 CFShow(s); 534 CFRelease(s); 535 } 536 else if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) { 537 CFStringRef s = CFStringCreateWithFormat(NULL, NULL, CFSTR("idx %d = CRL"), dex); 538 CFShow(s); 539 CFRelease(s); 540 } 541 else { 542 CFStringRef s = CFStringCreateWithFormat(NULL, NULL, CFSTR("idx %d = normal"), dex); 543 CFShow(s); 544 CFRelease(s); 545 } 546 } 547#else 548 CFArraySortValues(policies, CFRangeMake(0, CFArrayGetCount(policies)), compareRevocationPolicies, (void*)ocspFirst); 549#endif 550} 551 552/* 553 * This method returns a copy of the mPolicies array which ensures that 554 * revocation checking (preferably OCSP, otherwise CRL) will be attempted. 555 * 556 * If OCSP is already in the mPolicies array, this makes sure the 557 * CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT and CSSM_TP_ACTION_OCSP_SUFFICIENT 558 * flags are set. If it's not already in the array, a new policy object is added. 559 * 560 * If CRL is already in the mPolicies array, this makes sure the 561 * CSSM_TP_ACTION_FETCH_CRL_FROM_NET and CSSM_TP_ACTION_CRL_SUFFICIENT flags are 562 * set. If it's not already in the array, a new policy object is added. 563 * 564 * Caller is responsible for releasing the returned policies array. 565 */ 566CFMutableArrayRef Trust::forceRevocationPolicies( 567 uint32 &numAdded, 568 Allocator &alloc, 569 bool requirePerCert) 570{ 571 SecPointer<Policy> ocspPolicy; 572 SecPointer<Policy> crlPolicy; 573 CSSM_APPLE_TP_OCSP_OPT_FLAGS ocspFlags; 574 CSSM_APPLE_TP_CRL_OPT_FLAGS crlFlags; 575 bool hasOcspPolicy = false; 576 bool hasCrlPolicy = false; 577 numAdded = 0; 578 579 ocspFlags = CSSM_TP_ACTION_OCSP_SUFFICIENT; 580 crlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET | CSSM_TP_ACTION_CRL_SUFFICIENT; 581 if (requirePerCert) { 582 ocspFlags |= CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT; 583 crlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT; 584 } 585 586 CFIndex numPolicies = (mPolicies) ? CFArrayGetCount(mPolicies) : 0; 587 for(CFIndex dex=0; dex<numPolicies; dex++) { 588 SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(mPolicies, dex); 589 SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol)); 590 const CssmOid &oid = pol->oid(); 591 const CssmData &optData = pol->value(); 592 if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) { 593 // make sure OCSP options are set correctly 594 CSSM_APPLE_TP_OCSP_OPTIONS *opts = (CSSM_APPLE_TP_OCSP_OPTIONS *)optData.Data; 595 if (opts) { 596 opts->Flags |= ocspFlags; 597 } else { 598 CSSM_APPLE_TP_OCSP_OPTIONS newOpts; 599 memset(&newOpts, 0, sizeof(newOpts)); 600 newOpts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; 601 newOpts.Flags = ocspFlags; 602 CSSM_DATA optData = {sizeof(newOpts), (uint8 *)&newOpts}; 603 pol->value() = optData; 604 } 605 hasOcspPolicy = true; 606 } 607 else if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) { 608 // make sure CRL options are set correctly 609 CSSM_APPLE_TP_CRL_OPTIONS *opts = (CSSM_APPLE_TP_CRL_OPTIONS *)optData.Data; 610 if (opts) { 611 opts->CrlFlags |= crlFlags; 612 } else { 613 CSSM_APPLE_TP_CRL_OPTIONS newOpts; 614 memset(&newOpts, 0, sizeof(newOpts)); 615 newOpts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; 616 newOpts.CrlFlags = crlFlags; 617 CSSM_DATA optData = {sizeof(newOpts), (uint8 *)&newOpts}; 618 pol->value() = optData; 619 } 620 hasCrlPolicy = true; 621 } 622 } 623 624 /* We're potentially adding something to mPolicies, so make a copy we can work with */ 625 CFMutableArrayRef policies = CFArrayCreateMutableCopy(NULL, 0, mPolicies); 626 if(policies == NULL) { 627 throw std::bad_alloc(); 628 } 629 630 if(!hasOcspPolicy) { 631 /* Cook up a new Policy object */ 632 ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)); 633 CSSM_APPLE_TP_OCSP_OPTIONS opts; 634 memset(&opts, 0, sizeof(opts)); 635 opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; 636 opts.Flags = ocspFlags; 637 638 /* Check prefs dict for local responder info */ 639 Dictionary *prefsDict = NULL; 640 try { /* per-user prefs */ 641 prefsDict = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_User, true); 642 if (!prefsDict->dict()) { 643 delete prefsDict; 644 prefsDict = NULL; 645 } 646 } 647 catch(...) {} 648 if(prefsDict == NULL) { 649 try { /* system prefs */ 650 prefsDict = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_System, true); 651 if (!prefsDict->dict()) { 652 delete prefsDict; 653 prefsDict = NULL; 654 } 655 } 656 catch(...) {} 657 } 658 if(prefsDict != NULL) { 659 CFStringRef val = prefsDict->getStringValue(kSecOCSPLocalResponder); 660 if(val != NULL) { 661 CFDataRef cfData = CFStringCreateExternalRepresentation(NULL, 662 val, kCFStringEncodingUTF8, 0); 663 CFIndex len = CFDataGetLength(cfData); 664 opts.LocalResponder = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA)); 665 opts.LocalResponder->Data = (uint8 *)alloc.malloc(len); 666 opts.LocalResponder->Length = len; 667 memmove(opts.LocalResponder->Data, CFDataGetBytePtr(cfData), len); 668 CFRelease(cfData); 669 } 670 } 671 672 /* Policy manages its own copy of the options data */ 673 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; 674 ocspPolicy->value() = optData; 675 676 /* Policies array retains the Policy object */ 677 CFArrayAppendValue(policies, ocspPolicy->handle(false)); 678 numAdded++; 679 680 if(prefsDict != NULL) 681 delete prefsDict; 682 } 683 684 if(!hasCrlPolicy) { 685 /* Cook up a new Policy object */ 686 crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)); 687 CSSM_APPLE_TP_CRL_OPTIONS opts; 688 memset(&opts, 0, sizeof(opts)); 689 opts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; 690 opts.CrlFlags = crlFlags; 691 692 /* Policy manages its own copy of this data */ 693 CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; 694 crlPolicy->value() = optData; 695 696 /* Policies array retains the Policy object */ 697 CFArrayAppendValue(policies, crlPolicy->handle(false)); 698 numAdded++; 699 } 700 701 return policies; 702} 703