security/nss/lib/libpkix/pkix/top/pkix_build.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rwxr-xr-x

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 /*
michael@0 5 * pkix_build.c
michael@0 6 *
michael@0 7 * Top level buildChain function
michael@0 8 *
michael@0 9 */
michael@0 10
michael@0 11 /* #define PKIX_BUILDDEBUG 1 */
michael@0 12 /* #define PKIX_FORWARDBUILDERSTATEDEBUG 1 */
michael@0 13
michael@0 14 #include "pkix_build.h"
michael@0 15
michael@0 16 extern PRLogModuleInfo *pkixLog;
michael@0 17
michael@0 18 /*
michael@0 19 * List of critical extension OIDs associate with what build chain has
michael@0 20 * checked. Those OIDs need to be removed from the unresolved critical
michael@0 21 * extension OIDs list manually (instead of by checker automatically).
michael@0 22 */
michael@0 23 static SECOidTag buildCheckedCritExtOIDs[] = {
michael@0 24 PKIX_CERTKEYUSAGE_OID,
michael@0 25 PKIX_CERTSUBJALTNAME_OID,
michael@0 26 PKIX_BASICCONSTRAINTS_OID,
michael@0 27 PKIX_NAMECONSTRAINTS_OID,
michael@0 28 PKIX_EXTENDEDKEYUSAGE_OID,
michael@0 29 PKIX_NSCERTTYPE_OID,
michael@0 30 PKIX_UNKNOWN_OID
michael@0 31 };
michael@0 32
michael@0 33 /* --Private-ForwardBuilderState-Functions---------------------------------- */
michael@0 34
michael@0 35 /*
michael@0 36 * FUNCTION: pkix_ForwardBuilderState_Destroy
michael@0 37 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
michael@0 38 */
michael@0 39 static PKIX_Error *
michael@0 40 pkix_ForwardBuilderState_Destroy(
michael@0 41 PKIX_PL_Object *object,
michael@0 42 void *plContext)
michael@0 43 {
michael@0 44 PKIX_ForwardBuilderState *state = NULL;
michael@0 45
michael@0 46 PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_Destroy");
michael@0 47 PKIX_NULLCHECK_ONE(object);
michael@0 48
michael@0 49 PKIX_CHECK(pkix_CheckType
michael@0 50 (object, PKIX_FORWARDBUILDERSTATE_TYPE, plContext),
michael@0 51 PKIX_OBJECTNOTFORWARDBUILDERSTATE);
michael@0 52
michael@0 53 state = (PKIX_ForwardBuilderState *)object;
michael@0 54
michael@0 55 state->status = BUILD_INITIAL;
michael@0 56 state->traversedCACerts = 0;
michael@0 57 state->certStoreIndex = 0;
michael@0 58 state->numCerts = 0;
michael@0 59 state->numAias = 0;
michael@0 60 state->certIndex = 0;
michael@0 61 state->aiaIndex = 0;
michael@0 62 state->certCheckedIndex = 0;
michael@0 63 state->checkerIndex = 0;
michael@0 64 state->hintCertIndex = 0;
michael@0 65 state->numFanout = 0;
michael@0 66 state->numDepth = 0;
michael@0 67 state->reasonCode = 0;
michael@0 68 state->canBeCached = PKIX_FALSE;
michael@0 69 state->useOnlyLocal = PKIX_FALSE;
michael@0 70 state->revChecking = PKIX_FALSE;
michael@0 71 state->usingHintCerts = PKIX_FALSE;
michael@0 72 state->certLoopingDetected = PKIX_FALSE;
michael@0 73 PKIX_DECREF(state->validityDate);
michael@0 74 PKIX_DECREF(state->prevCert);
michael@0 75 PKIX_DECREF(state->candidateCert);
michael@0 76 PKIX_DECREF(state->traversedSubjNames);
michael@0 77 PKIX_DECREF(state->trustChain);
michael@0 78 PKIX_DECREF(state->aia);
michael@0 79 PKIX_DECREF(state->candidateCerts);
michael@0 80 PKIX_DECREF(state->reversedCertChain);
michael@0 81 PKIX_DECREF(state->checkedCritExtOIDs);
michael@0 82 PKIX_DECREF(state->checkerChain);
michael@0 83 PKIX_DECREF(state->certSel);
michael@0 84 PKIX_DECREF(state->verifyNode);
michael@0 85 PKIX_DECREF(state->client);
michael@0 86
michael@0 87 /*
michael@0 88 * If we ever add a child link we have to be careful not to have loops
michael@0 89 * in the Destroy process. But with one-way links we should be okay.
michael@0 90 */
michael@0 91 if (state->parentState == NULL) {
michael@0 92 state->buildConstants.numAnchors = 0;
michael@0 93 state->buildConstants.numCertStores = 0;
michael@0 94 state->buildConstants.numHintCerts = 0;
michael@0 95 state->buildConstants.procParams = 0;
michael@0 96 PKIX_DECREF(state->buildConstants.testDate);
michael@0 97 PKIX_DECREF(state->buildConstants.timeLimit);
michael@0 98 PKIX_DECREF(state->buildConstants.targetCert);
michael@0 99 PKIX_DECREF(state->buildConstants.targetPubKey);
michael@0 100 PKIX_DECREF(state->buildConstants.certStores);
michael@0 101 PKIX_DECREF(state->buildConstants.anchors);
michael@0 102 PKIX_DECREF(state->buildConstants.userCheckers);
michael@0 103 PKIX_DECREF(state->buildConstants.hintCerts);
michael@0 104 PKIX_DECREF(state->buildConstants.revChecker);
michael@0 105 PKIX_DECREF(state->buildConstants.aiaMgr);
michael@0 106 } else {
michael@0 107 PKIX_DECREF(state->parentState);
michael@0 108 }
michael@0 109
michael@0 110 cleanup:
michael@0 111
michael@0 112 PKIX_RETURN(FORWARDBUILDERSTATE);
michael@0 113 }
michael@0 114
michael@0 115 /*
michael@0 116 * FUNCTION: pkix_ForwardBuilderState_Create
michael@0 117 *
michael@0 118 * DESCRIPTION:
michael@0 119 * Allocate and initialize a ForwardBuilderState.
michael@0 120 *
michael@0 121 * PARAMETERS
michael@0 122 * "traversedCACerts"
michael@0 123 * Number of CA certificates traversed.
michael@0 124 * "numFanout"
michael@0 125 * Number of Certs that can be considered at this level (0 = no limit)
michael@0 126 * "numDepth"
michael@0 127 * Number of additional levels that can be searched (0 = no limit)
michael@0 128 * "canBeCached"
michael@0 129 * Boolean value indicating whether all certs on the chain can be cached.
michael@0 130 * "validityDate"
michael@0 131 * Address of Date at which build chain Certs' most restricted validity
michael@0 132 * time is kept. May be NULL.
michael@0 133 * "prevCert"
michael@0 134 * Address of Cert just traversed. Must be non-NULL.
michael@0 135 * "traversedSubjNames"
michael@0 136 * Address of List of GeneralNames that have been traversed.
michael@0 137 * Must be non-NULL.
michael@0 138 * "trustChain"
michael@0 139 * Address of List of certificates traversed. Must be non-NULL.
michael@0 140 * "parentState"
michael@0 141 * Address of previous ForwardBuilderState
michael@0 142 * "pState"
michael@0 143 * Address where ForwardBuilderState will be stored. Must be non-NULL.
michael@0 144 * "plContext"
michael@0 145 * Platform-specific context pointer.
michael@0 146 * THREAD SAFETY:
michael@0 147 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 148 * RETURNS:
michael@0 149 * Returns NULL if the function succeeds.
michael@0 150 * Returns a Build Error if the function fails in a non-fatal way.
michael@0 151 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 152 */
michael@0 153 static PKIX_Error *
michael@0 154 pkix_ForwardBuilderState_Create(
michael@0 155 PKIX_Int32 traversedCACerts,
michael@0 156 PKIX_UInt32 numFanout,
michael@0 157 PKIX_UInt32 numDepth,
michael@0 158 PKIX_Boolean canBeCached,
michael@0 159 PKIX_PL_Date *validityDate,
michael@0 160 PKIX_PL_Cert *prevCert,
michael@0 161 PKIX_List *traversedSubjNames,
michael@0 162 PKIX_List *trustChain,
michael@0 163 PKIX_ForwardBuilderState *parentState,
michael@0 164 PKIX_ForwardBuilderState **pState,
michael@0 165 void *plContext)
michael@0 166 {
michael@0 167 PKIX_ForwardBuilderState *state = NULL;
michael@0 168
michael@0 169 PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_Create");
michael@0 170 PKIX_NULLCHECK_FOUR(prevCert, traversedSubjNames, pState, trustChain);
michael@0 171
michael@0 172 PKIX_CHECK(PKIX_PL_Object_Alloc
michael@0 173 (PKIX_FORWARDBUILDERSTATE_TYPE,
michael@0 174 sizeof (PKIX_ForwardBuilderState),
michael@0 175 (PKIX_PL_Object **)&state,
michael@0 176 plContext),
michael@0 177 PKIX_COULDNOTCREATEFORWARDBUILDERSTATEOBJECT);
michael@0 178
michael@0 179 state->status = BUILD_INITIAL;
michael@0 180 state->traversedCACerts = traversedCACerts;
michael@0 181 state->certStoreIndex = 0;
michael@0 182 state->numCerts = 0;
michael@0 183 state->numAias = 0;
michael@0 184 state->certIndex = 0;
michael@0 185 state->aiaIndex = 0;
michael@0 186 state->certCheckedIndex = 0;
michael@0 187 state->checkerIndex = 0;
michael@0 188 state->hintCertIndex = 0;
michael@0 189 state->numFanout = numFanout;
michael@0 190 state->numDepth = numDepth;
michael@0 191 state->reasonCode = 0;
michael@0 192 state->revChecking = numDepth;
michael@0 193 state->canBeCached = canBeCached;
michael@0 194 state->useOnlyLocal = PKIX_TRUE;
michael@0 195 state->revChecking = PKIX_FALSE;
michael@0 196 state->usingHintCerts = PKIX_FALSE;
michael@0 197 state->certLoopingDetected = PKIX_FALSE;
michael@0 198
michael@0 199 PKIX_INCREF(validityDate);
michael@0 200 state->validityDate = validityDate;
michael@0 201
michael@0 202 PKIX_INCREF(prevCert);
michael@0 203 state->prevCert = prevCert;
michael@0 204
michael@0 205 state->candidateCert = NULL;
michael@0 206
michael@0 207 PKIX_INCREF(traversedSubjNames);
michael@0 208 state->traversedSubjNames = traversedSubjNames;
michael@0 209
michael@0 210 PKIX_INCREF(trustChain);
michael@0 211 state->trustChain = trustChain;
michael@0 212
michael@0 213 state->aia = NULL;
michael@0 214 state->candidateCerts = NULL;
michael@0 215 state->reversedCertChain = NULL;
michael@0 216 state->checkedCritExtOIDs = NULL;
michael@0 217 state->checkerChain = NULL;
michael@0 218 state->certSel = NULL;
michael@0 219 state->verifyNode = NULL;
michael@0 220 state->client = NULL;
michael@0 221
michael@0 222 PKIX_INCREF(parentState);
michael@0 223 state->parentState = parentState;
michael@0 224
michael@0 225 if (parentState != NULL) {
michael@0 226 state->buildConstants.numAnchors =
michael@0 227 parentState->buildConstants.numAnchors;
michael@0 228 state->buildConstants.numCertStores =
michael@0 229 parentState->buildConstants.numCertStores;
michael@0 230 state->buildConstants.numHintCerts =
michael@0 231 parentState->buildConstants.numHintCerts;
michael@0 232 state->buildConstants.maxFanout =
michael@0 233 parentState->buildConstants.maxFanout;
michael@0 234 state->buildConstants.maxDepth =
michael@0 235 parentState->buildConstants.maxDepth;
michael@0 236 state->buildConstants.maxTime =
michael@0 237 parentState->buildConstants.maxTime;
michael@0 238 state->buildConstants.procParams =
michael@0 239 parentState->buildConstants.procParams;
michael@0 240 state->buildConstants.testDate =
michael@0 241 parentState->buildConstants.testDate;
michael@0 242 state->buildConstants.timeLimit =
michael@0 243 parentState->buildConstants.timeLimit;
michael@0 244 state->buildConstants.targetCert =
michael@0 245 parentState->buildConstants.targetCert;
michael@0 246 state->buildConstants.targetPubKey =
michael@0 247 parentState->buildConstants.targetPubKey;
michael@0 248 state->buildConstants.certStores =
michael@0 249 parentState->buildConstants.certStores;
michael@0 250 state->buildConstants.anchors =
michael@0 251 parentState->buildConstants.anchors;
michael@0 252 state->buildConstants.userCheckers =
michael@0 253 parentState->buildConstants.userCheckers;
michael@0 254 state->buildConstants.hintCerts =
michael@0 255 parentState->buildConstants.hintCerts;
michael@0 256 state->buildConstants.revChecker =
michael@0 257 parentState->buildConstants.revChecker;
michael@0 258 state->buildConstants.aiaMgr =
michael@0 259 parentState->buildConstants.aiaMgr;
michael@0 260 state->buildConstants.trustOnlyUserAnchors =
michael@0 261 parentState->buildConstants.trustOnlyUserAnchors;
michael@0 262 }
michael@0 263
michael@0 264 *pState = state;
michael@0 265 state = NULL;
michael@0 266 cleanup:
michael@0 267
michael@0 268 PKIX_DECREF(state);
michael@0 269
michael@0 270 PKIX_RETURN(FORWARDBUILDERSTATE);
michael@0 271 }
michael@0 272
michael@0 273 /*
michael@0 274 * FUNCTION: pkix_Build_GetResourceLimits
michael@0 275 *
michael@0 276 * DESCRIPTION:
michael@0 277 * Retrieve Resource Limits from ProcessingParams and initialize them in
michael@0 278 * BuildConstants.
michael@0 279 *
michael@0 280 * PARAMETERS
michael@0 281 * "buildConstants"
michael@0 282 * Address of a BuildConstants structure containing objects and values
michael@0 283 * that remain constant throughout the building of a chain. Must be
michael@0 284 * non-NULL.
michael@0 285 * "plContext"
michael@0 286 * Platform-specific context pointer.
michael@0 287 * THREAD SAFETY:
michael@0 288 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 289 * RETURNS:
michael@0 290 * Returns NULL if the function succeeds.
michael@0 291 * Returns a Build Error if the function fails in a non-fatal way.
michael@0 292 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 293 */
michael@0 294 static PKIX_Error *
michael@0 295 pkix_Build_GetResourceLimits(
michael@0 296 BuildConstants *buildConstants,
michael@0 297 void *plContext)
michael@0 298 {
michael@0 299 PKIX_ResourceLimits *resourceLimits = NULL;
michael@0 300
michael@0 301 PKIX_ENTER(BUILD, "pkix_Build_GetResourceLimits");
michael@0 302 PKIX_NULLCHECK_ONE(buildConstants);
michael@0 303
michael@0 304 PKIX_CHECK(PKIX_ProcessingParams_GetResourceLimits
michael@0 305 (buildConstants->procParams, &resourceLimits, plContext),
michael@0 306 PKIX_PROCESSINGPARAMSGETRESOURCELIMITSFAILED);
michael@0 307
michael@0 308 buildConstants->maxFanout = 0;
michael@0 309 buildConstants->maxDepth = 0;
michael@0 310 buildConstants->maxTime = 0;
michael@0 311
michael@0 312 if (resourceLimits) {
michael@0 313
michael@0 314 PKIX_CHECK(PKIX_ResourceLimits_GetMaxFanout
michael@0 315 (resourceLimits, &buildConstants->maxFanout, plContext),
michael@0 316 PKIX_RESOURCELIMITSGETMAXFANOUTFAILED);
michael@0 317
michael@0 318 PKIX_CHECK(PKIX_ResourceLimits_GetMaxDepth
michael@0 319 (resourceLimits, &buildConstants->maxDepth, plContext),
michael@0 320 PKIX_RESOURCELIMITSGETMAXDEPTHFAILED);
michael@0 321
michael@0 322 PKIX_CHECK(PKIX_ResourceLimits_GetMaxTime
michael@0 323 (resourceLimits, &buildConstants->maxTime, plContext),
michael@0 324 PKIX_RESOURCELIMITSGETMAXTIMEFAILED);
michael@0 325 }
michael@0 326
michael@0 327 cleanup:
michael@0 328
michael@0 329 PKIX_DECREF(resourceLimits);
michael@0 330
michael@0 331 PKIX_RETURN(BUILD);
michael@0 332 }
michael@0 333
michael@0 334 /*
michael@0 335 * FUNCTION: pkix_ForwardBuilderState_ToString
michael@0 336 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
michael@0 337 */
michael@0 338 static PKIX_Error *
michael@0 339 pkix_ForwardBuilderState_ToString
michael@0 340 (PKIX_PL_Object *object,
michael@0 341 PKIX_PL_String **pString,
michael@0 342 void *plContext)
michael@0 343 {
michael@0 344 PKIX_ForwardBuilderState *state = NULL;
michael@0 345 PKIX_PL_String *formatString = NULL;
michael@0 346 PKIX_PL_String *resultString = NULL;
michael@0 347 PKIX_PL_String *buildStatusString = NULL;
michael@0 348 PKIX_PL_String *validityDateString = NULL;
michael@0 349 PKIX_PL_String *prevCertString = NULL;
michael@0 350 PKIX_PL_String *candidateCertString = NULL;
michael@0 351 PKIX_PL_String *traversedSubjNamesString = NULL;
michael@0 352 PKIX_PL_String *trustChainString = NULL;
michael@0 353 PKIX_PL_String *candidateCertsString = NULL;
michael@0 354 PKIX_PL_String *certSelString = NULL;
michael@0 355 PKIX_PL_String *verifyNodeString = NULL;
michael@0 356 PKIX_PL_String *parentStateString = NULL;
michael@0 357 char *asciiFormat = "\n"
michael@0 358 "\t{buildStatus: \t%s\n"
michael@0 359 "\ttraversedCACerts: \t%d\n"
michael@0 360 "\tcertStoreIndex: \t%d\n"
michael@0 361 "\tnumCerts: \t%d\n"
michael@0 362 "\tnumAias: \t%d\n"
michael@0 363 "\tcertIndex: \t%d\n"
michael@0 364 "\taiaIndex: \t%d\n"
michael@0 365 "\tnumFanout: \t%d\n"
michael@0 366 "\tnumDepth: \t%d\n"
michael@0 367 "\treasonCode: \t%d\n"
michael@0 368 "\tcanBeCached: \t%d\n"
michael@0 369 "\tuseOnlyLocal: \t%d\n"
michael@0 370 "\trevChecking: \t%d\n"
michael@0 371 "\tvalidityDate: \t%s\n"
michael@0 372 "\tprevCert: \t%s\n"
michael@0 373 "\tcandidateCert: \t%s\n"
michael@0 374 "\ttraversedSubjNames: \t%s\n"
michael@0 375 "\ttrustChain: \t%s\n"
michael@0 376 "\tcandidateCerts: \t%s\n"
michael@0 377 "\tcertSel: \t%s\n"
michael@0 378 "\tverifyNode: \t%s\n"
michael@0 379 "\tparentState: \t%s}\n";
michael@0 380 char *asciiStatus = NULL;
michael@0 381
michael@0 382 PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_ToString");
michael@0 383 PKIX_NULLCHECK_TWO(object, pString);
michael@0 384
michael@0 385 PKIX_CHECK(pkix_CheckType
michael@0 386 (object, PKIX_FORWARDBUILDERSTATE_TYPE, plContext),
michael@0 387 PKIX_OBJECTNOTFORWARDBUILDERSTATE);
michael@0 388
michael@0 389 state = (PKIX_ForwardBuilderState *)object;
michael@0 390
michael@0 391 PKIX_CHECK(PKIX_PL_String_Create
michael@0 392 (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
michael@0 393 PKIX_STRINGCREATEFAILED);
michael@0 394
michael@0 395 switch (state->status) {
michael@0 396 case BUILD_SHORTCUTPENDING: asciiStatus = "BUILD_SHORTCUTPENDING";
michael@0 397 break;
michael@0 398 case BUILD_INITIAL: asciiStatus = "BUILD_INITIAL";
michael@0 399 break;
michael@0 400 case BUILD_TRYAIA: asciiStatus = "BUILD_TRYAIA";
michael@0 401 break;
michael@0 402 case BUILD_AIAPENDING: asciiStatus = "BUILD_AIAPENDING";
michael@0 403 break;
michael@0 404 case BUILD_COLLECTINGCERTS: asciiStatus = "BUILD_COLLECTINGCERTS";
michael@0 405 break;
michael@0 406 case BUILD_GATHERPENDING: asciiStatus = "BUILD_GATHERPENDING";
michael@0 407 break;
michael@0 408 case BUILD_CERTVALIDATING: asciiStatus = "BUILD_CERTVALIDATING";
michael@0 409 break;
michael@0 410 case BUILD_ABANDONNODE: asciiStatus = "BUILD_ABANDONNODE";
michael@0 411 break;
michael@0 412 case BUILD_DATEPREP: asciiStatus = "BUILD_DATEPREP";
michael@0 413 break;
michael@0 414 case BUILD_CHECKTRUSTED: asciiStatus = "BUILD_CHECKTRUSTED";
michael@0 415 break;
michael@0 416 case BUILD_CHECKTRUSTED2: asciiStatus = "BUILD_CHECKTRUSTED2";
michael@0 417 break;
michael@0 418 case BUILD_ADDTOCHAIN: asciiStatus = "BUILD_ADDTOCHAIN";
michael@0 419 break;
michael@0 420 case BUILD_VALCHAIN: asciiStatus = "BUILD_VALCHAIN";
michael@0 421 break;
michael@0 422 case BUILD_VALCHAIN2: asciiStatus = "BUILD_VALCHAIN2";
michael@0 423 break;
michael@0 424 case BUILD_EXTENDCHAIN: asciiStatus = "BUILD_EXTENDCHAIN";
michael@0 425 break;
michael@0 426 case BUILD_GETNEXTCERT: asciiStatus = "BUILD_GETNEXTCERT";
michael@0 427 break;
michael@0 428 default: asciiStatus = "INVALID STATUS";
michael@0 429 break;
michael@0 430 }
michael@0 431
michael@0 432 PKIX_CHECK(PKIX_PL_String_Create
michael@0 433 (PKIX_ESCASCII, asciiStatus, 0, &buildStatusString, plContext),
michael@0 434 PKIX_STRINGCREATEFAILED);
michael@0 435
michael@0 436 PKIX_TOSTRING
michael@0 437 (state->validityDate, &validityDateString, plContext,
michael@0 438 PKIX_OBJECTTOSTRINGFAILED);
michael@0 439
michael@0 440 PKIX_TOSTRING
michael@0 441 (state->prevCert, &prevCertString, plContext,
michael@0 442 PKIX_OBJECTTOSTRINGFAILED);
michael@0 443
michael@0 444 PKIX_TOSTRING
michael@0 445 (state->candidateCert, &candidateCertString, plContext,
michael@0 446 PKIX_OBJECTTOSTRINGFAILED);
michael@0 447
michael@0 448 PKIX_TOSTRING
michael@0 449 (state->traversedSubjNames,
michael@0 450 &traversedSubjNamesString,
michael@0 451 plContext,
michael@0 452 PKIX_OBJECTTOSTRINGFAILED);
michael@0 453
michael@0 454 PKIX_TOSTRING
michael@0 455 (state->trustChain, &trustChainString, plContext,
michael@0 456 PKIX_OBJECTTOSTRINGFAILED);
michael@0 457
michael@0 458 PKIX_TOSTRING
michael@0 459 (state->candidateCerts, &candidateCertsString, plContext,
michael@0 460 PKIX_OBJECTTOSTRINGFAILED);
michael@0 461
michael@0 462 PKIX_TOSTRING
michael@0 463 (state->certSel, &certSelString, plContext,
michael@0 464 PKIX_OBJECTTOSTRINGFAILED);
michael@0 465
michael@0 466 PKIX_TOSTRING
michael@0 467 (state->verifyNode, &verifyNodeString, plContext,
michael@0 468 PKIX_OBJECTTOSTRINGFAILED);
michael@0 469
michael@0 470 PKIX_TOSTRING
michael@0 471 (state->parentState, &parentStateString, plContext,
michael@0 472 PKIX_OBJECTTOSTRINGFAILED);
michael@0 473
michael@0 474 PKIX_CHECK(PKIX_PL_Sprintf
michael@0 475 (&resultString,
michael@0 476 plContext,
michael@0 477 formatString,
michael@0 478 buildStatusString,
michael@0 479 (PKIX_Int32)state->traversedCACerts,
michael@0 480 (PKIX_UInt32)state->certStoreIndex,
michael@0 481 (PKIX_UInt32)state->numCerts,
michael@0 482 (PKIX_UInt32)state->numAias,
michael@0 483 (PKIX_UInt32)state->certIndex,
michael@0 484 (PKIX_UInt32)state->aiaIndex,
michael@0 485 (PKIX_UInt32)state->numFanout,
michael@0 486 (PKIX_UInt32)state->numDepth,
michael@0 487 (PKIX_UInt32)state->reasonCode,
michael@0 488 state->canBeCached,
michael@0 489 state->useOnlyLocal,
michael@0 490 state->revChecking,
michael@0 491 validityDateString,
michael@0 492 prevCertString,
michael@0 493 candidateCertString,
michael@0 494 traversedSubjNamesString,
michael@0 495 trustChainString,
michael@0 496 candidateCertsString,
michael@0 497 certSelString,
michael@0 498 verifyNodeString,
michael@0 499 parentStateString),
michael@0 500 PKIX_SPRINTFFAILED);
michael@0 501
michael@0 502 *pString = resultString;
michael@0 503
michael@0 504 cleanup:
michael@0 505 PKIX_DECREF(formatString);
michael@0 506 PKIX_DECREF(buildStatusString);
michael@0 507 PKIX_DECREF(validityDateString);
michael@0 508 PKIX_DECREF(prevCertString);
michael@0 509 PKIX_DECREF(candidateCertString);
michael@0 510 PKIX_DECREF(traversedSubjNamesString);
michael@0 511 PKIX_DECREF(trustChainString);
michael@0 512 PKIX_DECREF(candidateCertsString);
michael@0 513 PKIX_DECREF(certSelString);
michael@0 514 PKIX_DECREF(verifyNodeString);
michael@0 515 PKIX_DECREF(parentStateString);
michael@0 516
michael@0 517 PKIX_RETURN(FORWARDBUILDERSTATE);
michael@0 518
michael@0 519 }
michael@0 520
michael@0 521 /*
michael@0 522 * FUNCTION: pkix_ForwardBuilderState_RegisterSelf
michael@0 523 *
michael@0 524 * DESCRIPTION:
michael@0 525 * Registers PKIX_FORWARDBUILDERSTATE_TYPE and its related functions
michael@0 526 * with systemClasses[]
michael@0 527 *
michael@0 528 * THREAD SAFETY:
michael@0 529 * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 530 *
michael@0 531 * Since this function is only called by PKIX_PL_Initialize, which should
michael@0 532 * only be called once, it is acceptable that this function is not
michael@0 533 * thread-safe.
michael@0 534 */
michael@0 535 PKIX_Error *
michael@0 536 pkix_ForwardBuilderState_RegisterSelf(void *plContext)
michael@0 537 {
michael@0 538
michael@0 539 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
michael@0 540 pkix_ClassTable_Entry entry;
michael@0 541
michael@0 542 PKIX_ENTER(FORWARDBUILDERSTATE,
michael@0 543 "pkix_ForwardBuilderState_RegisterSelf");
michael@0 544
michael@0 545 entry.description = "ForwardBuilderState";
michael@0 546 entry.objCounter = 0;
michael@0 547 entry.typeObjectSize = sizeof(PKIX_ForwardBuilderState);
michael@0 548 entry.destructor = pkix_ForwardBuilderState_Destroy;
michael@0 549 entry.equalsFunction = NULL;
michael@0 550 entry.hashcodeFunction = NULL;
michael@0 551 entry.toStringFunction = pkix_ForwardBuilderState_ToString;
michael@0 552 entry.comparator = NULL;
michael@0 553 entry.duplicateFunction = NULL;
michael@0 554
michael@0 555 systemClasses[PKIX_FORWARDBUILDERSTATE_TYPE] = entry;
michael@0 556
michael@0 557 PKIX_RETURN(FORWARDBUILDERSTATE);
michael@0 558 }
michael@0 559
michael@0 560 #if PKIX_FORWARDBUILDERSTATEDEBUG
michael@0 561 /*
michael@0 562 * FUNCTION: pkix_ForwardBuilderState_DumpState
michael@0 563 *
michael@0 564 * DESCRIPTION:
michael@0 565 * This function invokes the ToString function on the argument pointed to
michael@0 566 * by "state".
michael@0 567 * PARAMETERS:
michael@0 568 * "state"
michael@0 569 * The address of the ForwardBuilderState object. Must be non-NULL.
michael@0 570 *
michael@0 571 * THREAD SAFETY:
michael@0 572 * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 573 */
michael@0 574 PKIX_Error *
michael@0 575 pkix_ForwardBuilderState_DumpState(
michael@0 576 PKIX_ForwardBuilderState *state,
michael@0 577 void *plContext)
michael@0 578 {
michael@0 579 PKIX_PL_String *stateString = NULL;
michael@0 580 char *stateAscii = NULL;
michael@0 581 PKIX_UInt32 length;
michael@0 582
michael@0 583 PKIX_ENTER(FORWARDBUILDERSTATE,"pkix_ForwardBuilderState_DumpState");
michael@0 584 PKIX_NULLCHECK_ONE(state);
michael@0 585
michael@0 586 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
michael@0 587 ((PKIX_PL_Object *)state, plContext),
michael@0 588 PKIX_OBJECTINVALIDATECACHEFAILED);
michael@0 589
michael@0 590 PKIX_CHECK(PKIX_PL_Object_ToString
michael@0 591 ((PKIX_PL_Object*)state, &stateString, plContext),
michael@0 592 PKIX_OBJECTTOSTRINGFAILED);
michael@0 593
michael@0 594 PKIX_CHECK(PKIX_PL_String_GetEncoded
michael@0 595 (stateString,
michael@0 596 PKIX_ESCASCII,
michael@0 597 (void **)&stateAscii,
michael@0 598 &length,
michael@0 599 plContext),
michael@0 600 PKIX_STRINGGETENCODEDFAILED);
michael@0 601
michael@0 602 PKIX_DEBUG_ARG("In Phase 1: state = %s\n", stateAscii);
michael@0 603
michael@0 604 PKIX_FREE(stateAscii);
michael@0 605 PKIX_DECREF(stateString);
michael@0 606
michael@0 607 cleanup:
michael@0 608 PKIX_RETURN(FORWARDBUILDERSTATE);
michael@0 609 }
michael@0 610 #endif
michael@0 611
michael@0 612 /*
michael@0 613 * FUNCTION: pkix_ForwardBuilderState_IsIOPending
michael@0 614 * DESCRIPTION:
michael@0 615 *
michael@0 616 * This function determines whether the state of the ForwardBuilderState
michael@0 617 * pointed to by "state" indicates I/O is in progress, and stores the Boolean
michael@0 618 * result at "pPending".
michael@0 619 *
michael@0 620 * PARAMETERS:
michael@0 621 * "state"
michael@0 622 * The address of the ForwardBuilderState object. Must be non-NULL.
michael@0 623 * "pPending"
michael@0 624 * The address at which the result is stored. Must be non-NULL.
michael@0 625 * "plContext"
michael@0 626 * Platform-specific context pointer.
michael@0 627 * THREAD SAFETY:
michael@0 628 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 629 * RETURNS:
michael@0 630 * Returns NULL if the function succeeds.
michael@0 631 * Returns a ForwardBuilderState Error if the function fails in a
michael@0 632 * non-fatal way.
michael@0 633 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 634 */
michael@0 635 static PKIX_Error*
michael@0 636 pkix_ForwardBuilderState_IsIOPending(
michael@0 637 PKIX_ForwardBuilderState *state,
michael@0 638 PKIX_Boolean *pPending,
michael@0 639 void *plContext)
michael@0 640 {
michael@0 641 PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_IsIOPending");
michael@0 642 PKIX_NULLCHECK_TWO(state, pPending);
michael@0 643
michael@0 644 if ((state->status == BUILD_GATHERPENDING) ||
michael@0 645 (state->status == BUILD_CHECKTRUSTED2) ||
michael@0 646 (state->status == BUILD_VALCHAIN2) ||
michael@0 647 (state->status == BUILD_AIAPENDING)) {
michael@0 648 *pPending = PKIX_TRUE;
michael@0 649 } else {
michael@0 650 *pPending = PKIX_FALSE;
michael@0 651 }
michael@0 652
michael@0 653 PKIX_RETURN(FORWARDBUILDERSTATE);
michael@0 654 }
michael@0 655
michael@0 656 /* --Private-BuildChain-Functions------------------------------------------- */
michael@0 657
michael@0 658 /*
michael@0 659 * FUNCTION: pkix_Build_SortCertComparator
michael@0 660 * DESCRIPTION:
michael@0 661 *
michael@0 662 * This Function takes two Certificates cast in "obj1" and "obj2",
michael@0 663 * compares their validity NotAfter dates and returns the result at
michael@0 664 * "pResult". The comparison key(s) can be expanded by using other
michael@0 665 * data in the Certificate in the future.
michael@0 666 *
michael@0 667 * PARAMETERS:
michael@0 668 * "obj1"
michael@0 669 * Address of the PKIX_PL_Object that is a cast of PKIX_PL_Cert.
michael@0 670 * Must be non-NULL.
michael@0 671 * "obj2"
michael@0 672 * Address of the PKIX_PL_Object that is a cast of PKIX_PL_Cert.
michael@0 673 * Must be non-NULL.
michael@0 674 * "pResult"
michael@0 675 * Address where the comparison result is returned. Must be non-NULL.
michael@0 676 * "plContext"
michael@0 677 * Platform-specific context pointer.
michael@0 678 * THREAD SAFETY:
michael@0 679 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 680 * RETURNS:
michael@0 681 * Returns NULL if the function succeeds.
michael@0 682 * Returns a Build Error if the function fails in a non-fatal way
michael@0 683 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 684 */
michael@0 685 static PKIX_Error *
michael@0 686 pkix_Build_SortCertComparator(
michael@0 687 PKIX_PL_Object *obj1,
michael@0 688 PKIX_PL_Object *obj2,
michael@0 689 PKIX_Int32 *pResult,
michael@0 690 void *plContext)
michael@0 691 {
michael@0 692 PKIX_PL_Date *date1 = NULL;
michael@0 693 PKIX_PL_Date *date2 = NULL;
michael@0 694 PKIX_Boolean result = PKIX_FALSE;
michael@0 695
michael@0 696 PKIX_ENTER(BUILD, "pkix_Build_SortCertComparator");
michael@0 697 PKIX_NULLCHECK_THREE(obj1, obj2, pResult);
michael@0 698
michael@0 699 /*
michael@0 700 * For sorting candidate certificates, we use NotAfter date as the
michael@0 701 * sorted key for now (can be expanded if desired in the future).
michael@0 702 *
michael@0 703 * In PKIX_BuildChain, the List of CertStores was reordered so that
michael@0 704 * trusted CertStores are ahead of untrusted CertStores. That sort, or
michael@0 705 * this one, could be taken out if it is determined that it doesn't help
michael@0 706 * performance, or in some way hinders the solution of choosing desired
michael@0 707 * candidates.
michael@0 708 */
michael@0 709
michael@0 710 PKIX_CHECK(pkix_CheckType(obj1, PKIX_CERT_TYPE, plContext),
michael@0 711 PKIX_OBJECTNOTCERT);
michael@0 712 PKIX_CHECK(pkix_CheckType(obj2, PKIX_CERT_TYPE, plContext),
michael@0 713 PKIX_OBJECTNOTCERT);
michael@0 714
michael@0 715 PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
michael@0 716 ((PKIX_PL_Cert *)obj1, &date1, plContext),
michael@0 717 PKIX_CERTGETVALIDITYNOTAFTERFAILED);
michael@0 718
michael@0 719 PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
michael@0 720 ((PKIX_PL_Cert *)obj2, &date2, plContext),
michael@0 721 PKIX_CERTGETVALIDITYNOTAFTERFAILED);
michael@0 722
michael@0 723 PKIX_CHECK(PKIX_PL_Object_Compare
michael@0 724 ((PKIX_PL_Object *)date1,
michael@0 725 (PKIX_PL_Object *)date2,
michael@0 726 &result,
michael@0 727 plContext),
michael@0 728 PKIX_OBJECTCOMPARATORFAILED);
michael@0 729
michael@0 730 *pResult = !result;
michael@0 731
michael@0 732 cleanup:
michael@0 733
michael@0 734 PKIX_DECREF(date1);
michael@0 735 PKIX_DECREF(date2);
michael@0 736
michael@0 737 PKIX_RETURN(BUILD);
michael@0 738 }
michael@0 739
michael@0 740 /* This local error check macro */
michael@0 741 #define ERROR_CHECK(errCode) \
michael@0 742 if (pkixErrorResult) { \
michael@0 743 if (pkixLog) { \
michael@0 744 PR_LOG(pkixLog, PR_LOG_DEBUG, ("====> ERROR_CHECK code %s\n", #errCode)); \
michael@0 745 } \
michael@0 746 pkixTempErrorReceived = PKIX_TRUE; \
michael@0 747 pkixErrorClass = pkixErrorResult->errClass; \
michael@0 748 if (pkixErrorClass == PKIX_FATAL_ERROR) { \
michael@0 749 goto cleanup; \
michael@0 750 } \
michael@0 751 if (verifyNode) { \
michael@0 752 PKIX_DECREF(verifyNode->error); \
michael@0 753 PKIX_INCREF(pkixErrorResult); \
michael@0 754 verifyNode->error = pkixErrorResult; \
michael@0 755 } \
michael@0 756 pkixErrorCode = errCode; \
michael@0 757 goto cleanup; \
michael@0 758 }
michael@0 759
michael@0 760 /*
michael@0 761 * FUNCTION: pkix_Build_VerifyCertificate
michael@0 762 * DESCRIPTION:
michael@0 763 *
michael@0 764 * Checks whether the previous Cert stored in the ForwardBuilderState pointed
michael@0 765 * to by "state" successfully chains, including signature verification, to the
michael@0 766 * candidate Cert also stored in "state", using the Boolean value in "trusted"
michael@0 767 * to determine whether "candidateCert" is trusted.
michael@0 768 *
michael@0 769 * First it checks whether "candidateCert" has already been traversed by
michael@0 770 * determining whether it is contained in the List of traversed Certs. It then
michael@0 771 * checks the candidate Cert with user checkers, if any, in the List pointed to
michael@0 772 * by "userCheckers". Finally, it runs the signature validation.
michael@0 773 *
michael@0 774 * If this Certificate fails verification, and state->verifyNode is non-NULL,
michael@0 775 * this function sets the Error code into the verifyNode.
michael@0 776 *
michael@0 777 * PARAMETERS:
michael@0 778 * "state"
michael@0 779 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 780 * "userCheckers"
michael@0 781 * Address of a List of CertChainCheckers to be used, if present, to
michael@0 782 * validate the candidateCert.
michael@0 783 * "trusted"
michael@0 784 * Boolean value of trust for the candidate Cert
michael@0 785 * "plContext"
michael@0 786 * Platform-specific context pointer.
michael@0 787 * THREAD SAFETY:
michael@0 788 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 789 * RETURNS:
michael@0 790 * Returns NULL if the function succeeds.
michael@0 791 * Returns a Build Error if the function fails in a non-fatal way
michael@0 792 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 793 */
michael@0 794 static PKIX_Error *
michael@0 795 pkix_Build_VerifyCertificate(
michael@0 796 PKIX_ForwardBuilderState *state,
michael@0 797 PKIX_List *userCheckers,
michael@0 798 PKIX_Boolean *pTrusted,
michael@0 799 PKIX_VerifyNode *verifyNode,
michael@0 800 void *plContext)
michael@0 801 {
michael@0 802 PKIX_UInt32 numUserCheckers = 0;
michael@0 803 PKIX_UInt32 i = 0;
michael@0 804 PKIX_Boolean loopFound = PKIX_FALSE;
michael@0 805 PKIX_Boolean supportForwardChecking = PKIX_FALSE;
michael@0 806 PKIX_Boolean trusted = PKIX_FALSE;
michael@0 807 PKIX_PL_Cert *candidateCert = NULL;
michael@0 808 PKIX_PL_PublicKey *candidatePubKey = NULL;
michael@0 809 PKIX_CertChainChecker *userChecker = NULL;
michael@0 810 PKIX_CertChainChecker_CheckCallback checkerCheck = NULL;
michael@0 811 PKIX_PL_TrustAnchorMode trustAnchorMode =
michael@0 812 PKIX_PL_TrustAnchorMode_Ignore;
michael@0 813 void *nbioContext = NULL;
michael@0 814
michael@0 815 PKIX_ENTER(BUILD, "pkix_Build_VerifyCertificate");
michael@0 816 PKIX_NULLCHECK_TWO(state, pTrusted);
michael@0 817 PKIX_NULLCHECK_THREE
michael@0 818 (state->candidateCerts, state->prevCert, state->trustChain);
michael@0 819
michael@0 820 PKIX_INCREF(state->candidateCert);
michael@0 821 candidateCert = state->candidateCert;
michael@0 822
michael@0 823 if (state->buildConstants.numAnchors) {
michael@0 824 if (state->buildConstants.trustOnlyUserAnchors) {
michael@0 825 trustAnchorMode = PKIX_PL_TrustAnchorMode_Exclusive;
michael@0 826 } else {
michael@0 827 trustAnchorMode = PKIX_PL_TrustAnchorMode_Additive;
michael@0 828 }
michael@0 829 } else {
michael@0 830 trustAnchorMode = PKIX_PL_TrustAnchorMode_Ignore;
michael@0 831 }
michael@0 832
michael@0 833 PKIX_CHECK(
michael@0 834 PKIX_PL_Cert_IsCertTrusted(candidateCert, trustAnchorMode,
michael@0 835 &trusted, plContext),
michael@0 836 PKIX_CERTISCERTTRUSTEDFAILED);
michael@0 837
michael@0 838 *pTrusted = trusted;
michael@0 839
michael@0 840 /* check for loops */
michael@0 841 PKIX_CHECK(pkix_List_Contains
michael@0 842 (state->trustChain,
michael@0 843 (PKIX_PL_Object *)candidateCert,
michael@0 844 &loopFound,
michael@0 845 plContext),
michael@0 846 PKIX_LISTCONTAINSFAILED);
michael@0 847
michael@0 848 if (loopFound) {
michael@0 849 if (verifyNode != NULL) {
michael@0 850 PKIX_Error *verifyError = NULL;
michael@0 851 PKIX_ERROR_CREATE
michael@0 852 (BUILD,
michael@0 853 PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED,
michael@0 854 verifyError);
michael@0 855 PKIX_DECREF(verifyNode->error);
michael@0 856 verifyNode->error = verifyError;
michael@0 857 }
michael@0 858 /* Even if error logged, still need to abort
michael@0 859 * if cert is not trusted. */
michael@0 860 if (!trusted) {
michael@0 861 PKIX_ERROR(PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED);
michael@0 862 }
michael@0 863 state->certLoopingDetected = PKIX_TRUE;
michael@0 864 }
michael@0 865
michael@0 866 if (userCheckers != NULL) {
michael@0 867
michael@0 868 PKIX_CHECK(PKIX_List_GetLength
michael@0 869 (userCheckers, &numUserCheckers, plContext),
michael@0 870 PKIX_LISTGETLENGTHFAILED);
michael@0 871
michael@0 872 for (i = 0; i < numUserCheckers; i++) {
michael@0 873
michael@0 874 PKIX_CHECK(PKIX_List_GetItem
michael@0 875 (userCheckers,
michael@0 876 i,
michael@0 877 (PKIX_PL_Object **) &userChecker,
michael@0 878 plContext),
michael@0 879 PKIX_LISTGETITEMFAILED);
michael@0 880
michael@0 881 PKIX_CHECK
michael@0 882 (PKIX_CertChainChecker_IsForwardCheckingSupported
michael@0 883 (userChecker, &supportForwardChecking, plContext),
michael@0 884 PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED);
michael@0 885
michael@0 886 if (supportForwardChecking == PKIX_TRUE) {
michael@0 887
michael@0 888 PKIX_CHECK(PKIX_CertChainChecker_GetCheckCallback
michael@0 889 (userChecker, &checkerCheck, plContext),
michael@0 890 PKIX_CERTCHAINCHECKERGETCHECKCALLBACKFAILED);
michael@0 891
michael@0 892 pkixErrorResult =
michael@0 893 checkerCheck(userChecker, candidateCert, NULL,
michael@0 894 &nbioContext, plContext);
michael@0 895
michael@0 896 ERROR_CHECK(PKIX_USERCHECKERCHECKFAILED);
michael@0 897 }
michael@0 898
michael@0 899 PKIX_DECREF(userChecker);
michael@0 900 }
michael@0 901 }
michael@0 902
michael@0 903 /* Check that public key of the trusted dsa cert has
michael@0 904 * dsa parameters */
michael@0 905 if (trusted) {
michael@0 906 PKIX_Boolean paramsNeeded = PKIX_FALSE;
michael@0 907 PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
michael@0 908 (candidateCert, &candidatePubKey, plContext),
michael@0 909 PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
michael@0 910 PKIX_CHECK(PKIX_PL_PublicKey_NeedsDSAParameters
michael@0 911 (candidatePubKey, &paramsNeeded, plContext),
michael@0 912 PKIX_PUBLICKEYNEEDSDSAPARAMETERSFAILED);
michael@0 913 if (paramsNeeded) {
michael@0 914 PKIX_ERROR(PKIX_MISSINGDSAPARAMETERS);
michael@0 915 }
michael@0 916 }
michael@0 917
michael@0 918 cleanup:
michael@0 919 PKIX_DECREF(candidateCert);
michael@0 920 PKIX_DECREF(candidatePubKey);
michael@0 921 PKIX_DECREF(userChecker);
michael@0 922
michael@0 923 PKIX_RETURN(BUILD);
michael@0 924 }
michael@0 925
michael@0 926 /*
michael@0 927 * FUNCTION: pkix_Build_ValidationCheckers
michael@0 928 * DESCRIPTION:
michael@0 929 *
michael@0 930 * Creates a List of Objects to be used in determining whether the List of
michael@0 931 * Certs pointed to by "certChain" successfully validates using the
michael@0 932 * ForwardBuilderState pointed to by "state", and the TrustAnchor pointed to by
michael@0 933 * "anchor". These objects are a reversed Cert Chain, consisting of the certs
michael@0 934 * in "certChain" in reversed order, suitable for presenting to the
michael@0 935 * CertChainCheckers; a List of critical extension OIDS that have already been
michael@0 936 * processed in forward building; a List of CertChainCheckers to be called, and
michael@0 937 * a List of RevocationCheckers to be called. These results are stored in
michael@0 938 * fields of "state".
michael@0 939 *
michael@0 940 * PARAMETERS:
michael@0 941 * "state"
michael@0 942 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 943 * "certChain"
michael@0 944 * Address of List of Certs to be validated. Must be non-NULL.
michael@0 945 * "anchor"
michael@0 946 * Address of TrustAnchor to be used. Must be non-NULL.
michael@0 947 * "addEkuChecker"
michael@0 948 * Boolean flags that tells to add eku checker to the list
michael@0 949 * of checkers. Only needs to be done for existing chain revalidation.
michael@0 950 * "plContext"
michael@0 951 * Platform-specific context pointer.
michael@0 952 * THREAD SAFETY:
michael@0 953 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 954 * RETURNS:
michael@0 955 * Returns NULL if the function succeeds.
michael@0 956 * Returns a Build Error if the function fails in a non-fatal way
michael@0 957 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 958 */
michael@0 959 static PKIX_Error *
michael@0 960 pkix_Build_ValidationCheckers(
michael@0 961 PKIX_ForwardBuilderState *state,
michael@0 962 PKIX_List *certChain,
michael@0 963 PKIX_TrustAnchor *anchor,
michael@0 964 PKIX_Boolean chainRevalidationStage,
michael@0 965 void *plContext)
michael@0 966 {
michael@0 967 PKIX_List *checkers = NULL;
michael@0 968 PKIX_List *initialPolicies = NULL;
michael@0 969 PKIX_List *reversedCertChain = NULL;
michael@0 970 PKIX_List *buildCheckedCritExtOIDsList = NULL;
michael@0 971 PKIX_ProcessingParams *procParams = NULL;
michael@0 972 PKIX_PL_Cert *trustedCert = NULL;
michael@0 973 PKIX_PL_PublicKey *trustedPubKey = NULL;
michael@0 974 PKIX_PL_CertNameConstraints *trustedNC = NULL;
michael@0 975 PKIX_CertChainChecker *sigChecker = NULL;
michael@0 976 PKIX_CertChainChecker *policyChecker = NULL;
michael@0 977 PKIX_CertChainChecker *userChecker = NULL;
michael@0 978 PKIX_CertChainChecker *nameConstraintsChecker = NULL;
michael@0 979 PKIX_CertChainChecker *checker = NULL;
michael@0 980 PKIX_CertSelector *certSelector = NULL;
michael@0 981 PKIX_List *userCheckerExtOIDs = NULL;
michael@0 982 PKIX_PL_OID *oid = NULL;
michael@0 983 PKIX_Boolean supportForwardChecking = PKIX_FALSE;
michael@0 984 PKIX_Boolean policyQualifiersRejected = PKIX_FALSE;
michael@0 985 PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE;
michael@0 986 PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE;
michael@0 987 PKIX_Boolean initialExplicitPolicy = PKIX_FALSE;
michael@0 988 PKIX_UInt32 numChainCerts;
michael@0 989 PKIX_UInt32 numCertCheckers;
michael@0 990 PKIX_UInt32 i;
michael@0 991
michael@0 992 PKIX_ENTER(BUILD, "pkix_Build_ValidationCheckers");
michael@0 993 PKIX_NULLCHECK_THREE(state, certChain, anchor);
michael@0 994
michael@0 995 PKIX_CHECK(PKIX_List_Create(&checkers, plContext),
michael@0 996 PKIX_LISTCREATEFAILED);
michael@0 997
michael@0 998 PKIX_CHECK(PKIX_List_ReverseList
michael@0 999 (certChain, &reversedCertChain, plContext),
michael@0 1000 PKIX_LISTREVERSELISTFAILED);
michael@0 1001
michael@0 1002 PKIX_CHECK(PKIX_List_GetLength
michael@0 1003 (reversedCertChain, &numChainCerts, plContext),
michael@0 1004 PKIX_LISTGETLENGTHFAILED);
michael@0 1005
michael@0 1006 procParams = state->buildConstants.procParams;
michael@0 1007
michael@0 1008 /* Do need to add a number of checker to revalidate
michael@0 1009 * a built chain. KU, EKU, CertType and Validity Date
michael@0 1010 * get checked by certificate selector during chain
michael@0 1011 * construction, but needed to be checked for chain from
michael@0 1012 * the cache.*/
michael@0 1013 if (chainRevalidationStage) {
michael@0 1014 PKIX_CHECK(pkix_ExpirationChecker_Initialize
michael@0 1015 (state->buildConstants.testDate, &checker, plContext),
michael@0 1016 PKIX_EXPIRATIONCHECKERINITIALIZEFAILED);
michael@0 1017 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1018 (checkers, (PKIX_PL_Object *)checker, plContext),
michael@0 1019 PKIX_LISTAPPENDITEMFAILED);
michael@0 1020 PKIX_DECREF(checker);
michael@0 1021
michael@0 1022 PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
michael@0 1023 (procParams, &certSelector, plContext),
michael@0 1024 PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
michael@0 1025
michael@0 1026 PKIX_CHECK(pkix_TargetCertChecker_Initialize
michael@0 1027 (certSelector, numChainCerts, &checker, plContext),
michael@0 1028 PKIX_EXPIRATIONCHECKERINITIALIZEFAILED);
michael@0 1029 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1030 (checkers, (PKIX_PL_Object *)checker, plContext),
michael@0 1031 PKIX_LISTAPPENDITEMFAILED);
michael@0 1032 PKIX_DECREF(checker);
michael@0 1033 }
michael@0 1034
michael@0 1035 PKIX_CHECK(PKIX_ProcessingParams_GetInitialPolicies
michael@0 1036 (procParams, &initialPolicies, plContext),
michael@0 1037 PKIX_PROCESSINGPARAMSGETINITIALPOLICIESFAILED);
michael@0 1038
michael@0 1039 PKIX_CHECK(PKIX_ProcessingParams_GetPolicyQualifiersRejected
michael@0 1040 (procParams, &policyQualifiersRejected, plContext),
michael@0 1041 PKIX_PROCESSINGPARAMSGETPOLICYQUALIFIERSREJECTEDFAILED);
michael@0 1042
michael@0 1043 PKIX_CHECK(PKIX_ProcessingParams_IsPolicyMappingInhibited
michael@0 1044 (procParams, &initialPolicyMappingInhibit, plContext),
michael@0 1045 PKIX_PROCESSINGPARAMSISPOLICYMAPPINGINHIBITEDFAILED);
michael@0 1046
michael@0 1047 PKIX_CHECK(PKIX_ProcessingParams_IsAnyPolicyInhibited
michael@0 1048 (procParams, &initialAnyPolicyInhibit, plContext),
michael@0 1049 PKIX_PROCESSINGPARAMSISANYPOLICYINHIBITEDFAILED);
michael@0 1050
michael@0 1051 PKIX_CHECK(PKIX_ProcessingParams_IsExplicitPolicyRequired
michael@0 1052 (procParams, &initialExplicitPolicy, plContext),
michael@0 1053 PKIX_PROCESSINGPARAMSISEXPLICITPOLICYREQUIREDFAILED);
michael@0 1054
michael@0 1055 PKIX_CHECK(pkix_PolicyChecker_Initialize
michael@0 1056 (initialPolicies,
michael@0 1057 policyQualifiersRejected,
michael@0 1058 initialPolicyMappingInhibit,
michael@0 1059 initialExplicitPolicy,
michael@0 1060 initialAnyPolicyInhibit,
michael@0 1061 numChainCerts,
michael@0 1062 &policyChecker,
michael@0 1063 plContext),
michael@0 1064 PKIX_POLICYCHECKERINITIALIZEFAILED);
michael@0 1065
michael@0 1066 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1067 (checkers, (PKIX_PL_Object *)policyChecker, plContext),
michael@0 1068 PKIX_LISTAPPENDITEMFAILED);
michael@0 1069
michael@0 1070 /*
michael@0 1071 * Create an OID list that contains critical extensions processed
michael@0 1072 * by BuildChain. These are specified in a static const array.
michael@0 1073 */
michael@0 1074 PKIX_CHECK(PKIX_List_Create(&buildCheckedCritExtOIDsList, plContext),
michael@0 1075 PKIX_LISTCREATEFAILED);
michael@0 1076
michael@0 1077 for (i = 0; buildCheckedCritExtOIDs[i] != PKIX_UNKNOWN_OID; i++) {
michael@0 1078 PKIX_CHECK(PKIX_PL_OID_Create
michael@0 1079 (buildCheckedCritExtOIDs[i], &oid, plContext),
michael@0 1080 PKIX_OIDCREATEFAILED);
michael@0 1081
michael@0 1082 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1083 (buildCheckedCritExtOIDsList,
michael@0 1084 (PKIX_PL_Object *) oid,
michael@0 1085 plContext),
michael@0 1086 PKIX_LISTAPPENDITEMFAILED);
michael@0 1087
michael@0 1088 PKIX_DECREF(oid);
michael@0 1089 }
michael@0 1090
michael@0 1091 if (state->buildConstants.userCheckers != NULL) {
michael@0 1092
michael@0 1093 PKIX_CHECK(PKIX_List_GetLength
michael@0 1094 (state->buildConstants.userCheckers,
michael@0 1095 &numCertCheckers,
michael@0 1096 plContext),
michael@0 1097 PKIX_LISTGETLENGTHFAILED);
michael@0 1098
michael@0 1099 for (i = 0; i < numCertCheckers; i++) {
michael@0 1100
michael@0 1101 PKIX_CHECK(PKIX_List_GetItem
michael@0 1102 (state->buildConstants.userCheckers,
michael@0 1103 i,
michael@0 1104 (PKIX_PL_Object **) &userChecker,
michael@0 1105 plContext),
michael@0 1106 PKIX_LISTGETITEMFAILED);
michael@0 1107
michael@0 1108 PKIX_CHECK
michael@0 1109 (PKIX_CertChainChecker_IsForwardCheckingSupported
michael@0 1110 (userChecker, &supportForwardChecking, plContext),
michael@0 1111 PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED);
michael@0 1112
michael@0 1113 /*
michael@0 1114 * If this userChecker supports forwardChecking then it
michael@0 1115 * should have been checked during build chain. Skip
michael@0 1116 * checking but need to add checker's extension OIDs
michael@0 1117 * to buildCheckedCritExtOIDsList.
michael@0 1118 */
michael@0 1119 if (supportForwardChecking == PKIX_TRUE) {
michael@0 1120
michael@0 1121 PKIX_CHECK
michael@0 1122 (PKIX_CertChainChecker_GetSupportedExtensions
michael@0 1123 (userChecker, &userCheckerExtOIDs, plContext),
michael@0 1124 PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED);
michael@0 1125
michael@0 1126 if (userCheckerExtOIDs != NULL) {
michael@0 1127 PKIX_CHECK(pkix_List_AppendList
michael@0 1128 (buildCheckedCritExtOIDsList,
michael@0 1129 userCheckerExtOIDs,
michael@0 1130 plContext),
michael@0 1131 PKIX_LISTAPPENDLISTFAILED);
michael@0 1132 }
michael@0 1133
michael@0 1134 } else {
michael@0 1135 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1136 (checkers,
michael@0 1137 (PKIX_PL_Object *)userChecker,
michael@0 1138 plContext),
michael@0 1139 PKIX_LISTAPPENDITEMFAILED);
michael@0 1140 }
michael@0 1141
michael@0 1142 PKIX_DECREF(userCheckerExtOIDs);
michael@0 1143 PKIX_DECREF(userChecker);
michael@0 1144 }
michael@0 1145 }
michael@0 1146
michael@0 1147 /* Enabling post chain building signature check on the certs. */
michael@0 1148 PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
michael@0 1149 (anchor, &trustedCert, plContext),
michael@0 1150 PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
michael@0 1151
michael@0 1152 PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
michael@0 1153 (trustedCert, &trustedPubKey, plContext),
michael@0 1154 PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
michael@0 1155
michael@0 1156 PKIX_CHECK(pkix_SignatureChecker_Initialize
michael@0 1157 (trustedPubKey,
michael@0 1158 numChainCerts,
michael@0 1159 &sigChecker,
michael@0 1160 plContext),
michael@0 1161 PKIX_SIGNATURECHECKERINITIALIZEFAILED);
michael@0 1162
michael@0 1163 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1164 (checkers,
michael@0 1165 (PKIX_PL_Object *)sigChecker,
michael@0 1166 plContext),
michael@0 1167 PKIX_LISTAPPENDITEMFAILED);
michael@0 1168
michael@0 1169 /* Enabling post chain building name constraints check on the certs. */
michael@0 1170 PKIX_CHECK(PKIX_TrustAnchor_GetNameConstraints
michael@0 1171 (anchor, &trustedNC, plContext),
michael@0 1172 PKIX_TRUSTANCHORGETNAMECONSTRAINTSFAILED);
michael@0 1173
michael@0 1174 PKIX_CHECK(pkix_NameConstraintsChecker_Initialize
michael@0 1175 (trustedNC, numChainCerts, &nameConstraintsChecker,
michael@0 1176 plContext),
michael@0 1177 PKIX_NAMECONSTRAINTSCHECKERINITIALIZEFAILED);
michael@0 1178
michael@0 1179 PKIX_CHECK(PKIX_List_AppendItem
michael@0 1180 (checkers,
michael@0 1181 (PKIX_PL_Object *)nameConstraintsChecker,
michael@0 1182 plContext),
michael@0 1183 PKIX_LISTAPPENDITEMFAILED);
michael@0 1184
michael@0 1185
michael@0 1186 PKIX_DECREF(state->reversedCertChain);
michael@0 1187 PKIX_INCREF(reversedCertChain);
michael@0 1188 state->reversedCertChain = reversedCertChain;
michael@0 1189 PKIX_DECREF(state->checkedCritExtOIDs);
michael@0 1190 PKIX_INCREF(buildCheckedCritExtOIDsList);
michael@0 1191 state->checkedCritExtOIDs = buildCheckedCritExtOIDsList;
michael@0 1192 PKIX_DECREF(state->checkerChain);
michael@0 1193 state->checkerChain = checkers;
michael@0 1194 checkers = NULL;
michael@0 1195 state->certCheckedIndex = 0;
michael@0 1196 state->checkerIndex = 0;
michael@0 1197 state->revChecking = PKIX_FALSE;
michael@0 1198
michael@0 1199
michael@0 1200 cleanup:
michael@0 1201
michael@0 1202 PKIX_DECREF(oid);
michael@0 1203 PKIX_DECREF(reversedCertChain);
michael@0 1204 PKIX_DECREF(buildCheckedCritExtOIDsList);
michael@0 1205 PKIX_DECREF(checker);
michael@0 1206 PKIX_DECREF(checkers);
michael@0 1207 PKIX_DECREF(initialPolicies);
michael@0 1208 PKIX_DECREF(trustedCert);
michael@0 1209 PKIX_DECREF(trustedPubKey);
michael@0 1210 PKIX_DECREF(certSelector);
michael@0 1211 PKIX_DECREF(sigChecker);
michael@0 1212 PKIX_DECREF(trustedNC);
michael@0 1213 PKIX_DECREF(nameConstraintsChecker);
michael@0 1214 PKIX_DECREF(policyChecker);
michael@0 1215 PKIX_DECREF(userChecker);
michael@0 1216 PKIX_DECREF(userCheckerExtOIDs);
michael@0 1217
michael@0 1218 PKIX_RETURN(BUILD);
michael@0 1219 }
michael@0 1220
michael@0 1221 /*
michael@0 1222 * FUNCTION: pkix_Build_ValidateEntireChain
michael@0 1223 * DESCRIPTION:
michael@0 1224 *
michael@0 1225 * Checks whether the current List of Certs successfully validates using the
michael@0 1226 * TrustAnchor pointed to by "anchor" and other parameters contained, as was
michael@0 1227 * the Cert List, in "state".
michael@0 1228 *
michael@0 1229 * If a checker using non-blocking I/O returns with a non-NULL non-blocking I/O
michael@0 1230 * context (NBIOContext), an indication that I/O is in progress and the
michael@0 1231 * checking has not been completed, this function stores that context at
michael@0 1232 * "pNBIOContext". Otherwise, it stores NULL at "pNBIOContext".
michael@0 1233 *
michael@0 1234 * If not awaiting I/O and if successful, a ValidateResult is created
michael@0 1235 * containing the Public Key of the target certificate (including DSA parameter
michael@0 1236 * inheritance, if any) and the PolicyNode representing the policy tree output
michael@0 1237 * by the validation algorithm. If not successful, an Error pointer is
michael@0 1238 * returned.
michael@0 1239 *
michael@0 1240 * PARAMETERS:
michael@0 1241 * "state"
michael@0 1242 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 1243 * "anchor"
michael@0 1244 * Address of TrustAnchor to be used. Must be non-NULL.
michael@0 1245 * "pNBIOContext"
michael@0 1246 * Address at which the NBIOContext is stored indicating whether the
michael@0 1247 * validation is complete. Must be non-NULL.
michael@0 1248 * "pValResult"
michael@0 1249 * Address at which the ValidateResult is stored. Must be non-NULL.
michael@0 1250 * "plContext"
michael@0 1251 * Platform-specific context pointer.
michael@0 1252 * THREAD SAFETY:
michael@0 1253 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 1254 * RETURNS:
michael@0 1255 * Returns NULL if the function succeeds.
michael@0 1256 * Returns a Build Error if the function fails in a non-fatal way
michael@0 1257 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 1258 */
michael@0 1259 static PKIX_Error *
michael@0 1260 pkix_Build_ValidateEntireChain(
michael@0 1261 PKIX_ForwardBuilderState *state,
michael@0 1262 PKIX_TrustAnchor *anchor,
michael@0 1263 void **pNBIOContext,
michael@0 1264 PKIX_ValidateResult **pValResult,
michael@0 1265 PKIX_VerifyNode *verifyNode,
michael@0 1266 void *plContext)
michael@0 1267 {
michael@0 1268 PKIX_UInt32 numChainCerts = 0;
michael@0 1269 PKIX_PL_PublicKey *subjPubKey = NULL;
michael@0 1270 PKIX_PolicyNode *policyTree = NULL;
michael@0 1271 PKIX_ValidateResult *valResult = NULL;
michael@0 1272 void *nbioContext = NULL;
michael@0 1273
michael@0 1274 PKIX_ENTER(BUILD, "pkix_Build_ValidateEntireChain");
michael@0 1275 PKIX_NULLCHECK_FOUR(state, anchor, pNBIOContext, pValResult);
michael@0 1276
michael@0 1277 *pNBIOContext = NULL; /* prepare for case of error exit */
michael@0 1278
michael@0 1279 PKIX_CHECK(PKIX_List_GetLength
michael@0 1280 (state->reversedCertChain, &numChainCerts, plContext),
michael@0 1281 PKIX_LISTGETLENGTHFAILED);
michael@0 1282
michael@0 1283 pkixErrorResult =
michael@0 1284 pkix_CheckChain(state->reversedCertChain, numChainCerts, anchor,
michael@0 1285 state->checkerChain,
michael@0 1286 state->buildConstants.revChecker,
michael@0 1287 state->checkedCritExtOIDs,
michael@0 1288 state->buildConstants.procParams,
michael@0 1289 &state->certCheckedIndex, &state->checkerIndex,
michael@0 1290 &state->revChecking, &state->reasonCode,
michael@0 1291 &nbioContext, &subjPubKey, &policyTree, NULL,
michael@0 1292 plContext);
michael@0 1293
michael@0 1294 if (nbioContext != NULL) {
michael@0 1295 *pNBIOContext = nbioContext;
michael@0 1296 goto cleanup;
michael@0 1297 }
michael@0 1298
michael@0 1299 ERROR_CHECK(PKIX_CHECKCHAINFAILED);
michael@0 1300
michael@0 1301 /* XXX Remove this assertion after 2014-12-31. See bug 946984. */
michael@0 1302 PORT_Assert(state->reasonCode == 0);
michael@0 1303
michael@0 1304 PKIX_CHECK(pkix_ValidateResult_Create
michael@0 1305 (subjPubKey, anchor, policyTree, &valResult, plContext),
michael@0 1306 PKIX_VALIDATERESULTCREATEFAILED);
michael@0 1307
michael@0 1308 *pValResult = valResult;
michael@0 1309 valResult = NULL;
michael@0 1310
michael@0 1311 cleanup:
michael@0 1312 PKIX_DECREF(subjPubKey);
michael@0 1313 PKIX_DECREF(policyTree);
michael@0 1314 PKIX_DECREF(valResult);
michael@0 1315
michael@0 1316 PKIX_RETURN(BUILD);
michael@0 1317 }
michael@0 1318
michael@0 1319 /*
michael@0 1320 * FUNCTION: pkix_Build_SortCandidateCerts
michael@0 1321 * DESCRIPTION:
michael@0 1322 *
michael@0 1323 * This function sorts a List of candidate Certs pointed to by "candidates"
michael@0 1324 * using an algorithm that places Certs most likely to produce a successful
michael@0 1325 * chain at the front of the list, storing the resulting sorted List at
michael@0 1326 * "pSortedCandidates".
michael@0 1327 *
michael@0 1328 * At present the only sort criterion is that trusted Certs go ahead of
michael@0 1329 * untrusted Certs.
michael@0 1330 *
michael@0 1331 * PARAMETERS:
michael@0 1332 * "candidates"
michael@0 1333 * Address of List of Candidate Certs to be sorted. Must be non-NULL.
michael@0 1334 * "pSortedCandidates"
michael@0 1335 * Address at which sorted List is stored. Must be non-NULL.
michael@0 1336 * "plContext"
michael@0 1337 * Platform-specific context pointer.
michael@0 1338 * THREAD SAFETY:
michael@0 1339 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 1340 * RETURNS:
michael@0 1341 * Returns NULL if the function succeeds.
michael@0 1342 * Returns a Build Error if the function fails in a non-fatal way
michael@0 1343 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 1344 */
michael@0 1345 static PKIX_Error *
michael@0 1346 pkix_Build_SortCandidateCerts(
michael@0 1347 PKIX_List *candidates,
michael@0 1348 PKIX_List **pSortedCandidates,
michael@0 1349 void *plContext)
michael@0 1350 {
michael@0 1351 PKIX_List *sortedList = NULL;
michael@0 1352
michael@0 1353 PKIX_ENTER(BUILD, "pkix_Build_SortCandidateCerts");
michael@0 1354 PKIX_NULLCHECK_TWO(candidates, pSortedCandidates);
michael@0 1355
michael@0 1356 /*
michael@0 1357 * Both bubble and quick sort algorithms are available.
michael@0 1358 * For a list of fewer than around 100 items, the bubble sort is more
michael@0 1359 * efficient. (This number was determined by experimenting with both
michael@0 1360 * algorithms on a Java List.)
michael@0 1361 * If the candidate list is very small, using the sort can drag down
michael@0 1362 * the performance a little bit.
michael@0 1363 */
michael@0 1364
michael@0 1365 PKIX_CHECK(pkix_List_BubbleSort
michael@0 1366 (candidates,
michael@0 1367 pkix_Build_SortCertComparator,
michael@0 1368 &sortedList,
michael@0 1369 plContext),
michael@0 1370 PKIX_LISTBUBBLESORTFAILED);
michael@0 1371
michael@0 1372 *pSortedCandidates = sortedList;
michael@0 1373
michael@0 1374 cleanup:
michael@0 1375
michael@0 1376 PKIX_RETURN(BUILD);
michael@0 1377 }
michael@0 1378
michael@0 1379 /*
michael@0 1380 * FUNCTION: pkix_Build_BuildSelectorAndParams
michael@0 1381 * DESCRIPTION:
michael@0 1382 *
michael@0 1383 * This function creates a CertSelector, initialized with an appropriate
michael@0 1384 * ComCertSelParams, using the variables provided in the ForwardBuilderState
michael@0 1385 * pointed to by "state". The CertSelector created is stored in the certsel
michael@0 1386 * element of "state".
michael@0 1387 *
michael@0 1388 * PARAMETERS:
michael@0 1389 * "state"
michael@0 1390 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 1391 * "plContext"
michael@0 1392 * Platform-specific context pointer.
michael@0 1393 * THREAD SAFETY:
michael@0 1394 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 1395 * RETURNS:
michael@0 1396 * Returns NULL if the function succeeds.
michael@0 1397 * Returns a Build Error if the function fails in a non-fatal way
michael@0 1398 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 1399 */
michael@0 1400 static PKIX_Error *
michael@0 1401 pkix_Build_BuildSelectorAndParams(
michael@0 1402 PKIX_ForwardBuilderState *state,
michael@0 1403 void *plContext)
michael@0 1404 {
michael@0 1405 PKIX_ComCertSelParams *certSelParams = NULL;
michael@0 1406 PKIX_CertSelector *certSel = NULL;
michael@0 1407 PKIX_PL_X500Name *currentIssuer = NULL;
michael@0 1408 PKIX_PL_ByteArray *authKeyId = NULL;
michael@0 1409 PKIX_PL_Date *testDate = NULL;
michael@0 1410 PKIX_CertSelector *callerCertSelector = NULL;
michael@0 1411 PKIX_ComCertSelParams *callerComCertSelParams = NULL;
michael@0 1412 PKIX_UInt32 reqKu = 0;
michael@0 1413 PKIX_List *reqEkuOids = NULL;
michael@0 1414
michael@0 1415 PKIX_ENTER(BUILD, "pkix_Build_BuildSelectorAndParams");
michael@0 1416 PKIX_NULLCHECK_THREE(state, state->prevCert, state->traversedSubjNames);
michael@0 1417
michael@0 1418 PKIX_CHECK(PKIX_PL_Cert_GetIssuer
michael@0 1419 (state->prevCert, &currentIssuer, plContext),
michael@0 1420 PKIX_CERTGETISSUERFAILED);
michael@0 1421
michael@0 1422 PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier
michael@0 1423 (state->prevCert, &authKeyId, plContext),
michael@0 1424 PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED);
michael@0 1425
michael@0 1426 PKIX_CHECK(PKIX_ComCertSelParams_Create(&certSelParams, plContext),
michael@0 1427 PKIX_COMCERTSELPARAMSCREATEFAILED);
michael@0 1428
michael@0 1429 PKIX_CHECK(PKIX_ComCertSelParams_SetSubject
michael@0 1430 (certSelParams, currentIssuer, plContext),
michael@0 1431 PKIX_COMCERTSELPARAMSSETSUBJECTFAILED);
michael@0 1432
michael@0 1433 if (authKeyId != NULL) {
michael@0 1434 PKIX_CHECK(PKIX_ComCertSelParams_SetSubjKeyIdentifier
michael@0 1435 (certSelParams, authKeyId, plContext),
michael@0 1436 PKIX_COMCERTSELPARAMSSETSUBJKEYIDENTIFIERFAILED);
michael@0 1437 }
michael@0 1438
michael@0 1439 PKIX_INCREF(state->buildConstants.testDate);
michael@0 1440 testDate = state->buildConstants.testDate;
michael@0 1441
michael@0 1442 PKIX_CHECK(PKIX_ComCertSelParams_SetCertificateValid
michael@0 1443 (certSelParams, testDate, plContext),
michael@0 1444 PKIX_COMCERTSELPARAMSSETCERTIFICATEVALIDFAILED);
michael@0 1445
michael@0 1446 PKIX_CHECK(PKIX_ComCertSelParams_SetBasicConstraints
michael@0 1447 (certSelParams, state->traversedCACerts, plContext),
michael@0 1448 PKIX_COMCERTSELPARAMSSETBASICCONSTRAINTSFAILED);
michael@0 1449
michael@0 1450 PKIX_CHECK(PKIX_ComCertSelParams_SetPathToNames
michael@0 1451 (certSelParams, state->traversedSubjNames, plContext),
michael@0 1452 PKIX_COMCERTSELPARAMSSETPATHTONAMESFAILED);
michael@0 1453
michael@0 1454 PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
michael@0 1455 (state->buildConstants.procParams,
michael@0 1456 &callerCertSelector, plContext),
michael@0 1457 PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
michael@0 1458
michael@0 1459 if (callerCertSelector != NULL) {
michael@0 1460
michael@0 1461 /* Get initial EKU OIDs from ComCertSelParams, if set */
michael@0 1462 PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
michael@0 1463 (callerCertSelector, &callerComCertSelParams, plContext),
michael@0 1464 PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
michael@0 1465
michael@0 1466 if (callerComCertSelParams != NULL) {
michael@0 1467 PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage
michael@0 1468 (callerComCertSelParams, &reqEkuOids, plContext),
michael@0 1469 PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED);
michael@0 1470
michael@0 1471 PKIX_CHECK(PKIX_ComCertSelParams_GetKeyUsage
michael@0 1472 (callerComCertSelParams, &reqKu, plContext),
michael@0 1473 PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED);
michael@0 1474 }
michael@0 1475 }
michael@0 1476
michael@0 1477 PKIX_CHECK(
michael@0 1478 PKIX_ComCertSelParams_SetKeyUsage(certSelParams, reqKu,
michael@0 1479 plContext),
michael@0 1480 PKIX_COMCERTSELPARAMSSETKEYUSAGEFAILED);
michael@0 1481
michael@0 1482 PKIX_CHECK(
michael@0 1483 PKIX_ComCertSelParams_SetExtendedKeyUsage(certSelParams,
michael@0 1484 reqEkuOids,
michael@0 1485 plContext),
michael@0 1486 PKIX_COMCERTSELPARAMSSETEXTKEYUSAGEFAILED);
michael@0 1487
michael@0 1488 PKIX_CHECK(PKIX_CertSelector_Create
michael@0 1489 (NULL, NULL, &state->certSel, plContext),
michael@0 1490 PKIX_CERTSELECTORCREATEFAILED);
michael@0 1491
michael@0 1492 PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
michael@0 1493 (state->certSel, certSelParams, plContext),
michael@0 1494 PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
michael@0 1495
michael@0 1496 PKIX_CHECK(PKIX_List_Create(&state->candidateCerts, plContext),
michael@0 1497 PKIX_LISTCREATEFAILED);
michael@0 1498
michael@0 1499 state->certStoreIndex = 0;
michael@0 1500
michael@0 1501 cleanup:
michael@0 1502 PKIX_DECREF(certSelParams);
michael@0 1503 PKIX_DECREF(certSel);
michael@0 1504 PKIX_DECREF(currentIssuer);
michael@0 1505 PKIX_DECREF(authKeyId);
michael@0 1506 PKIX_DECREF(testDate);
michael@0 1507 PKIX_DECREF(reqEkuOids);
michael@0 1508 PKIX_DECREF(callerComCertSelParams);
michael@0 1509 PKIX_DECREF(callerCertSelector);
michael@0 1510
michael@0 1511 PKIX_RETURN(BUILD);
michael@0 1512 }
michael@0 1513
michael@0 1514 /* Match trust anchor to select params in order to find next cert. */
michael@0 1515 static PKIX_Error*
michael@0 1516 pkix_Build_SelectCertsFromTrustAnchors(
michael@0 1517 PKIX_List *trustAnchorsList,
michael@0 1518 PKIX_ComCertSelParams *certSelParams,
michael@0 1519 PKIX_List **pMatchList,
michael@0 1520 void *plContext)
michael@0 1521 {
michael@0 1522 int anchorIndex = 0;
michael@0 1523 PKIX_TrustAnchor *anchor = NULL;
michael@0 1524 PKIX_PL_Cert *trustedCert = NULL;
michael@0 1525 PKIX_List *matchList = NULL;
michael@0 1526 PKIX_CertSelector *certSel = NULL;
michael@0 1527 PKIX_CertSelector_MatchCallback selectorMatchCB = NULL;
michael@0 1528
michael@0 1529 PKIX_ENTER(BUILD, "pkix_Build_SelectCertsFromTrustAnchors");
michael@0 1530
michael@0 1531 PKIX_CHECK(PKIX_CertSelector_Create
michael@0 1532 (NULL, NULL, &certSel, plContext),
michael@0 1533 PKIX_CERTSELECTORCREATEFAILED);
michael@0 1534 PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
michael@0 1535 (certSel, certSelParams, plContext),
michael@0 1536 PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
michael@0 1537 PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
michael@0 1538 (certSel, &selectorMatchCB, plContext),
michael@0 1539 PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
michael@0 1540
michael@0 1541 for (anchorIndex = 0;anchorIndex < trustAnchorsList->length; anchorIndex++) {
michael@0 1542 PKIX_CHECK(
michael@0 1543 PKIX_List_GetItem(trustAnchorsList,
michael@0 1544 anchorIndex,
michael@0 1545 (PKIX_PL_Object **)&anchor,
michael@0 1546 plContext),
michael@0 1547 PKIX_LISTGETITEMFAILED);
michael@0 1548 PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
michael@0 1549 (anchor, &trustedCert, plContext),
michael@0 1550 PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
michael@0 1551 pkixErrorResult =
michael@0 1552 (*selectorMatchCB)(certSel, trustedCert, plContext);
michael@0 1553 if (!pkixErrorResult) {
michael@0 1554 if (!matchList) {
michael@0 1555 PKIX_CHECK(PKIX_List_Create(&matchList,
michael@0 1556 plContext),
michael@0 1557 PKIX_LISTCREATEFAILED);
michael@0 1558 }
michael@0 1559 PKIX_CHECK(
michael@0 1560 PKIX_List_AppendItem(matchList,
michael@0 1561 (PKIX_PL_Object*)trustedCert,
michael@0 1562 plContext),
michael@0 1563 PKIX_LISTAPPENDITEMFAILED);
michael@0 1564 } else {
michael@0 1565 PKIX_DECREF(pkixErrorResult);
michael@0 1566 }
michael@0 1567 PKIX_DECREF(trustedCert);
michael@0 1568 PKIX_DECREF(anchor);
michael@0 1569 }
michael@0 1570
michael@0 1571 *pMatchList = matchList;
michael@0 1572 matchList = NULL;
michael@0 1573
michael@0 1574 cleanup:
michael@0 1575 PKIX_DECREF(matchList);
michael@0 1576 PKIX_DECREF(trustedCert);
michael@0 1577 PKIX_DECREF(anchor);
michael@0 1578 PKIX_DECREF(certSel);
michael@0 1579
michael@0 1580 PKIX_RETURN(BUILD);
michael@0 1581 }
michael@0 1582
michael@0 1583
michael@0 1584 static PKIX_Error*
michael@0 1585 pkix_Build_RemoveDupUntrustedCerts(
michael@0 1586 PKIX_List *trustedCertList,
michael@0 1587 PKIX_List *certsFound,
michael@0 1588 void *plContext)
michael@0 1589 {
michael@0 1590 PKIX_UInt32 trustIndex;
michael@0 1591 PKIX_PL_Cert *trustCert = NULL, *cert = NULL;
michael@0 1592
michael@0 1593 PKIX_ENTER(BUILD, "pkix_Build_RemoveDupUntrustedCerts");
michael@0 1594 if (trustedCertList == NULL || certsFound == NULL) {
michael@0 1595 goto cleanup;
michael@0 1596 }
michael@0 1597 for (trustIndex = 0;trustIndex < trustedCertList->length;
michael@0 1598 trustIndex++) {
michael@0 1599 PKIX_UInt32 certIndex = 0;
michael@0 1600 PKIX_CHECK(
michael@0 1601 PKIX_List_GetItem(trustedCertList,
michael@0 1602 trustIndex,
michael@0 1603 (PKIX_PL_Object **)&trustCert,
michael@0 1604 plContext),
michael@0 1605 PKIX_LISTGETITEMFAILED);
michael@0 1606
michael@0 1607 while (certIndex < certsFound->length) {
michael@0 1608 PKIX_Boolean result = PKIX_FALSE;
michael@0 1609 PKIX_DECREF(cert);
michael@0 1610 PKIX_CHECK(
michael@0 1611 PKIX_List_GetItem(certsFound, certIndex,
michael@0 1612 (PKIX_PL_Object **)&cert,
michael@0 1613 plContext),
michael@0 1614 PKIX_LISTGETITEMFAILED);
michael@0 1615 PKIX_CHECK(
michael@0 1616 PKIX_PL_Object_Equals((PKIX_PL_Object *)trustCert,
michael@0 1617 (PKIX_PL_Object *)cert,
michael@0 1618 &result,
michael@0 1619 plContext),
michael@0 1620 PKIX_OBJECTEQUALSFAILED);
michael@0 1621 if (!result) {
michael@0 1622 certIndex += 1;
michael@0 1623 continue;
michael@0 1624 }
michael@0 1625 PKIX_CHECK(
michael@0 1626 PKIX_List_DeleteItem(certsFound, certIndex,
michael@0 1627 plContext),
michael@0 1628 PKIX_LISTDELETEITEMFAILED);
michael@0 1629 }
michael@0 1630 PKIX_DECREF(trustCert);
michael@0 1631 }
michael@0 1632 cleanup:
michael@0 1633 PKIX_DECREF(cert);
michael@0 1634 PKIX_DECREF(trustCert);
michael@0 1635
michael@0 1636 PKIX_RETURN(BUILD);
michael@0 1637 }
michael@0 1638
michael@0 1639
michael@0 1640 /*
michael@0 1641 * FUNCTION: pkix_Build_GatherCerts
michael@0 1642 * DESCRIPTION:
michael@0 1643 *
michael@0 1644 * This function traverses the CertStores in the List of CertStores contained
michael@0 1645 * in "state", using the certSelector and other parameters contained in
michael@0 1646 * "state", to obtain a List of all available Certs that satisfy the criteria.
michael@0 1647 * If a CertStore has a cache, "certSelParams" is used both to query the cache
michael@0 1648 * and, if an actual CertStore search occurred, to update the cache. (Behavior
michael@0 1649 * is undefined if "certSelParams" is different from the parameters that were
michael@0 1650 * used to initialize the certSelector in "state".)
michael@0 1651 *
michael@0 1652 * If a CertStore using non-blocking I/O returns with an indication that I/O is
michael@0 1653 * in progress and the checking has not been completed, this function stores
michael@0 1654 * platform-dependent information at "pNBIOContext". Otherwise it stores NULL
michael@0 1655 * at "pNBIOContext", and state is updated with the results of the search.
michael@0 1656 *
michael@0 1657 * PARAMETERS:
michael@0 1658 * "state"
michael@0 1659 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 1660 * "certSelParams"
michael@0 1661 * Address of ComCertSelParams which were used in creating the current
michael@0 1662 * CertSelector, and to be used in querying and updating any caches that
michael@0 1663 * may be associated with with the CertStores.
michael@0 1664 * "pNBIOContext"
michael@0 1665 * Address at which platform-dependent information is returned if request
michael@0 1666 * is suspended for non-blocking I/O. Must be non-NULL.
michael@0 1667 * "plContext"
michael@0 1668 * Platform-specific context pointer.
michael@0 1669 * THREAD SAFETY:
michael@0 1670 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 1671 * RETURNS:
michael@0 1672 * Returns NULL if the function succeeds.
michael@0 1673 * Returns a Build Error if the function fails in a non-fatal way
michael@0 1674 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 1675 */
michael@0 1676 /* return NULL if wouldblock, empty list if none found, else list of found */
michael@0 1677 static PKIX_Error *
michael@0 1678 pkix_Build_GatherCerts(
michael@0 1679 PKIX_ForwardBuilderState *state,
michael@0 1680 PKIX_ComCertSelParams *certSelParams,
michael@0 1681 void **pNBIOContext,
michael@0 1682 void *plContext)
michael@0 1683 {
michael@0 1684 PKIX_Boolean certStoreIsCached = PKIX_FALSE;
michael@0 1685 PKIX_Boolean certStoreIsLocal = PKIX_FALSE;
michael@0 1686 PKIX_Boolean foundInCache = PKIX_FALSE;
michael@0 1687 PKIX_CertStore *certStore = NULL;
michael@0 1688 PKIX_CertStore_CertCallback getCerts = NULL;
michael@0 1689 PKIX_List *certsFound = NULL;
michael@0 1690 PKIX_List *trustedCertList = NULL;
michael@0 1691 void *nbioContext = NULL;
michael@0 1692
michael@0 1693 PKIX_ENTER(BUILD, "pkix_Build_GatherCerts");
michael@0 1694 PKIX_NULLCHECK_THREE(state, certSelParams, pNBIOContext);
michael@0 1695
michael@0 1696 nbioContext = *pNBIOContext;
michael@0 1697 *pNBIOContext = NULL;
michael@0 1698
michael@0 1699 PKIX_DECREF(state->candidateCerts);
michael@0 1700
michael@0 1701 while (state->certStoreIndex < state->buildConstants.numCertStores) {
michael@0 1702
michael@0 1703 /* Get the current CertStore */
michael@0 1704 PKIX_CHECK(PKIX_List_GetItem
michael@0 1705 (state->buildConstants.certStores,
michael@0 1706 state->certStoreIndex,
michael@0 1707 (PKIX_PL_Object **)&certStore,
michael@0 1708 plContext),
michael@0 1709 PKIX_LISTGETITEMFAILED);
michael@0 1710
michael@0 1711 PKIX_CHECK(PKIX_CertStore_GetLocalFlag
michael@0 1712 (certStore, &certStoreIsLocal, plContext),
michael@0 1713 PKIX_CERTSTOREGETLOCALFLAGFAILED);
michael@0 1714
michael@0 1715 if (state->useOnlyLocal == certStoreIsLocal) {
michael@0 1716 /* If GATHERPENDING, we've already checked the cache */
michael@0 1717 if (state->status == BUILD_GATHERPENDING) {
michael@0 1718 certStoreIsCached = PKIX_FALSE;
michael@0 1719 foundInCache = PKIX_FALSE;
michael@0 1720 } else {
michael@0 1721 PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
michael@0 1722 (certStore, &certStoreIsCached, plContext),
michael@0 1723 PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
michael@0 1724
michael@0 1725 if (certStoreIsCached) {
michael@0 1726 /*
michael@0 1727 * Look for Certs in the cache, using the SubjectName as
michael@0 1728 * the key. Then the ComCertSelParams are used to filter
michael@0 1729 * for qualified certs. If none are found, then the
michael@0 1730 * certStores are queried. When we eventually add items
michael@0 1731 * to the cache, we will only add items that passed the
michael@0 1732 * ComCertSelParams filter, rather than all Certs which
michael@0 1733 * matched the SubjectName.
michael@0 1734 */
michael@0 1735
michael@0 1736 PKIX_CHECK(pkix_CacheCert_Lookup
michael@0 1737 (certStore,
michael@0 1738 certSelParams,
michael@0 1739 state->buildConstants.testDate,
michael@0 1740 &foundInCache,
michael@0 1741 &certsFound,
michael@0 1742 plContext),
michael@0 1743 PKIX_CACHECERTCHAINLOOKUPFAILED);
michael@0 1744
michael@0 1745 }
michael@0 1746 }
michael@0 1747
michael@0 1748 /*
michael@0 1749 * XXX need to verify if Cert is trusted, hence may not
michael@0 1750 * be worth it to have the Cert Cached or
michael@0 1751 * If it is trusted, don't cache, but once there is cached
michael@0 1752 * certs, we won't get certs from database any more.
michael@0 1753 * can use flag to force not getting certs from cache
michael@0 1754 */
michael@0 1755 if (!foundInCache) {
michael@0 1756
michael@0 1757 if (nbioContext == NULL) {
michael@0 1758 PKIX_CHECK(PKIX_CertStore_GetCertCallback
michael@0 1759 (certStore, &getCerts, plContext),
michael@0 1760 PKIX_CERTSTOREGETCERTCALLBACKFAILED);
michael@0 1761
michael@0 1762 PKIX_CHECK(getCerts
michael@0 1763 (certStore,
michael@0 1764 state->certSel,
michael@0 1765 state->verifyNode,
michael@0 1766 &nbioContext,
michael@0 1767 &certsFound,
michael@0 1768 plContext),
michael@0 1769 PKIX_GETCERTSFAILED);
michael@0 1770 } else {
michael@0 1771 PKIX_CHECK(PKIX_CertStore_CertContinue
michael@0 1772 (certStore,
michael@0 1773 state->certSel,
michael@0 1774 state->verifyNode,
michael@0 1775 &nbioContext,
michael@0 1776 &certsFound,
michael@0 1777 plContext),
michael@0 1778 PKIX_CERTSTORECERTCONTINUEFAILED);
michael@0 1779 }
michael@0 1780
michael@0 1781 if (certStoreIsCached && certsFound) {
michael@0 1782
michael@0 1783 PKIX_CHECK(pkix_CacheCert_Add
michael@0 1784 (certStore,
michael@0 1785 certSelParams,
michael@0 1786 certsFound,
michael@0 1787 plContext),
michael@0 1788 PKIX_CACHECERTADDFAILED);
michael@0 1789 }
michael@0 1790 }
michael@0 1791
michael@0 1792 /*
michael@0 1793 * getCerts returns an empty list for "NONE FOUND",
michael@0 1794 * a NULL list for "would block"
michael@0 1795 */
michael@0 1796 if (certsFound == NULL) {
michael@0 1797 state->status = BUILD_GATHERPENDING;
michael@0 1798 *pNBIOContext = nbioContext;
michael@0 1799 goto cleanup;
michael@0 1800 }
michael@0 1801 }
michael@0 1802
michael@0 1803 /* Are there any more certStores to query? */
michael@0 1804 PKIX_DECREF(certStore);
michael@0 1805 ++(state->certStoreIndex);
michael@0 1806 }
michael@0 1807
michael@0 1808 if (certsFound && certsFound->length > 1) {
michael@0 1809 PKIX_List *sorted = NULL;
michael@0 1810
michael@0 1811 /* sort Certs to try to optimize search */
michael@0 1812 PKIX_CHECK(pkix_Build_SortCandidateCerts
michael@0 1813 (certsFound, &sorted, plContext),
michael@0 1814 PKIX_BUILDSORTCANDIDATECERTSFAILED);
michael@0 1815 PKIX_DECREF(certsFound);
michael@0 1816 certsFound = sorted;
michael@0 1817 }
michael@0 1818
michael@0 1819 PKIX_CHECK(
michael@0 1820 pkix_Build_SelectCertsFromTrustAnchors(
michael@0 1821 state->buildConstants.anchors,
michael@0 1822 certSelParams, &trustedCertList,
michael@0 1823 plContext),
michael@0 1824 PKIX_FAILTOSELECTCERTSFROMANCHORS);
michael@0 1825 PKIX_CHECK(
michael@0 1826 pkix_Build_RemoveDupUntrustedCerts(trustedCertList,
michael@0 1827 certsFound,
michael@0 1828 plContext),
michael@0 1829 PKIX_REMOVEDUPUNTRUSTEDCERTSFAILED);
michael@0 1830
michael@0 1831 PKIX_CHECK(
michael@0 1832 pkix_List_MergeLists(trustedCertList,
michael@0 1833 certsFound,
michael@0 1834 &state->candidateCerts,
michael@0 1835 plContext),
michael@0 1836 PKIX_LISTMERGEFAILED);
michael@0 1837
michael@0 1838 /* No, return the list we have gathered */
michael@0 1839 PKIX_CHECK(PKIX_List_GetLength
michael@0 1840 (state->candidateCerts, &state->numCerts, plContext),
michael@0 1841 PKIX_LISTGETLENGTHFAILED);
michael@0 1842
michael@0 1843 state->certIndex = 0;
michael@0 1844
michael@0 1845 cleanup:
michael@0 1846 PKIX_DECREF(trustedCertList);
michael@0 1847 PKIX_DECREF(certStore);
michael@0 1848 PKIX_DECREF(certsFound);
michael@0 1849
michael@0 1850 PKIX_RETURN(BUILD);
michael@0 1851 }
michael@0 1852
michael@0 1853 /*
michael@0 1854 * FUNCTION: pkix_Build_UpdateDate
michael@0 1855 * DESCRIPTION:
michael@0 1856 *
michael@0 1857 * This function updates the validityDate contained in "state", for the current
michael@0 1858 * CertChain contained in "state", to include the validityDate of the
michael@0 1859 * candidateCert contained in "state". The validityDate of a chain is the
michael@0 1860 * earliest of all the notAfter dates contained in the respective Certificates.
michael@0 1861 *
michael@0 1862 * PARAMETERS:
michael@0 1863 * "state"
michael@0 1864 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 1865 * "plContext"
michael@0 1866 * Platform-specific context pointer.
michael@0 1867 * THREAD SAFETY:
michael@0 1868 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 1869 * RETURNS:
michael@0 1870 * Returns NULL if the function succeeds.
michael@0 1871 * Returns a Build Error if the function fails in a non-fatal way
michael@0 1872 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 1873 */
michael@0 1874 static PKIX_Error *
michael@0 1875 pkix_Build_UpdateDate(
michael@0 1876 PKIX_ForwardBuilderState *state,
michael@0 1877 void *plContext)
michael@0 1878 {
michael@0 1879 PKIX_Boolean canBeCached = PKIX_FALSE;
michael@0 1880 PKIX_Int32 comparison = 0;
michael@0 1881 PKIX_PL_Date *notAfter = NULL;
michael@0 1882
michael@0 1883 PKIX_ENTER(BUILD, "pkix_Build_UpdateDate");
michael@0 1884 PKIX_NULLCHECK_ONE(state);
michael@0 1885
michael@0 1886 PKIX_CHECK(PKIX_PL_Cert_GetCacheFlag
michael@0 1887 (state->candidateCert, &canBeCached, plContext),
michael@0 1888 PKIX_CERTGETCACHEFLAGFAILED);
michael@0 1889
michael@0 1890 state->canBeCached = state->canBeCached && canBeCached;
michael@0 1891 if (state->canBeCached == PKIX_TRUE) {
michael@0 1892
michael@0 1893 /*
michael@0 1894 * So far, all certs can be cached. Update cert
michael@0 1895 * chain validity time, which is the earliest of
michael@0 1896 * all certs' notAfter times.
michael@0 1897 */
michael@0 1898 PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
michael@0 1899 (state->candidateCert, &notAfter, plContext),
michael@0 1900 PKIX_CERTGETVALIDITYNOTAFTERFAILED);
michael@0 1901
michael@0 1902 if (state->validityDate == NULL) {
michael@0 1903 state->validityDate = notAfter;
michael@0 1904 notAfter = NULL;
michael@0 1905 } else {
michael@0 1906 PKIX_CHECK(PKIX_PL_Object_Compare
michael@0 1907 ((PKIX_PL_Object *)state->validityDate,
michael@0 1908 (PKIX_PL_Object *)notAfter,
michael@0 1909 &comparison,
michael@0 1910 plContext),
michael@0 1911 PKIX_OBJECTCOMPARATORFAILED);
michael@0 1912 if (comparison > 0) {
michael@0 1913 PKIX_DECREF(state->validityDate);
michael@0 1914 state->validityDate = notAfter;
michael@0 1915 notAfter = NULL;
michael@0 1916 }
michael@0 1917 }
michael@0 1918 }
michael@0 1919
michael@0 1920 cleanup:
michael@0 1921
michael@0 1922 PKIX_DECREF(notAfter);
michael@0 1923
michael@0 1924 PKIX_RETURN(BUILD);
michael@0 1925 }
michael@0 1926
michael@0 1927 /* Prepare 'state' for the AIA round. */
michael@0 1928 static void
michael@0 1929 pkix_PrepareForwardBuilderStateForAIA(
michael@0 1930 PKIX_ForwardBuilderState *state)
michael@0 1931 {
michael@0 1932 PORT_Assert(state->useOnlyLocal == PKIX_TRUE);
michael@0 1933 state->useOnlyLocal = PKIX_FALSE;
michael@0 1934 state->certStoreIndex = 0;
michael@0 1935 state->numFanout = state->buildConstants.maxFanout;
michael@0 1936 state->status = BUILD_TRYAIA;
michael@0 1937 }
michael@0 1938
michael@0 1939 /*
michael@0 1940 * FUNCTION: pkix_BuildForwardDepthFirstSearch
michael@0 1941 * DESCRIPTION:
michael@0 1942 *
michael@0 1943 * This function performs a depth first search in the "forward" direction (from
michael@0 1944 * the target Cert to the trust anchor). A non-NULL targetCert must be stored
michael@0 1945 * in the ForwardBuilderState before this function is called. It is not written
michael@0 1946 * recursively since execution may be suspended in in any of several places
michael@0 1947 * pending completion of non-blocking I/O. This iterative structure makes it
michael@0 1948 * much easier to resume where it left off.
michael@0 1949 *
michael@0 1950 * Since the nature of the search is recursive, the recursion is handled by
michael@0 1951 * chaining states. That is, each new step involves creating a new
michael@0 1952 * ForwardBuilderState linked to its predecessor. If a step turns out to be
michael@0 1953 * fruitless, the state of the predecessor is restored and the next alternative
michael@0 1954 * is tried. When a search is successful, values needed from the last state
michael@0 1955 * (canBeCached and validityDate) are copied to the state provided by the
michael@0 1956 * caller, so that the caller can retrieve those values.
michael@0 1957 *
michael@0 1958 * There are three return arguments, the NBIOContext, the ValidateResult and
michael@0 1959 * the ForwardBuilderState. If NBIOContext is non-NULL, it means the search is
michael@0 1960 * suspended until the results of a non-blocking IO become available. The
michael@0 1961 * caller may wait for the completion using platform-dependent methods and then
michael@0 1962 * call this function again, allowing it to resume the search. If NBIOContext
michael@0 1963 * is NULL and the ValidateResult is non-NULL, it means the search has
michael@0 1964 * concluded successfully. If the NBIOContext is NULL but the ValidateResult is
michael@0 1965 * NULL, it means the search was unsuccessful.
michael@0 1966 *
michael@0 1967 * This function performs several steps at each node in the constructed chain:
michael@0 1968 *
michael@0 1969 * 1) It retrieves Certs from the registered CertStores that match the
michael@0 1970 * criteria established by the ForwardBuilderState pointed to by "state", such
michael@0 1971 * as a subject name matching the issuer name of the previous Cert. If there
michael@0 1972 * are no matching Certs, the function returns to the previous, or "parent",
michael@0 1973 * state and tries to continue the chain building with another of the Certs
michael@0 1974 * obtained from the CertStores as possible issuers for that parent Cert.
michael@0 1975 *
michael@0 1976 * 2) For each candidate Cert returned by the CertStores, this function checks
michael@0 1977 * whether the Cert is valid. If it is trusted, this function checks whether
michael@0 1978 * this Cert might serve as a TrustAnchor for a complete chain.
michael@0 1979 *
michael@0 1980 * 3) It determines whether this Cert, in conjunction with any of the
michael@0 1981 * TrustAnchors, might complete a chain. A complete chain, from this or the
michael@0 1982 * preceding step, is checked to see whether it is valid as a complete
michael@0 1983 * chain, including the checks that cannot be done in the forward direction.
michael@0 1984 *
michael@0 1985 * 4) If this Cert chains successfully, but is not a complete chain, that is,
michael@0 1986 * we have not reached a trusted Cert, a new ForwardBuilderState is created
michael@0 1987 * with this Cert as the immediate predecessor, and we continue in step (1),
michael@0 1988 * attempting to get Certs from the CertStores with this Certs "issuer" as
michael@0 1989 * their subject.
michael@0 1990 *
michael@0 1991 * 5) If an entire chain validates successfully, then we are done. A
michael@0 1992 * ValidateResult is created containing the Public Key of the target
michael@0 1993 * certificate (including DSA parameter inheritance, if any) and the
michael@0 1994 * PolicyNode representing the policy tree output by the validation algorithm,
michael@0 1995 * and stored at pValResult, and the function exits returning NULL.
michael@0 1996 *
michael@0 1997 * 5) If the entire chain does not validate successfully, the algorithm
michael@0 1998 * discards the latest Cert and continues in step 2 with the next candidate
michael@0 1999 * Cert, backing up to a parent state when no more possibilities exist at a
michael@0 2000 * given level, and returning failure when we try to back up but discover we
michael@0 2001 * are at the top level.
michael@0 2002 *
michael@0 2003 * PARAMETERS:
michael@0 2004 * "pNBIOContext"
michael@0 2005 * Address at which platform-dependent information is returned if building
michael@0 2006 * is suspended for non-blocking I/O. Must be non-NULL.
michael@0 2007 * "pState"
michael@0 2008 * Address at which input ForwardBuilderState is found, and at which output
michael@0 2009 * ForwardBuilderState is stored. Must be non-NULL.
michael@0 2010 * "pValResult"
michael@0 2011 * Address at which the ValidateResult is stored. Must be non-NULL.
michael@0 2012 * "plContext"
michael@0 2013 * Platform-specific context pointer.
michael@0 2014 * THREAD SAFETY:
michael@0 2015 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 2016 * RETURNS:
michael@0 2017 * Returns NULL if the function succeeds.
michael@0 2018 * Returns a Build Error if the function fails in a non-fatal way.
michael@0 2019 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 2020 */
michael@0 2021 static PKIX_Error *
michael@0 2022 pkix_BuildForwardDepthFirstSearch(
michael@0 2023 void **pNBIOContext,
michael@0 2024 PKIX_ForwardBuilderState *state,
michael@0 2025 PKIX_ValidateResult **pValResult,
michael@0 2026 void *plContext)
michael@0 2027 {
michael@0 2028 PKIX_Boolean outOfOptions = PKIX_FALSE;
michael@0 2029 PKIX_Boolean trusted = PKIX_FALSE;
michael@0 2030 PKIX_Boolean isSelfIssued = PKIX_FALSE;
michael@0 2031 PKIX_Boolean canBeCached = PKIX_FALSE;
michael@0 2032 PKIX_Boolean ioPending = PKIX_FALSE;
michael@0 2033 PKIX_PL_Date *validityDate = NULL;
michael@0 2034 PKIX_PL_Date *currTime = NULL;
michael@0 2035 PKIX_Int32 childTraversedCACerts = 0;
michael@0 2036 PKIX_UInt32 numSubjectNames = 0;
michael@0 2037 PKIX_UInt32 numChained = 0;
michael@0 2038 PKIX_Int32 cmpTimeResult = 0;
michael@0 2039 PKIX_UInt32 i = 0;
michael@0 2040 PKIX_UInt32 certsSoFar = 0;
michael@0 2041 PKIX_List *childTraversedSubjNames = NULL;
michael@0 2042 PKIX_List *subjectNames = NULL;
michael@0 2043 PKIX_List *unfilteredCerts = NULL;
michael@0 2044 PKIX_List *filteredCerts = NULL;
michael@0 2045 PKIX_PL_Object *subjectName = NULL;
michael@0 2046 PKIX_ValidateResult *valResult = NULL;
michael@0 2047 PKIX_ForwardBuilderState *childState = NULL;
michael@0 2048 PKIX_ForwardBuilderState *parentState = NULL;
michael@0 2049 PKIX_PL_Object *revCheckerState = NULL;
michael@0 2050 PKIX_ComCertSelParams *certSelParams = NULL;
michael@0 2051 PKIX_TrustAnchor *trustAnchor = NULL;
michael@0 2052 PKIX_PL_Cert *trustedCert = NULL;
michael@0 2053 PKIX_VerifyNode *verifyNode = NULL;
michael@0 2054 PKIX_Error *verifyError = NULL;
michael@0 2055 PKIX_Error *finalError = NULL;
michael@0 2056 void *nbio = NULL;
michael@0 2057 PKIX_UInt32 numIterations = 0;
michael@0 2058
michael@0 2059 PKIX_ENTER(BUILD, "pkix_BuildForwardDepthFirstSearch");
michael@0 2060 PKIX_NULLCHECK_THREE(pNBIOContext, state, pValResult);
michael@0 2061
michael@0 2062 nbio = *pNBIOContext;
michael@0 2063 *pNBIOContext = NULL;
michael@0 2064 PKIX_INCREF(state->validityDate);
michael@0 2065 validityDate = state->validityDate;
michael@0 2066 canBeCached = state->canBeCached;
michael@0 2067 PKIX_DECREF(*pValResult);
michael@0 2068
michael@0 2069 /*
michael@0 2070 * We return if successful; if we fall off the end
michael@0 2071 * of this "while" clause our search has failed.
michael@0 2072 */
michael@0 2073 while (outOfOptions == PKIX_FALSE) {
michael@0 2074 /*
michael@0 2075 * The maximum number of iterations works around a bug that
michael@0 2076 * causes this while loop to never exit when AIA and cross
michael@0 2077 * certificates are involved. See bug xxxxx.
michael@0 2078 */
michael@0 2079 if (numIterations++ > 250)
michael@0 2080 PKIX_ERROR(PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS);
michael@0 2081
michael@0 2082 if (state->buildConstants.maxTime != 0) {
michael@0 2083 PKIX_DECREF(currTime);
michael@0 2084 PKIX_CHECK(PKIX_PL_Date_Create_UTCTime
michael@0 2085 (NULL, &currTime, plContext),
michael@0 2086 PKIX_DATECREATEUTCTIMEFAILED);
michael@0 2087
michael@0 2088 PKIX_CHECK(PKIX_PL_Object_Compare
michael@0 2089 ((PKIX_PL_Object *)state->buildConstants.timeLimit,
michael@0 2090 (PKIX_PL_Object *)currTime,
michael@0 2091 &cmpTimeResult,
michael@0 2092 plContext),
michael@0 2093 PKIX_OBJECTCOMPARATORFAILED);
michael@0 2094
michael@0 2095 if (cmpTimeResult < 0) {
michael@0 2096 if (state->verifyNode != NULL) {
michael@0 2097 PKIX_ERROR_CREATE
michael@0 2098 (BUILD,
michael@0 2099 PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS,
michael@0 2100 verifyError);
michael@0 2101 PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
michael@0 2102 (state->verifyNode,
michael@0 2103 verifyError,
michael@0 2104 plContext),
michael@0 2105 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2106 PKIX_DECREF(finalError);
michael@0 2107 finalError = verifyError;
michael@0 2108 verifyError = NULL;
michael@0 2109 }
michael@0 2110 /* Even if we logged error, we still have to abort */
michael@0 2111 PKIX_ERROR(PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS);
michael@0 2112 }
michael@0 2113 }
michael@0 2114
michael@0 2115 if (state->status == BUILD_INITIAL) {
michael@0 2116
michael@0 2117 PKIX_CHECK(pkix_Build_BuildSelectorAndParams(state, plContext),
michael@0 2118 PKIX_BUILDBUILDSELECTORANDPARAMSFAILED);
michael@0 2119
michael@0 2120 /*
michael@0 2121 * If the caller supplied a partial certChain (hintCerts) try
michael@0 2122 * the next one from that List before we go to the certStores.
michael@0 2123 */
michael@0 2124 if (state->buildConstants.numHintCerts > 0) {
michael@0 2125 /* How many Certs does our trust chain have already? */
michael@0 2126 PKIX_CHECK(PKIX_List_GetLength
michael@0 2127 (state->trustChain, &certsSoFar, plContext),
michael@0 2128 PKIX_LISTGETLENGTHFAILED);
michael@0 2129
michael@0 2130 /* That includes the target Cert. Don't count it. */
michael@0 2131 certsSoFar--;
michael@0 2132
michael@0 2133 /* Are we still within range of the partial chain? */
michael@0 2134 if (certsSoFar >= state->buildConstants.numHintCerts) {
michael@0 2135 state->status = BUILD_TRYAIA;
michael@0 2136 } else {
michael@0 2137 /*
michael@0 2138 * If we already have n certs, we want the n+1th
michael@0 2139 * (i.e., index = n) from the list of hints.
michael@0 2140 */
michael@0 2141 PKIX_DECREF(state->candidateCert);
michael@0 2142 PKIX_CHECK(PKIX_List_GetItem
michael@0 2143 (state->buildConstants.hintCerts,
michael@0 2144 certsSoFar,
michael@0 2145 (PKIX_PL_Object **)&state->candidateCert,
michael@0 2146 plContext),
michael@0 2147 PKIX_LISTGETITEMFAILED);
michael@0 2148
michael@0 2149 PKIX_CHECK(PKIX_List_AppendItem
michael@0 2150 (state->candidateCerts,
michael@0 2151 (PKIX_PL_Object *)state->candidateCert,
michael@0 2152 plContext),
michael@0 2153 PKIX_LISTAPPENDITEMFAILED);
michael@0 2154
michael@0 2155 state->numCerts = 1;
michael@0 2156 state->usingHintCerts = PKIX_TRUE;
michael@0 2157 state->status = BUILD_CERTVALIDATING;
michael@0 2158 }
michael@0 2159 } else {
michael@0 2160 state->status = BUILD_TRYAIA;
michael@0 2161 }
michael@0 2162
michael@0 2163 }
michael@0 2164
michael@0 2165 if (state->status == BUILD_TRYAIA) {
michael@0 2166 if (state->useOnlyLocal == PKIX_TRUE) {
michael@0 2167 state->status = BUILD_COLLECTINGCERTS;
michael@0 2168 } else {
michael@0 2169 state->status = BUILD_AIAPENDING;
michael@0 2170 }
michael@0 2171 }
michael@0 2172
michael@0 2173 if (state->status == BUILD_AIAPENDING &&
michael@0 2174 state->buildConstants.aiaMgr) {
michael@0 2175 pkixErrorResult = PKIX_PL_AIAMgr_GetAIACerts
michael@0 2176 (state->buildConstants.aiaMgr,
michael@0 2177 state->prevCert,
michael@0 2178 &nbio,
michael@0 2179 &unfilteredCerts,
michael@0 2180 plContext);
michael@0 2181
michael@0 2182 if (nbio != NULL) {
michael@0 2183 /* IO still pending, resume later */
michael@0 2184 *pNBIOContext = nbio;
michael@0 2185 goto cleanup;
michael@0 2186 }
michael@0 2187 state->numCerts = 0;
michael@0 2188 if (pkixErrorResult) {
michael@0 2189 pkixErrorClass = pkixErrorResult->errClass;
michael@0 2190 if (pkixErrorClass == PKIX_FATAL_ERROR) {
michael@0 2191 goto fatal;
michael@0 2192 }
michael@0 2193 PKIX_DECREF(finalError);
michael@0 2194 finalError = pkixErrorResult;
michael@0 2195 pkixErrorResult = NULL;
michael@0 2196 if (state->verifyNode != NULL) {
michael@0 2197 /* state->verifyNode is the object that contains a list
michael@0 2198 * of verifyNodes. verifyNodes contains cert chain
michael@0 2199 * build failures that occurred on this level of chain
michael@0 2200 * building. Here, creating new verify node
michael@0 2201 * to log the failure and adding it to the list. */
michael@0 2202 PKIX_CHECK_FATAL(pkix_VerifyNode_Create
michael@0 2203 (state->prevCert,
michael@0 2204 0, NULL,
michael@0 2205 &verifyNode,
michael@0 2206 plContext),
michael@0 2207 PKIX_VERIFYNODECREATEFAILED);
michael@0 2208 PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
michael@0 2209 (verifyNode, finalError, plContext),
michael@0 2210 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2211 PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
michael@0 2212 (state->verifyNode,
michael@0 2213 verifyNode,
michael@0 2214 plContext),
michael@0 2215 PKIX_VERIFYNODEADDTOTREEFAILED);
michael@0 2216 PKIX_DECREF(verifyNode);
michael@0 2217 }
michael@0 2218 }
michael@0 2219 #ifdef PKIX_BUILDDEBUG
michael@0 2220 /* Turn this on to trace the List of Certs, before CertSelect */
michael@0 2221 {
michael@0 2222 PKIX_PL_String *unString;
michael@0 2223 char *unAscii;
michael@0 2224 PKIX_UInt32 length;
michael@0 2225 PKIX_TOSTRING
michael@0 2226 ((PKIX_PL_Object*)unfilteredCerts,
michael@0 2227 &unString,
michael@0 2228 plContext,
michael@0 2229 PKIX_OBJECTTOSTRINGFAILED);
michael@0 2230
michael@0 2231 PKIX_CHECK(PKIX_PL_String_GetEncoded
michael@0 2232 (unString,
michael@0 2233 PKIX_ESCASCII,
michael@0 2234 (void **)&unAscii,
michael@0 2235 &length,
michael@0 2236 plContext),
michael@0 2237 PKIX_STRINGGETENCODEDFAILED);
michael@0 2238
michael@0 2239 PKIX_DEBUG_ARG
michael@0 2240 ("unfilteredCerts = %s\n", unAscii);
michael@0 2241 PKIX_DECREF(unString);
michael@0 2242 PKIX_FREE(unAscii);
michael@0 2243 }
michael@0 2244 #endif
michael@0 2245
michael@0 2246 /* Note: Certs winnowed here don't get into VerifyTree. */
michael@0 2247 if (unfilteredCerts) {
michael@0 2248 PKIX_CHECK(pkix_CertSelector_Select
michael@0 2249 (state->certSel,
michael@0 2250 unfilteredCerts,
michael@0 2251 &filteredCerts,
michael@0 2252 plContext),
michael@0 2253 PKIX_CERTSELECTORSELECTFAILED);
michael@0 2254
michael@0 2255 PKIX_DECREF(unfilteredCerts);
michael@0 2256
michael@0 2257 PKIX_CHECK(PKIX_List_GetLength
michael@0 2258 (filteredCerts, &(state->numCerts), plContext),
michael@0 2259 PKIX_LISTGETLENGTHFAILED);
michael@0 2260
michael@0 2261 #ifdef PKIX_BUILDDEBUG
michael@0 2262 /* Turn this on to trace the List of Certs, after CertSelect */
michael@0 2263 {
michael@0 2264 PKIX_PL_String *unString;
michael@0 2265 char *unAscii;
michael@0 2266 PKIX_UInt32 length;
michael@0 2267 PKIX_TOSTRING
michael@0 2268 ((PKIX_PL_Object*)filteredCerts,
michael@0 2269 &unString,
michael@0 2270 plContext,
michael@0 2271 PKIX_OBJECTTOSTRINGFAILED);
michael@0 2272
michael@0 2273 PKIX_CHECK(PKIX_PL_String_GetEncoded
michael@0 2274 (unString,
michael@0 2275 PKIX_ESCASCII,
michael@0 2276 (void **)&unAscii,
michael@0 2277 &length,
michael@0 2278 plContext),
michael@0 2279 PKIX_STRINGGETENCODEDFAILED);
michael@0 2280
michael@0 2281 PKIX_DEBUG_ARG("filteredCerts = %s\n", unAscii);
michael@0 2282 PKIX_DECREF(unString);
michael@0 2283 PKIX_FREE(unAscii);
michael@0 2284 }
michael@0 2285 #endif
michael@0 2286
michael@0 2287 PKIX_DECREF(state->candidateCerts);
michael@0 2288 state->candidateCerts = filteredCerts;
michael@0 2289 state->certIndex = 0;
michael@0 2290 filteredCerts = NULL;
michael@0 2291 }
michael@0 2292
michael@0 2293 /* Are there any Certs to try? */
michael@0 2294 if (state->numCerts > 0) {
michael@0 2295 state->status = BUILD_CERTVALIDATING;
michael@0 2296 } else {
michael@0 2297 state->status = BUILD_COLLECTINGCERTS;
michael@0 2298 }
michael@0 2299 }
michael@0 2300
michael@0 2301 PKIX_DECREF(certSelParams);
michael@0 2302 PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
michael@0 2303 (state->certSel, &certSelParams, plContext),
michael@0 2304 PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
michael@0 2305
michael@0 2306 /* **** Querying the CertStores ***** */
michael@0 2307 if ((state->status == BUILD_COLLECTINGCERTS) ||
michael@0 2308 (state->status == BUILD_GATHERPENDING)) {
michael@0 2309
michael@0 2310 #if PKIX_FORWARDBUILDERSTATEDEBUG
michael@0 2311 PKIX_CHECK(pkix_ForwardBuilderState_DumpState
michael@0 2312 (state, plContext),
michael@0 2313 PKIX_FORWARDBUILDERSTATEDUMPSTATEFAILED);
michael@0 2314 #endif
michael@0 2315
michael@0 2316 PKIX_CHECK(pkix_Build_GatherCerts
michael@0 2317 (state, certSelParams, &nbio, plContext),
michael@0 2318 PKIX_BUILDGATHERCERTSFAILED);
michael@0 2319
michael@0 2320 if (nbio != NULL) {
michael@0 2321 /* IO still pending, resume later */
michael@0 2322 *pNBIOContext = nbio;
michael@0 2323 goto cleanup;
michael@0 2324 }
michael@0 2325
michael@0 2326 /* Are there any Certs to try? */
michael@0 2327 if (state->numCerts > 0) {
michael@0 2328 state->status = BUILD_CERTVALIDATING;
michael@0 2329 } else {
michael@0 2330 state->status = BUILD_ABANDONNODE;
michael@0 2331 }
michael@0 2332 }
michael@0 2333
michael@0 2334 /* ****Phase 2 - Chain building***** */
michael@0 2335
michael@0 2336 #if PKIX_FORWARDBUILDERSTATEDEBUG
michael@0 2337 PKIX_CHECK(pkix_ForwardBuilderState_DumpState(state, plContext),
michael@0 2338 PKIX_FORWARDBUILDERSTATEDUMPSTATEFAILED);
michael@0 2339 #endif
michael@0 2340
michael@0 2341 if (state->status == BUILD_CERTVALIDATING) {
michael@0 2342 PKIX_DECREF(state->candidateCert);
michael@0 2343 PKIX_CHECK(PKIX_List_GetItem
michael@0 2344 (state->candidateCerts,
michael@0 2345 state->certIndex,
michael@0 2346 (PKIX_PL_Object **)&(state->candidateCert),
michael@0 2347 plContext),
michael@0 2348 PKIX_LISTGETITEMFAILED);
michael@0 2349
michael@0 2350 if ((state->verifyNode) != NULL) {
michael@0 2351 PKIX_CHECK_FATAL(pkix_VerifyNode_Create
michael@0 2352 (state->candidateCert,
michael@0 2353 0,
michael@0 2354 NULL,
michael@0 2355 &verifyNode,
michael@0 2356 plContext),
michael@0 2357 PKIX_VERIFYNODECREATEFAILED);
michael@0 2358 }
michael@0 2359
michael@0 2360 /* If failure, this function sets Error in verifyNode */
michael@0 2361 verifyError = pkix_Build_VerifyCertificate
michael@0 2362 (state,
michael@0 2363 state->buildConstants.userCheckers,
michael@0 2364 &trusted,
michael@0 2365 verifyNode,
michael@0 2366 plContext);
michael@0 2367
michael@0 2368 if (verifyError) {
michael@0 2369 pkixTempErrorReceived = PKIX_TRUE;
michael@0 2370 pkixErrorClass = verifyError->errClass;
michael@0 2371 if (pkixErrorClass == PKIX_FATAL_ERROR) {
michael@0 2372 pkixErrorResult = verifyError;
michael@0 2373 verifyError = NULL;
michael@0 2374 goto fatal;
michael@0 2375 }
michael@0 2376 }
michael@0 2377
michael@0 2378 if (PKIX_ERROR_RECEIVED) {
michael@0 2379 if (state->verifyNode != NULL) {
michael@0 2380 PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
michael@0 2381 (verifyNode, verifyError, plContext),
michael@0 2382 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2383 PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
michael@0 2384 (state->verifyNode,
michael@0 2385 verifyNode,
michael@0 2386 plContext),
michael@0 2387 PKIX_VERIFYNODEADDTOTREEFAILED);
michael@0 2388 PKIX_DECREF(verifyNode);
michael@0 2389 }
michael@0 2390 pkixTempErrorReceived = PKIX_FALSE;
michael@0 2391 PKIX_DECREF(finalError);
michael@0 2392 finalError = verifyError;
michael@0 2393 verifyError = NULL;
michael@0 2394 if (state->certLoopingDetected) {
michael@0 2395 PKIX_ERROR
michael@0 2396 (PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED);
michael@0 2397 }
michael@0 2398 state->status = BUILD_GETNEXTCERT;
michael@0 2399 } else {
michael@0 2400 state->status = BUILD_DATEPREP;
michael@0 2401 }
michael@0 2402 }
michael@0 2403
michael@0 2404 if (state->status == BUILD_DATEPREP) {
michael@0 2405 /* Keep track of whether this chain can be cached */
michael@0 2406 PKIX_CHECK(pkix_Build_UpdateDate(state, plContext),
michael@0 2407 PKIX_BUILDUPDATEDATEFAILED);
michael@0 2408
michael@0 2409 canBeCached = state->canBeCached;
michael@0 2410 PKIX_DECREF(validityDate);
michael@0 2411 PKIX_INCREF(state->validityDate);
michael@0 2412 validityDate = state->validityDate;
michael@0 2413 if (trusted == PKIX_TRUE) {
michael@0 2414 state->status = BUILD_CHECKTRUSTED;
michael@0 2415 } else {
michael@0 2416 state->status = BUILD_ADDTOCHAIN;
michael@0 2417 }
michael@0 2418 }
michael@0 2419
michael@0 2420 if (state->status == BUILD_CHECKTRUSTED) {
michael@0 2421
michael@0 2422 /*
michael@0 2423 * If this cert is trusted, try to validate the entire
michael@0 2424 * chain using this certificate as trust anchor.
michael@0 2425 */
michael@0 2426 PKIX_CHECK(PKIX_TrustAnchor_CreateWithCert
michael@0 2427 (state->candidateCert,
michael@0 2428 &trustAnchor,
michael@0 2429 plContext),
michael@0 2430 PKIX_TRUSTANCHORCREATEWITHCERTFAILED);
michael@0 2431
michael@0 2432 PKIX_CHECK(pkix_Build_ValidationCheckers
michael@0 2433 (state,
michael@0 2434 state->trustChain,
michael@0 2435 trustAnchor,
michael@0 2436 PKIX_FALSE, /* do not add eku checker
michael@0 2437 * since eku was already
michael@0 2438 * checked */
michael@0 2439 plContext),
michael@0 2440 PKIX_BUILDVALIDATIONCHECKERSFAILED);
michael@0 2441
michael@0 2442 state->status = BUILD_CHECKTRUSTED2;
michael@0 2443 }
michael@0 2444
michael@0 2445 if (state->status == BUILD_CHECKTRUSTED2) {
michael@0 2446 verifyError =
michael@0 2447 pkix_Build_ValidateEntireChain(state,
michael@0 2448 trustAnchor,
michael@0 2449 &nbio, &valResult,
michael@0 2450 verifyNode,
michael@0 2451 plContext);
michael@0 2452 if (nbio != NULL) {
michael@0 2453 /* IO still pending, resume later */
michael@0 2454 goto cleanup;
michael@0 2455 } else {
michael@0 2456 /* checking the error for fatal status */
michael@0 2457 if (verifyError) {
michael@0 2458 pkixTempErrorReceived = PKIX_TRUE;
michael@0 2459 pkixErrorClass = verifyError->errClass;
michael@0 2460 if (pkixErrorClass == PKIX_FATAL_ERROR) {
michael@0 2461 pkixErrorResult = verifyError;
michael@0 2462 verifyError = NULL;
michael@0 2463 goto fatal;
michael@0 2464 }
michael@0 2465 }
michael@0 2466 if (state->verifyNode != NULL) {
michael@0 2467 PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
michael@0 2468 (state->verifyNode,
michael@0 2469 verifyNode,
michael@0 2470 plContext),
michael@0 2471 PKIX_VERIFYNODEADDTOTREEFAILED);
michael@0 2472 PKIX_DECREF(verifyNode);
michael@0 2473 }
michael@0 2474 if (!PKIX_ERROR_RECEIVED) {
michael@0 2475 *pValResult = valResult;
michael@0 2476 valResult = NULL;
michael@0 2477 /* Change state so IsIOPending is FALSE */
michael@0 2478 state->status = BUILD_CHECKTRUSTED;
michael@0 2479 goto cleanup;
michael@0 2480 }
michael@0 2481 PKIX_DECREF(finalError);
michael@0 2482 finalError = verifyError;
michael@0 2483 verifyError = NULL;
michael@0 2484 /* Reset temp error that was set by
michael@0 2485 * PKIX_CHECK_ONLY_FATAL and continue */
michael@0 2486 pkixTempErrorReceived = PKIX_FALSE;
michael@0 2487 PKIX_DECREF(trustAnchor);
michael@0 2488 }
michael@0 2489
michael@0 2490 /*
michael@0 2491 * If chain doesn't validate with a trusted Cert,
michael@0 2492 * adding more Certs to it can't help.
michael@0 2493 */
michael@0 2494 if (state->certLoopingDetected) {
michael@0 2495 PKIX_DECREF(verifyError);
michael@0 2496 PKIX_ERROR_CREATE(BUILD,
michael@0 2497 PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED,
michael@0 2498 verifyError);
michael@0 2499 PKIX_CHECK_FATAL(
michael@0 2500 pkix_VerifyNode_SetError(state->verifyNode,
michael@0 2501 verifyError,
michael@0 2502 plContext),
michael@0 2503 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2504 PKIX_DECREF(verifyError);
michael@0 2505 }
michael@0 2506 state->status = BUILD_GETNEXTCERT;
michael@0 2507 }
michael@0 2508
michael@0 2509 /*
michael@0 2510 * This Cert was not trusted. Add it to our chain, and
michael@0 2511 * continue building. If we don't reach a trust anchor,
michael@0 2512 * we'll take it off later and continue without it.
michael@0 2513 */
michael@0 2514 if (state->status == BUILD_ADDTOCHAIN) {
michael@0 2515 PKIX_CHECK(PKIX_List_AppendItem
michael@0 2516 (state->trustChain,
michael@0 2517 (PKIX_PL_Object *)state->candidateCert,
michael@0 2518 plContext),
michael@0 2519 PKIX_LISTAPPENDITEMFAILED);
michael@0 2520
michael@0 2521 state->status = BUILD_EXTENDCHAIN;
michael@0 2522 }
michael@0 2523
michael@0 2524 if (state->status == BUILD_EXTENDCHAIN) {
michael@0 2525
michael@0 2526 /* Check whether we are allowed to extend the chain */
michael@0 2527 if ((state->buildConstants.maxDepth != 0) &&
michael@0 2528 (state->numDepth <= 1)) {
michael@0 2529
michael@0 2530 if (state->verifyNode != NULL) {
michael@0 2531 PKIX_ERROR_CREATE
michael@0 2532 (BUILD,
michael@0 2533 PKIX_DEPTHWOULDEXCEEDRESOURCELIMITS,
michael@0 2534 verifyError);
michael@0 2535 PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
michael@0 2536 (verifyNode, verifyError, plContext),
michael@0 2537 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2538 PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
michael@0 2539 (state->verifyNode, verifyNode, plContext),
michael@0 2540 PKIX_VERIFYNODEADDTOTREEFAILED);
michael@0 2541 PKIX_DECREF(verifyNode);
michael@0 2542 PKIX_DECREF(finalError);
michael@0 2543 finalError = verifyError;
michael@0 2544 verifyError = NULL;
michael@0 2545 }
michael@0 2546 /* Even if error logged, still need to abort */
michael@0 2547 PKIX_ERROR(PKIX_DEPTHWOULDEXCEEDRESOURCELIMITS);
michael@0 2548 }
michael@0 2549
michael@0 2550 PKIX_CHECK(pkix_IsCertSelfIssued
michael@0 2551 (state->candidateCert, &isSelfIssued, plContext),
michael@0 2552 PKIX_ISCERTSELFISSUEDFAILED);
michael@0 2553
michael@0 2554 PKIX_CHECK(PKIX_PL_Object_Duplicate
michael@0 2555 ((PKIX_PL_Object *)state->traversedSubjNames,
michael@0 2556 (PKIX_PL_Object **)&childTraversedSubjNames,
michael@0 2557 plContext),
michael@0 2558 PKIX_OBJECTDUPLICATEFAILED);
michael@0 2559
michael@0 2560 if (isSelfIssued) {
michael@0 2561 childTraversedCACerts = state->traversedCACerts;
michael@0 2562 } else {
michael@0 2563 childTraversedCACerts = state->traversedCACerts + 1;
michael@0 2564
michael@0 2565 PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames
michael@0 2566 (state->candidateCert,
michael@0 2567 &subjectNames,
michael@0 2568 plContext),
michael@0 2569 PKIX_CERTGETALLSUBJECTNAMESFAILED);
michael@0 2570
michael@0 2571 if (subjectNames) {
michael@0 2572 PKIX_CHECK(PKIX_List_GetLength
michael@0 2573 (subjectNames,
michael@0 2574 &numSubjectNames,
michael@0 2575 plContext),
michael@0 2576 PKIX_LISTGETLENGTHFAILED);
michael@0 2577
michael@0 2578 } else {
michael@0 2579 numSubjectNames = 0;
michael@0 2580 }
michael@0 2581
michael@0 2582 for (i = 0; i < numSubjectNames; i++) {
michael@0 2583 PKIX_CHECK(PKIX_List_GetItem
michael@0 2584 (subjectNames,
michael@0 2585 i,
michael@0 2586 &subjectName,
michael@0 2587 plContext),
michael@0 2588 PKIX_LISTGETITEMFAILED);
michael@0 2589 PKIX_NULLCHECK_ONE
michael@0 2590 (state->traversedSubjNames);
michael@0 2591 PKIX_CHECK(PKIX_List_AppendItem
michael@0 2592 (state->traversedSubjNames,
michael@0 2593 subjectName,
michael@0 2594 plContext),
michael@0 2595 PKIX_LISTAPPENDITEMFAILED);
michael@0 2596 PKIX_DECREF(subjectName);
michael@0 2597 }
michael@0 2598 PKIX_DECREF(subjectNames);
michael@0 2599 }
michael@0 2600
michael@0 2601 PKIX_CHECK(pkix_ForwardBuilderState_Create
michael@0 2602 (childTraversedCACerts,
michael@0 2603 state->buildConstants.maxFanout,
michael@0 2604 state->numDepth - 1,
michael@0 2605 canBeCached,
michael@0 2606 validityDate,
michael@0 2607 state->candidateCert,
michael@0 2608 childTraversedSubjNames,
michael@0 2609 state->trustChain,
michael@0 2610 state,
michael@0 2611 &childState,
michael@0 2612 plContext),
michael@0 2613 PKIX_FORWARDBUILDSTATECREATEFAILED);
michael@0 2614
michael@0 2615 PKIX_DECREF(childTraversedSubjNames);
michael@0 2616 PKIX_DECREF(certSelParams);
michael@0 2617 childState->verifyNode = verifyNode;
michael@0 2618 verifyNode = NULL;
michael@0 2619 PKIX_DECREF(state);
michael@0 2620 state = childState; /* state->status == BUILD_INITIAL */
michael@0 2621 childState = NULL;
michael@0 2622 continue; /* with while (!outOfOptions) */
michael@0 2623 }
michael@0 2624
michael@0 2625 if (state->status == BUILD_GETNEXTCERT) {
michael@0 2626 pkixTempErrorReceived = PKIX_FALSE;
michael@0 2627 PKIX_DECREF(state->candidateCert);
michael@0 2628
michael@0 2629 /*
michael@0 2630 * If we were using a Cert from the callier-supplied partial
michael@0 2631 * chain, delete it and go to the certStores.
michael@0 2632 */
michael@0 2633 if (state->usingHintCerts == PKIX_TRUE) {
michael@0 2634 PKIX_DECREF(state->candidateCerts);
michael@0 2635 PKIX_CHECK(PKIX_List_Create
michael@0 2636 (&state->candidateCerts, plContext),
michael@0 2637 PKIX_LISTCREATEFAILED);
michael@0 2638
michael@0 2639 state->numCerts = 0;
michael@0 2640 state->usingHintCerts = PKIX_FALSE;
michael@0 2641 state->status = BUILD_TRYAIA;
michael@0 2642 continue;
michael@0 2643 } else if (++(state->certIndex) < (state->numCerts)) {
michael@0 2644 if ((state->buildConstants.maxFanout != 0) &&
michael@0 2645 (--(state->numFanout) == 0)) {
michael@0 2646
michael@0 2647 if (state->verifyNode != NULL) {
michael@0 2648 PKIX_ERROR_CREATE
michael@0 2649 (BUILD,
michael@0 2650 PKIX_FANOUTEXCEEDSRESOURCELIMITS,
michael@0 2651 verifyError);
michael@0 2652 PKIX_CHECK_FATAL
michael@0 2653 (pkix_VerifyNode_SetError
michael@0 2654 (state->verifyNode,
michael@0 2655 verifyError,
michael@0 2656 plContext),
michael@0 2657 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2658 PKIX_DECREF(finalError);
michael@0 2659 finalError = verifyError;
michael@0 2660 verifyError = NULL;
michael@0 2661 }
michael@0 2662 /* Even if error logged, still need to abort */
michael@0 2663 PKIX_ERROR
michael@0 2664 (PKIX_FANOUTEXCEEDSRESOURCELIMITS);
michael@0 2665 }
michael@0 2666 state->status = BUILD_CERTVALIDATING;
michael@0 2667 continue;
michael@0 2668 }
michael@0 2669 }
michael@0 2670
michael@0 2671 /*
michael@0 2672 * Adding the current cert to the chain didn't help. If our search
michael@0 2673 * has been restricted to local certStores, try opening up the
michael@0 2674 * search and see whether that helps. Otherwise, back up to the
michael@0 2675 * parent cert, and see if there are any more to try.
michael@0 2676 */
michael@0 2677 if (state->useOnlyLocal == PKIX_TRUE) {
michael@0 2678 pkix_PrepareForwardBuilderStateForAIA(state);
michael@0 2679 } else do {
michael@0 2680 if (state->parentState == NULL) {
michael@0 2681 /* We are at the top level, and can't back up! */
michael@0 2682 outOfOptions = PKIX_TRUE;
michael@0 2683 } else {
michael@0 2684 /*
michael@0 2685 * Try the next cert, if any, for this parent.
michael@0 2686 * Otherwise keep backing up until we reach a
michael@0 2687 * parent with more certs to try.
michael@0 2688 */
michael@0 2689 PKIX_CHECK(PKIX_List_GetLength
michael@0 2690 (state->trustChain, &numChained, plContext),
michael@0 2691 PKIX_LISTGETLENGTHFAILED);
michael@0 2692 PKIX_CHECK(PKIX_List_DeleteItem
michael@0 2693 (state->trustChain, numChained - 1, plContext),
michael@0 2694 PKIX_LISTDELETEITEMFAILED);
michael@0 2695
michael@0 2696 /* local and aia fetching returned no good certs.
michael@0 2697 * Creating a verify node in the parent that tells
michael@0 2698 * us this. */
michael@0 2699 if (!state->verifyNode) {
michael@0 2700 PKIX_CHECK_FATAL(
michael@0 2701 pkix_VerifyNode_Create(state->prevCert,
michael@0 2702 0, NULL,
michael@0 2703 &state->verifyNode,
michael@0 2704 plContext),
michael@0 2705 PKIX_VERIFYNODECREATEFAILED);
michael@0 2706 }
michael@0 2707 /* Updating the log with the error. */
michael@0 2708 PKIX_DECREF(verifyError);
michael@0 2709 PKIX_ERROR_CREATE(BUILD, PKIX_SECERRORUNKNOWNISSUER,
michael@0 2710 verifyError);
michael@0 2711 PKIX_CHECK_FATAL(
michael@0 2712 pkix_VerifyNode_SetError(state->verifyNode,
michael@0 2713 verifyError,
michael@0 2714 plContext),
michael@0 2715 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2716 PKIX_DECREF(verifyError);
michael@0 2717
michael@0 2718 PKIX_INCREF(state->parentState);
michael@0 2719 parentState = state->parentState;
michael@0 2720 PKIX_DECREF(verifyNode);
michael@0 2721 verifyNode = state->verifyNode;
michael@0 2722 state->verifyNode = NULL;
michael@0 2723 PKIX_DECREF(state);
michael@0 2724 state = parentState;
michael@0 2725 parentState = NULL;
michael@0 2726 if (state->verifyNode != NULL && verifyNode) {
michael@0 2727 PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
michael@0 2728 (state->verifyNode,
michael@0 2729 verifyNode,
michael@0 2730 plContext),
michael@0 2731 PKIX_VERIFYNODEADDTOTREEFAILED);
michael@0 2732 PKIX_DECREF(verifyNode);
michael@0 2733 }
michael@0 2734 PKIX_DECREF(validityDate);
michael@0 2735 PKIX_INCREF(state->validityDate);
michael@0 2736 validityDate = state->validityDate;
michael@0 2737 canBeCached = state->canBeCached;
michael@0 2738
michael@0 2739 /* Are there any more Certs to try? */
michael@0 2740 if (++(state->certIndex) < (state->numCerts)) {
michael@0 2741 state->status = BUILD_CERTVALIDATING;
michael@0 2742 PKIX_DECREF(state->candidateCert);
michael@0 2743 break;
michael@0 2744 }
michael@0 2745 if (state->useOnlyLocal == PKIX_TRUE) {
michael@0 2746 /* Clean up and go for AIA round. */
michael@0 2747 pkix_PrepareForwardBuilderStateForAIA(state);
michael@0 2748 break;
michael@0 2749 }
michael@0 2750 }
michael@0 2751 PKIX_DECREF(state->candidateCert);
michael@0 2752 } while (outOfOptions == PKIX_FALSE);
michael@0 2753
michael@0 2754 } /* while (outOfOptions == PKIX_FALSE) */
michael@0 2755
michael@0 2756 cleanup:
michael@0 2757
michael@0 2758 if (pkixErrorClass == PKIX_FATAL_ERROR) {
michael@0 2759 goto fatal;
michael@0 2760 }
michael@0 2761
michael@0 2762 /* verifyNode should be equal to NULL at this point. Assert it.
michael@0 2763 * Temporarelly use verifyError to store an error ref to which we
michael@0 2764 * have in pkixErrorResult. This is done to prevent error cloberring
michael@0 2765 * while using macros below. */
michael@0 2766 PORT_Assert(verifyError == NULL);
michael@0 2767 verifyError = pkixErrorResult;
michael@0 2768
michael@0 2769 /*
michael@0 2770 * We were called with an initialState that had no parent. If we are
michael@0 2771 * returning with an error or with a result, we must destroy any state
michael@0 2772 * that we created (any state with a parent).
michael@0 2773 */
michael@0 2774
michael@0 2775 PKIX_CHECK_FATAL(pkix_ForwardBuilderState_IsIOPending
michael@0 2776 (state, &ioPending, plContext),
michael@0 2777 PKIX_FORWARDBUILDERSTATEISIOPENDINGFAILED);
michael@0 2778
michael@0 2779 if (ioPending == PKIX_FALSE) {
michael@0 2780 while (state->parentState) {
michael@0 2781 PKIX_INCREF(state->parentState);
michael@0 2782 parentState = state->parentState;
michael@0 2783 PKIX_DECREF(verifyNode);
michael@0 2784 verifyNode = state->verifyNode;
michael@0 2785 state->verifyNode = NULL;
michael@0 2786 PKIX_DECREF(state);
michael@0 2787 state = parentState;
michael@0 2788 parentState = NULL;
michael@0 2789 if (state->verifyNode != NULL && verifyNode) {
michael@0 2790 PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
michael@0 2791 (state->verifyNode,
michael@0 2792 verifyNode,
michael@0 2793 plContext),
michael@0 2794 PKIX_VERIFYNODEADDTOTREEFAILED);
michael@0 2795 PKIX_DECREF(verifyNode);
michael@0 2796 }
michael@0 2797 }
michael@0 2798 state->canBeCached = canBeCached;
michael@0 2799 PKIX_DECREF(state->validityDate);
michael@0 2800 state->validityDate = validityDate;
michael@0 2801 validityDate = NULL;
michael@0 2802 }
michael@0 2803 if (!*pValResult && !verifyError) {
michael@0 2804 if (!finalError) {
michael@0 2805 PKIX_CHECK_FATAL(
michael@0 2806 pkix_VerifyNode_FindError(state->verifyNode,
michael@0 2807 &finalError,
michael@0 2808 plContext),
michael@0 2809 PKIX_VERIFYNODEFINDERRORFAILED);
michael@0 2810 }
michael@0 2811 if (finalError) {
michael@0 2812 pkixErrorResult = finalError;
michael@0 2813 pkixErrorCode = PKIX_BUILDFORWARDDEPTHFIRSTSEARCHFAILED;
michael@0 2814 finalError = NULL;
michael@0 2815 goto fatal;
michael@0 2816 }
michael@0 2817 pkixErrorCode = PKIX_SECERRORUNKNOWNISSUER;
michael@0 2818 pkixErrorReceived = PKIX_TRUE;
michael@0 2819 PKIX_ERROR_CREATE(BUILD, PKIX_SECERRORUNKNOWNISSUER,
michael@0 2820 verifyError);
michael@0 2821 PKIX_CHECK_FATAL(
michael@0 2822 pkix_VerifyNode_SetError(state->verifyNode, verifyError,
michael@0 2823 plContext),
michael@0 2824 PKIX_VERIFYNODESETERRORFAILED);
michael@0 2825 } else {
michael@0 2826 pkixErrorResult = verifyError;
michael@0 2827 verifyError = NULL;
michael@0 2828 }
michael@0 2829
michael@0 2830 fatal:
michael@0 2831 if (state->parentState) {
michael@0 2832 /* parentState in "state" object should be NULL at this point.
michael@0 2833 * If itn't, that means that we got fatal error(we have jumped to
michael@0 2834 * "fatal" label) and we should destroy all state except the top one. */
michael@0 2835 while (state->parentState) {
michael@0 2836 PKIX_Error *error = NULL;
michael@0 2837 PKIX_ForwardBuilderState *prntState = state->parentState;
michael@0 2838 /* Dumb: need to increment parentState to avoid destruction
michael@0 2839 * of "build constants"(they get destroyed when parentState is
michael@0 2840 * set to NULL. */
michael@0 2841 PKIX_INCREF(prntState);
michael@0 2842 error = PKIX_PL_Object_DecRef((PKIX_PL_Object*)state, plContext);
michael@0 2843 if (error) {
michael@0 2844 PKIX_PL_Object_DecRef((PKIX_PL_Object*)error, plContext);
michael@0 2845 }
michael@0 2846 /* No need to decref the parent state. It was already done by
michael@0 2847 * pkix_ForwardBuilderState_Destroy function. */
michael@0 2848 state = prntState;
michael@0 2849 }
michael@0 2850 }
michael@0 2851 PKIX_DECREF(parentState);
michael@0 2852 PKIX_DECREF(childState);
michael@0 2853 PKIX_DECREF(valResult);
michael@0 2854 PKIX_DECREF(verifyError);
michael@0 2855 PKIX_DECREF(finalError);
michael@0 2856 PKIX_DECREF(verifyNode);
michael@0 2857 PKIX_DECREF(childTraversedSubjNames);
michael@0 2858 PKIX_DECREF(certSelParams);
michael@0 2859 PKIX_DECREF(subjectNames);
michael@0 2860 PKIX_DECREF(subjectName);
michael@0 2861 PKIX_DECREF(trustAnchor);
michael@0 2862 PKIX_DECREF(validityDate);
michael@0 2863 PKIX_DECREF(revCheckerState);
michael@0 2864 PKIX_DECREF(currTime);
michael@0 2865 PKIX_DECREF(filteredCerts);
michael@0 2866 PKIX_DECREF(unfilteredCerts);
michael@0 2867 PKIX_DECREF(trustedCert);
michael@0 2868
michael@0 2869 PKIX_RETURN(BUILD);
michael@0 2870 }
michael@0 2871
michael@0 2872 /*
michael@0 2873 * FUNCTION: pkix_Build_CheckInCache
michael@0 2874 * DESCRIPTION:
michael@0 2875 *
michael@0 2876 * The function tries to locate a chain for a cert in the cert chain cache.
michael@0 2877 * If found, the chain goes through revocation chacking and returned back to
michael@0 2878 * caller. Chains that fail revocation check get removed from cache.
michael@0 2879 *
michael@0 2880 * PARAMETERS:
michael@0 2881 * "state"
michael@0 2882 * Address of ForwardBuilderState to be used. Must be non-NULL.
michael@0 2883 * "pBuildResult"
michael@0 2884 * Address at which the BuildResult is stored, after a successful build.
michael@0 2885 * Must be non-NULL.
michael@0 2886 * "pNBIOContext"
michael@0 2887 * Address at which the NBIOContext is stored indicating whether the
michael@0 2888 * validation is complete. Must be non-NULL.
michael@0 2889 * "plContext"
michael@0 2890 * Platform-specific context pointer.
michael@0 2891 * THREAD SAFETY:
michael@0 2892 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 2893 * RETURNS:
michael@0 2894 * Returns NULL if the function succeeds.
michael@0 2895 * Returns a Build Error if the function fails in a non-fatal way
michael@0 2896 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 2897 */
michael@0 2898 static PKIX_Error*
michael@0 2899 pkix_Build_CheckInCache(
michael@0 2900 PKIX_ForwardBuilderState *state,
michael@0 2901 PKIX_BuildResult **pBuildResult,
michael@0 2902 void **pNBIOContext,
michael@0 2903 void *plContext)
michael@0 2904 {
michael@0 2905 PKIX_PL_Cert *targetCert = NULL;
michael@0 2906 PKIX_List *anchors = NULL;
michael@0 2907 PKIX_PL_Date *testDate = NULL;
michael@0 2908 PKIX_BuildResult *buildResult = NULL;
michael@0 2909 PKIX_ValidateResult *valResult = NULL;
michael@0 2910 PKIX_Error *buildError = NULL;
michael@0 2911 PKIX_TrustAnchor *matchingAnchor = NULL;
michael@0 2912 PKIX_PL_Cert *trustedCert = NULL;
michael@0 2913 PKIX_List *certList = NULL;
michael@0 2914 PKIX_Boolean cacheHit = PKIX_FALSE;
michael@0 2915 PKIX_Boolean trusted = PKIX_FALSE;
michael@0 2916 PKIX_Boolean stillValid = PKIX_FALSE;
michael@0 2917 void *nbioContext = NULL;
michael@0 2918
michael@0 2919 PKIX_ENTER(BUILD, "pkix_Build_CheckInCache");
michael@0 2920
michael@0 2921 nbioContext = *pNBIOContext;
michael@0 2922 *pNBIOContext = NULL;
michael@0 2923
michael@0 2924 targetCert = state->buildConstants.targetCert;
michael@0 2925 anchors = state->buildConstants.anchors;
michael@0 2926 testDate = state->buildConstants.testDate;
michael@0 2927
michael@0 2928 /* Check whether this cert verification has been cached. */
michael@0 2929 PKIX_CHECK(pkix_CacheCertChain_Lookup
michael@0 2930 (targetCert,
michael@0 2931 anchors,
michael@0 2932 testDate,
michael@0 2933 &cacheHit,
michael@0 2934 &buildResult,
michael@0 2935 plContext),
michael@0 2936 PKIX_CACHECERTCHAINLOOKUPFAILED);
michael@0 2937
michael@0 2938 if (!cacheHit) {
michael@0 2939 goto cleanup;
michael@0 2940 }
michael@0 2941
michael@0 2942 /*
michael@0 2943 * We found something in cache. Verify that the anchor
michael@0 2944 * cert is still trusted,
michael@0 2945 */
michael@0 2946 PKIX_CHECK(PKIX_BuildResult_GetValidateResult
michael@0 2947 (buildResult, &valResult, plContext),
michael@0 2948 PKIX_BUILDRESULTGETVALIDATERESULTFAILED);
michael@0 2949
michael@0 2950 PKIX_CHECK(PKIX_ValidateResult_GetTrustAnchor
michael@0 2951 (valResult, &matchingAnchor, plContext),
michael@0 2952 PKIX_VALIDATERESULTGETTRUSTANCHORFAILED);
michael@0 2953
michael@0 2954 PKIX_DECREF(valResult);
michael@0 2955
michael@0 2956 PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
michael@0 2957 (matchingAnchor, &trustedCert, plContext),
michael@0 2958 PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
michael@0 2959
michael@0 2960 if (anchors && state->buildConstants.numAnchors) {
michael@0 2961 /* Check if it is one of the trust anchors */
michael@0 2962 PKIX_CHECK(
michael@0 2963 pkix_List_Contains(anchors,
michael@0 2964 (PKIX_PL_Object *)matchingAnchor,
michael@0 2965 &trusted,
michael@0 2966 plContext),
michael@0 2967 PKIX_LISTCONTAINSFAILED);
michael@0 2968 }
michael@0 2969
michael@0 2970 if ((!trusted && !state->buildConstants.trustOnlyUserAnchors) ||
michael@0 2971 !state->buildConstants.numAnchors) {
michael@0 2972 /* If it is not one of the trust anchors and the trust anchors
michael@0 2973 * are supplemental, or if there are no trust anchors, then check
michael@0 2974 * if the cert is trusted directly.
michael@0 2975 */
michael@0 2976 PKIX_CHECK(
michael@0 2977 PKIX_PL_Cert_IsCertTrusted(trustedCert,
michael@0 2978 PKIX_PL_TrustAnchorMode_Ignore,
michael@0 2979 &trusted, plContext),
michael@0 2980 PKIX_CERTISCERTTRUSTEDFAILED);
michael@0 2981 }
michael@0 2982
michael@0 2983 if (!trusted) {
michael@0 2984 goto cleanup;
michael@0 2985 }
michael@0 2986 /*
michael@0 2987 * Since the key usage may vary for different
michael@0 2988 * applications, we need to verify the chain again.
michael@0 2989 * Reverification will be improved with a fix for 397805.
michael@0 2990 */
michael@0 2991 PKIX_CHECK(PKIX_BuildResult_GetCertChain
michael@0 2992 (buildResult, &certList, plContext),
michael@0 2993 PKIX_BUILDRESULTGETCERTCHAINFAILED);
michael@0 2994
michael@0 2995 PKIX_CHECK(pkix_Build_ValidationCheckers
michael@0 2996 (state,
michael@0 2997 certList,
michael@0 2998 matchingAnchor,
michael@0 2999 PKIX_TRUE, /* Chain revalidation stage. */
michael@0 3000 plContext),
michael@0 3001 PKIX_BUILDVALIDATIONCHECKERSFAILED);
michael@0 3002
michael@0 3003 PKIX_CHECK_ONLY_FATAL(
michael@0 3004 pkix_Build_ValidateEntireChain(state, matchingAnchor,
michael@0 3005 &nbioContext, &valResult,
michael@0 3006 state->verifyNode, plContext),
michael@0 3007 PKIX_BUILDVALIDATEENTIRECHAINFAILED);
michael@0 3008
michael@0 3009 if (nbioContext != NULL) {
michael@0 3010 /* IO still pending, resume later */
michael@0 3011 *pNBIOContext = nbioContext;
michael@0 3012 goto cleanup;
michael@0 3013 }
michael@0 3014 if (!PKIX_ERROR_RECEIVED) {
michael@0 3015 /* The result from cache is still valid. But we replace an old*/
michael@0 3016 *pBuildResult = buildResult;
michael@0 3017 buildResult = NULL;
michael@0 3018 stillValid = PKIX_TRUE;
michael@0 3019 }
michael@0 3020
michael@0 3021 cleanup:
michael@0 3022
michael@0 3023 if (!nbioContext && cacheHit && !(trusted && stillValid)) {
michael@0 3024 /* The anchor of this chain is no longer trusted or
michael@0 3025 * chain cert(s) has been revoked.
michael@0 3026 * Invalidate this result in the cache */
michael@0 3027 buildError = pkixErrorResult;
michael@0 3028 PKIX_CHECK_FATAL(pkix_CacheCertChain_Remove
michael@0 3029 (targetCert,
michael@0 3030 anchors,
michael@0 3031 plContext),
michael@0 3032 PKIX_CACHECERTCHAINREMOVEFAILED);
michael@0 3033 pkixErrorResult = buildError;
michael@0 3034 buildError = NULL;
michael@0 3035 }
michael@0 3036
michael@0 3037 fatal:
michael@0 3038 PKIX_DECREF(buildResult);
michael@0 3039 PKIX_DECREF(valResult);
michael@0 3040 PKIX_DECREF(buildError);
michael@0 3041 PKIX_DECREF(certList);
michael@0 3042 PKIX_DECREF(matchingAnchor);
michael@0 3043 PKIX_DECREF(trustedCert);
michael@0 3044
michael@0 3045
michael@0 3046 PKIX_RETURN(BUILD);
michael@0 3047 }
michael@0 3048
michael@0 3049 /*
michael@0 3050 * FUNCTION: pkix_Build_InitiateBuildChain
michael@0 3051 * DESCRIPTION:
michael@0 3052 *
michael@0 3053 * This function initiates the search for a BuildChain, using the parameters
michael@0 3054 * provided in "procParams" and, if continuing a search that was suspended
michael@0 3055 * for I/O, using the ForwardBuilderState pointed to by "pState".
michael@0 3056 *
michael@0 3057 * If a successful chain is built, this function stores the BuildResult at
michael@0 3058 * "pBuildResult". Alternatively, if an operation using non-blocking I/O
michael@0 3059 * is in progress and the operation has not been completed, this function
michael@0 3060 * stores the platform-dependent non-blocking I/O context (nbioContext) at
michael@0 3061 * "pNBIOContext", the FowardBuilderState at "pState", and NULL at
michael@0 3062 * "pBuildResult". Finally, if chain building was unsuccessful, this function
michael@0 3063 * stores NULL at both "pState" and at "pBuildResult".
michael@0 3064 *
michael@0 3065 * Note: This function is re-entered only for the case of non-blocking I/O
michael@0 3066 * in the "short-cut" attempt to build a chain using the target Certificate
michael@0 3067 * directly with one of the trustAnchors. For all other cases, resumption
michael@0 3068 * after non-blocking I/O is via pkix_Build_ResumeBuildChain.
michael@0 3069 *
michael@0 3070 * PARAMETERS:
michael@0 3071 * "procParams"
michael@0 3072 * Address of the ProcessingParams for the search. Must be non-NULL.
michael@0 3073 * "pNBIOContext"
michael@0 3074 * Address at which the NBIOContext is stored indicating whether the
michael@0 3075 * validation is complete. Must be non-NULL.
michael@0 3076 * "pState"
michael@0 3077 * Address at which the ForwardBuilderState is stored, if the chain
michael@0 3078 * building is suspended for waiting I/O; also, the address at which the
michael@0 3079 * ForwardBuilderState is provided for resumption of the chain building
michael@0 3080 * attempt. Must be non-NULL.
michael@0 3081 * "pBuildResult"
michael@0 3082 * Address at which the BuildResult is stored, after a successful build.
michael@0 3083 * Must be non-NULL.
michael@0 3084 * "pVerifyNode"
michael@0 3085 * Address at which a VerifyNode chain is returned, if non-NULL.
michael@0 3086 * "plContext"
michael@0 3087 * Platform-specific context pointer.
michael@0 3088 * THREAD SAFETY:
michael@0 3089 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 3090 * RETURNS:
michael@0 3091 * Returns NULL if the function succeeds.
michael@0 3092 * Returns a Build Error if the function fails in a non-fatal way
michael@0 3093 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 3094 */
michael@0 3095 static PKIX_Error *
michael@0 3096 pkix_Build_InitiateBuildChain(
michael@0 3097 PKIX_ProcessingParams *procParams,
michael@0 3098 void **pNBIOContext,
michael@0 3099 PKIX_ForwardBuilderState **pState,
michael@0 3100 PKIX_BuildResult **pBuildResult,
michael@0 3101 PKIX_VerifyNode **pVerifyNode,
michael@0 3102 void *plContext)
michael@0 3103 {
michael@0 3104 PKIX_UInt32 numAnchors = 0;
michael@0 3105 PKIX_UInt32 numCertStores = 0;
michael@0 3106 PKIX_UInt32 numHintCerts = 0;
michael@0 3107 PKIX_UInt32 i = 0;
michael@0 3108 PKIX_Boolean isDuplicate = PKIX_FALSE;
michael@0 3109 PKIX_PL_Cert *trustedCert = NULL;
michael@0 3110 PKIX_CertSelector *targetConstraints = NULL;
michael@0 3111 PKIX_ComCertSelParams *targetParams = NULL;
michael@0 3112 PKIX_List *anchors = NULL;
michael@0 3113 PKIX_List *targetSubjNames = NULL;
michael@0 3114 PKIX_PL_Cert *targetCert = NULL;
michael@0 3115 PKIX_PL_Object *firstHintCert = NULL;
michael@0 3116 PKIX_RevocationChecker *revChecker = NULL;
michael@0 3117 PKIX_List *certStores = NULL;
michael@0 3118 PKIX_CertStore *certStore = NULL;
michael@0 3119 PKIX_List *userCheckers = NULL;
michael@0 3120 PKIX_List *hintCerts = NULL;
michael@0 3121 PKIX_PL_Date *testDate = NULL;
michael@0 3122 PKIX_PL_PublicKey *targetPubKey = NULL;
michael@0 3123 void *nbioContext = NULL;
michael@0 3124 BuildConstants buildConstants;
michael@0 3125
michael@0 3126 PKIX_List *tentativeChain = NULL;
michael@0 3127 PKIX_ValidateResult *valResult = NULL;
michael@0 3128 PKIX_BuildResult *buildResult = NULL;
michael@0 3129 PKIX_List *certList = NULL;
michael@0 3130 PKIX_ForwardBuilderState *state = NULL;
michael@0 3131 PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
michael@0 3132 PKIX_CertSelector_MatchCallback selectorCallback = NULL;
michael@0 3133 PKIX_Boolean trusted = PKIX_FALSE;
michael@0 3134 PKIX_PL_AIAMgr *aiaMgr = NULL;
michael@0 3135
michael@0 3136 PKIX_ENTER(BUILD, "pkix_Build_InitiateBuildChain");
michael@0 3137 PKIX_NULLCHECK_FOUR(procParams, pNBIOContext, pState, pBuildResult);
michael@0 3138
michael@0 3139 nbioContext = *pNBIOContext;
michael@0 3140 *pNBIOContext = NULL;
michael@0 3141
michael@0 3142 state = *pState;
michael@0 3143 *pState = NULL; /* no net change in reference count */
michael@0 3144
michael@0 3145 if (state == NULL) {
michael@0 3146 PKIX_CHECK(PKIX_ProcessingParams_GetDate
michael@0 3147 (procParams, &testDate, plContext),
michael@0 3148 PKIX_PROCESSINGPARAMSGETDATEFAILED);
michael@0 3149
michael@0 3150 PKIX_CHECK(PKIX_ProcessingParams_GetTrustAnchors
michael@0 3151 (procParams, &anchors, plContext),
michael@0 3152 PKIX_PROCESSINGPARAMSGETTRUSTANCHORSFAILED);
michael@0 3153
michael@0 3154 PKIX_CHECK(PKIX_List_GetLength(anchors, &numAnchors, plContext),
michael@0 3155 PKIX_LISTGETLENGTHFAILED);
michael@0 3156
michael@0 3157 /* retrieve stuff from targetCertConstraints */
michael@0 3158 PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
michael@0 3159 (procParams, &targetConstraints, plContext),
michael@0 3160 PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
michael@0 3161
michael@0 3162 PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
michael@0 3163 (targetConstraints, &targetParams, plContext),
michael@0 3164 PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
michael@0 3165
michael@0 3166 PKIX_CHECK(PKIX_ComCertSelParams_GetCertificate
michael@0 3167 (targetParams, &targetCert, plContext),
michael@0 3168 PKIX_COMCERTSELPARAMSGETCERTIFICATEFAILED);
michael@0 3169
michael@0 3170 PKIX_CHECK(
michael@0 3171 PKIX_ComCertSelParams_SetLeafCertFlag(targetParams,
michael@0 3172 PKIX_TRUE, plContext),
michael@0 3173 PKIX_COMCERTSELPARAMSSETLEAFCERTFLAGFAILED);
michael@0 3174
michael@0 3175 PKIX_CHECK(PKIX_ProcessingParams_GetHintCerts
michael@0 3176 (procParams, &hintCerts, plContext),
michael@0 3177 PKIX_PROCESSINGPARAMSGETHINTCERTSFAILED);
michael@0 3178
michael@0 3179 if (hintCerts != NULL) {
michael@0 3180 PKIX_CHECK(PKIX_List_GetLength
michael@0 3181 (hintCerts, &numHintCerts, plContext),
michael@0 3182 PKIX_LISTGETLENGTHFAILED);
michael@0 3183 }
michael@0 3184
michael@0 3185 /*
michael@0 3186 * Caller must provide either a target Cert
michael@0 3187 * (in ComCertSelParams->Certificate) or a partial Cert
michael@0 3188 * chain (in ProcParams->HintCerts).
michael@0 3189 */
michael@0 3190
michael@0 3191 if (targetCert == NULL) {
michael@0 3192
michael@0 3193 /* Use first cert of hintCerts as the targetCert */
michael@0 3194 if (numHintCerts == 0) {
michael@0 3195 PKIX_ERROR(PKIX_NOTARGETCERTSUPPLIED);
michael@0 3196 }
michael@0 3197
michael@0 3198 PKIX_CHECK(PKIX_List_GetItem
michael@0 3199 (hintCerts,
michael@0 3200 0,
michael@0 3201 (PKIX_PL_Object **)&targetCert,
michael@0 3202 plContext),
michael@0 3203 PKIX_LISTGETITEMFAILED);
michael@0 3204
michael@0 3205 PKIX_CHECK(PKIX_List_DeleteItem(hintCerts, 0, plContext),
michael@0 3206 PKIX_LISTGETITEMFAILED);
michael@0 3207 } else {
michael@0 3208
michael@0 3209 /*
michael@0 3210 * If the first hintCert is the same as the targetCert,
michael@0 3211 * delete it from hintCerts.
michael@0 3212 */
michael@0 3213 if (numHintCerts != 0) {
michael@0 3214 PKIX_CHECK(PKIX_List_GetItem
michael@0 3215 (hintCerts, 0, &firstHintCert, plContext),
michael@0 3216 PKIX_LISTGETITEMFAILED);
michael@0 3217
michael@0 3218 PKIX_CHECK(PKIX_PL_Object_Equals
michael@0 3219 ((PKIX_PL_Object *)targetCert,
michael@0 3220 firstHintCert,
michael@0 3221 &isDuplicate,
michael@0 3222 plContext),
michael@0 3223 PKIX_OBJECTEQUALSFAILED);
michael@0 3224
michael@0 3225 if (isDuplicate) {
michael@0 3226 PKIX_CHECK(PKIX_List_DeleteItem
michael@0 3227 (hintCerts, 0, plContext),
michael@0 3228 PKIX_LISTGETITEMFAILED);
michael@0 3229 }
michael@0 3230 PKIX_DECREF(firstHintCert);
michael@0 3231 }
michael@0 3232
michael@0 3233 }
michael@0 3234
michael@0 3235 if (targetCert == NULL) {
michael@0 3236 PKIX_ERROR(PKIX_NOTARGETCERTSUPPLIED);
michael@0 3237 }
michael@0 3238
michael@0 3239 PKIX_CHECK(PKIX_PL_Cert_IsLeafCertTrusted
michael@0 3240 (targetCert,
michael@0 3241 &trusted,
michael@0 3242 plContext),
michael@0 3243 PKIX_CERTISCERTTRUSTEDFAILED);
michael@0 3244
michael@0 3245 PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames
michael@0 3246 (targetCert,
michael@0 3247 &targetSubjNames,
michael@0 3248 plContext),
michael@0 3249 PKIX_CERTGETALLSUBJECTNAMESFAILED);
michael@0 3250
michael@0 3251 PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
michael@0 3252 (targetCert, &targetPubKey, plContext),
michael@0 3253 PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
michael@0 3254
michael@0 3255 PKIX_CHECK(PKIX_List_Create(&tentativeChain, plContext),
michael@0 3256 PKIX_LISTCREATEFAILED);
michael@0 3257
michael@0 3258 PKIX_CHECK(PKIX_List_AppendItem
michael@0 3259 (tentativeChain, (PKIX_PL_Object *)targetCert, plContext),
michael@0 3260 PKIX_LISTAPPENDITEMFAILED);
michael@0 3261
michael@0 3262 if (procParams->qualifyTargetCert) {
michael@0 3263 /* EE cert validation */
michael@0 3264 /* Sync up the time on the target selector parameter struct. */
michael@0 3265 PKIX_CHECK(
michael@0 3266 PKIX_ComCertSelParams_SetCertificateValid(targetParams,
michael@0 3267 testDate,
michael@0 3268 plContext),
michael@0 3269 PKIX_COMCERTSELPARAMSSETCERTIFICATEVALIDFAILED);
michael@0 3270
michael@0 3271 PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
michael@0 3272 (targetConstraints, &selectorCallback, plContext),
michael@0 3273 PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
michael@0 3274
michael@0 3275 pkixErrorResult =
michael@0 3276 (*selectorCallback)(targetConstraints, targetCert,
michael@0 3277 plContext);
michael@0 3278 if (pkixErrorResult) {
michael@0 3279 pkixErrorClass = pkixErrorResult->errClass;
michael@0 3280 if (pkixErrorClass == PKIX_FATAL_ERROR) {
michael@0 3281 goto cleanup;
michael@0 3282 }
michael@0 3283 if (pVerifyNode != NULL) {
michael@0 3284 PKIX_Error *tempResult =
michael@0 3285 pkix_VerifyNode_Create(targetCert, 0,
michael@0 3286 pkixErrorResult,
michael@0 3287 pVerifyNode,
michael@0 3288 plContext);
michael@0 3289 if (tempResult) {
michael@0 3290 PKIX_DECREF(pkixErrorResult);
michael@0 3291 pkixErrorResult = tempResult;
michael@0 3292 pkixErrorCode = PKIX_VERIFYNODECREATEFAILED;
michael@0 3293 pkixErrorClass = PKIX_FATAL_ERROR;
michael@0 3294 goto cleanup;
michael@0 3295 }
michael@0 3296 }
michael@0 3297 pkixErrorCode = PKIX_CERTCHECKVALIDITYFAILED;
michael@0 3298 goto cleanup;
michael@0 3299 }
michael@0 3300 }
michael@0 3301
michael@0 3302 /* If the EE cert is trusted, force success. We only want to do
michael@0 3303 * this if we aren't validating against a policy (like EV). */
michael@0 3304 if (trusted && procParams->initialPolicies == NULL) {
michael@0 3305 if (pVerifyNode != NULL) {
michael@0 3306 PKIX_Error *tempResult =
michael@0 3307 pkix_VerifyNode_Create(targetCert, 0, NULL,
michael@0 3308 pVerifyNode,
michael@0 3309 plContext);
michael@0 3310 if (tempResult) {
michael@0 3311 pkixErrorResult = tempResult;
michael@0 3312 pkixErrorCode = PKIX_VERIFYNODECREATEFAILED;
michael@0 3313 pkixErrorClass = PKIX_FATAL_ERROR;
michael@0 3314 goto cleanup;
michael@0 3315 }
michael@0 3316 }
michael@0 3317 PKIX_CHECK(pkix_ValidateResult_Create
michael@0 3318 (targetPubKey, NULL /* anchor */,
michael@0 3319 NULL /* policyTree */, &valResult, plContext),
michael@0 3320 PKIX_VALIDATERESULTCREATEFAILED);
michael@0 3321 PKIX_CHECK(
michael@0 3322 pkix_BuildResult_Create(valResult, tentativeChain,
michael@0 3323 &buildResult, plContext),
michael@0 3324 PKIX_BUILDRESULTCREATEFAILED);
michael@0 3325 *pBuildResult = buildResult;
michael@0 3326 /* Note that *pState is NULL. The only side effect is that
michael@0 3327 * the cert chain won't be cached in PKIX_BuildChain, which
michael@0 3328 * is fine. */
michael@0 3329 goto cleanup;
michael@0 3330 }
michael@0 3331
michael@0 3332 PKIX_CHECK(PKIX_ProcessingParams_GetCertStores
michael@0 3333 (procParams, &certStores, plContext),
michael@0 3334 PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED);
michael@0 3335
michael@0 3336 PKIX_CHECK(PKIX_List_GetLength
michael@0 3337 (certStores, &numCertStores, plContext),
michael@0 3338 PKIX_LISTGETLENGTHFAILED);
michael@0 3339
michael@0 3340 /* Reorder CertStores so trusted are at front of the List */
michael@0 3341 if (numCertStores > 1) {
michael@0 3342 for (i = numCertStores - 1; i > 0; i--) {
michael@0 3343 PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
michael@0 3344 (certStores,
michael@0 3345 i,
michael@0 3346 (PKIX_PL_Object **)&certStore,
michael@0 3347 plContext),
michael@0 3348 PKIX_LISTGETITEMFAILED);
michael@0 3349 PKIX_CHECK_ONLY_FATAL(PKIX_CertStore_GetTrustCallback
michael@0 3350 (certStore, &trustCallback, plContext),
michael@0 3351 PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
michael@0 3352
michael@0 3353 if (trustCallback != NULL) {
michael@0 3354 /* Is a trusted Cert, move CertStore to front */
michael@0 3355 PKIX_CHECK(PKIX_List_DeleteItem
michael@0 3356 (certStores, i, plContext),
michael@0 3357 PKIX_LISTDELETEITEMFAILED);
michael@0 3358 PKIX_CHECK(PKIX_List_InsertItem
michael@0 3359 (certStores,
michael@0 3360 0,
michael@0 3361 (PKIX_PL_Object *)certStore,
michael@0 3362 plContext),
michael@0 3363 PKIX_LISTINSERTITEMFAILED);
michael@0 3364
michael@0 3365 }
michael@0 3366
michael@0 3367 PKIX_DECREF(certStore);
michael@0 3368 }
michael@0 3369 }
michael@0 3370
michael@0 3371 PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers
michael@0 3372 (procParams, &userCheckers, plContext),
michael@0 3373 PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED);
michael@0 3374
michael@0 3375 PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker
michael@0 3376 (procParams, &revChecker, plContext),
michael@0 3377 PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED);
michael@0 3378 /* Do not initialize AIA manager if we are not going to fetch
michael@0 3379 * cert using aia url. */
michael@0 3380 if (procParams->useAIAForCertFetching) {
michael@0 3381 PKIX_CHECK(PKIX_PL_AIAMgr_Create(&aiaMgr, plContext),
michael@0 3382 PKIX_AIAMGRCREATEFAILED);
michael@0 3383 }
michael@0 3384
michael@0 3385 /*
michael@0 3386 * We initialize all the fields of buildConstants here, in one place,
michael@0 3387 * just to help keep track and ensure that we got everything.
michael@0 3388 */
michael@0 3389
michael@0 3390 buildConstants.numAnchors = numAnchors;
michael@0 3391 buildConstants.numCertStores = numCertStores;
michael@0 3392 buildConstants.numHintCerts = numHintCerts;
michael@0 3393 buildConstants.procParams = procParams;
michael@0 3394 buildConstants.testDate = testDate;
michael@0 3395 buildConstants.timeLimit = NULL;
michael@0 3396 buildConstants.targetCert = targetCert;
michael@0 3397 buildConstants.targetPubKey = targetPubKey;
michael@0 3398 buildConstants.certStores = certStores;
michael@0 3399 buildConstants.anchors = anchors;
michael@0 3400 buildConstants.userCheckers = userCheckers;
michael@0 3401 buildConstants.hintCerts = hintCerts;
michael@0 3402 buildConstants.revChecker = revChecker;
michael@0 3403 buildConstants.aiaMgr = aiaMgr;
michael@0 3404 buildConstants.trustOnlyUserAnchors =
michael@0 3405 procParams->useOnlyTrustAnchors;
michael@0 3406
michael@0 3407 PKIX_CHECK(pkix_Build_GetResourceLimits(&buildConstants, plContext),
michael@0 3408 PKIX_BUILDGETRESOURCELIMITSFAILED);
michael@0 3409
michael@0 3410 PKIX_CHECK(pkix_ForwardBuilderState_Create
michael@0 3411 (0, /* PKIX_UInt32 traversedCACerts */
michael@0 3412 buildConstants.maxFanout,
michael@0 3413 buildConstants.maxDepth,
michael@0 3414 PKIX_TRUE, /* PKIX_Boolean canBeCached */
michael@0 3415 NULL, /* PKIX_Date *validityDate */
michael@0 3416 targetCert, /* PKIX_PL_Cert *prevCert */
michael@0 3417 targetSubjNames, /* PKIX_List *traversedSubjNames */
michael@0 3418 tentativeChain, /* PKIX_List *trustChain */
michael@0 3419 NULL, /* PKIX_ForwardBuilderState *parent */
michael@0 3420 &state, /* PKIX_ForwardBuilderState **pState */
michael@0 3421 plContext),
michael@0 3422 PKIX_BUILDSTATECREATEFAILED);
michael@0 3423
michael@0 3424 state->buildConstants.numAnchors = buildConstants.numAnchors;
michael@0 3425 state->buildConstants.numCertStores = buildConstants.numCertStores;
michael@0 3426 state->buildConstants.numHintCerts = buildConstants.numHintCerts;
michael@0 3427 state->buildConstants.maxFanout = buildConstants.maxFanout;
michael@0 3428 state->buildConstants.maxDepth = buildConstants.maxDepth;
michael@0 3429 state->buildConstants.maxTime = buildConstants.maxTime;
michael@0 3430 state->buildConstants.procParams = buildConstants.procParams;
michael@0 3431 PKIX_INCREF(buildConstants.testDate);
michael@0 3432 state->buildConstants.testDate = buildConstants.testDate;
michael@0 3433 state->buildConstants.timeLimit = buildConstants.timeLimit;
michael@0 3434 PKIX_INCREF(buildConstants.targetCert);
michael@0 3435 state->buildConstants.targetCert = buildConstants.targetCert;
michael@0 3436 PKIX_INCREF(buildConstants.targetPubKey);
michael@0 3437 state->buildConstants.targetPubKey =
michael@0 3438 buildConstants.targetPubKey;
michael@0 3439 PKIX_INCREF(buildConstants.certStores);
michael@0 3440 state->buildConstants.certStores = buildConstants.certStores;
michael@0 3441 PKIX_INCREF(buildConstants.anchors);
michael@0 3442 state->buildConstants.anchors = buildConstants.anchors;
michael@0 3443 PKIX_INCREF(buildConstants.userCheckers);
michael@0 3444 state->buildConstants.userCheckers =
michael@0 3445 buildConstants.userCheckers;
michael@0 3446 PKIX_INCREF(buildConstants.hintCerts);
michael@0 3447 state->buildConstants.hintCerts = buildConstants.hintCerts;
michael@0 3448 PKIX_INCREF(buildConstants.revChecker);
michael@0 3449 state->buildConstants.revChecker = buildConstants.revChecker;
michael@0 3450 state->buildConstants.aiaMgr = buildConstants.aiaMgr;
michael@0 3451 aiaMgr = NULL;
michael@0 3452 state->buildConstants.trustOnlyUserAnchors =
michael@0 3453 buildConstants.trustOnlyUserAnchors;
michael@0 3454
michael@0 3455 if (buildConstants.maxTime != 0) {
michael@0 3456 PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds
michael@0 3457 (buildConstants.maxTime,
michael@0 3458 &state->buildConstants.timeLimit,
michael@0 3459 plContext),
michael@0 3460 PKIX_DATECREATECURRENTOFFBYSECONDSFAILED);
michael@0 3461 }
michael@0 3462
michael@0 3463 if (pVerifyNode != NULL) {
michael@0 3464 PKIX_Error *tempResult =
michael@0 3465 pkix_VerifyNode_Create(targetCert, 0, NULL,
michael@0 3466 &(state->verifyNode),
michael@0 3467 plContext);
michael@0 3468 if (tempResult) {
michael@0 3469 pkixErrorResult = tempResult;
michael@0 3470 pkixErrorCode = PKIX_VERIFYNODECREATEFAILED;
michael@0 3471 pkixErrorClass = PKIX_FATAL_ERROR;
michael@0 3472 goto cleanup;
michael@0 3473 }
michael@0 3474 }
michael@0 3475
michael@0 3476 PKIX_CHECK_ONLY_FATAL(
michael@0 3477 pkix_Build_CheckInCache(state, &buildResult,
michael@0 3478 &nbioContext, plContext),
michael@0 3479 PKIX_UNABLETOBUILDCHAIN);
michael@0 3480 if (nbioContext) {
michael@0 3481 *pNBIOContext = nbioContext;
michael@0 3482 *pState = state;
michael@0 3483 state = NULL;
michael@0 3484 goto cleanup;
michael@0 3485 }
michael@0 3486 if (buildResult) {
michael@0 3487 *pBuildResult = buildResult;
michael@0 3488 if (pVerifyNode != NULL) {
michael@0 3489 *pVerifyNode = state->verifyNode;
michael@0 3490 state->verifyNode = NULL;
michael@0 3491 }
michael@0 3492 goto cleanup;
michael@0 3493 }
michael@0 3494 }
michael@0 3495
michael@0 3496 /* If we're resuming after non-blocking I/O we need to get SubjNames */
michael@0 3497 if (targetSubjNames == NULL) {
michael@0 3498 PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames
michael@0 3499 (state->buildConstants.targetCert,
michael@0 3500 &targetSubjNames,
michael@0 3501 plContext),
michael@0 3502 PKIX_CERTGETALLSUBJECTNAMESFAILED);
michael@0 3503 }
michael@0 3504
michael@0 3505 state->status = BUILD_INITIAL;
michael@0 3506
michael@0 3507 pkixErrorResult =
michael@0 3508 pkix_BuildForwardDepthFirstSearch(&nbioContext, state,
michael@0 3509 &valResult, plContext);
michael@0 3510
michael@0 3511 /* non-null nbioContext means the build would block */
michael@0 3512 if (pkixErrorResult == NULL && nbioContext != NULL) {
michael@0 3513
michael@0 3514 *pNBIOContext = nbioContext;
michael@0 3515 *pBuildResult = NULL;
michael@0 3516
michael@0 3517 /* no valResult means the build has failed */
michael@0 3518 } else {
michael@0 3519 if (pVerifyNode != NULL) {
michael@0 3520 PKIX_INCREF(state->verifyNode);
michael@0 3521 *pVerifyNode = state->verifyNode;
michael@0 3522 }
michael@0 3523
michael@0 3524 if (valResult == NULL || pkixErrorResult)
michael@0 3525 PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN);
michael@0 3526 PKIX_CHECK(
michael@0 3527 pkix_BuildResult_Create(valResult, state->trustChain,
michael@0 3528 &buildResult, plContext),
michael@0 3529 PKIX_BUILDRESULTCREATEFAILED);
michael@0 3530 *pBuildResult = buildResult;
michael@0 3531 }
michael@0 3532
michael@0 3533 *pState = state;
michael@0 3534 state = NULL;
michael@0 3535
michael@0 3536 cleanup:
michael@0 3537
michael@0 3538 PKIX_DECREF(targetConstraints);
michael@0 3539 PKIX_DECREF(targetParams);
michael@0 3540 PKIX_DECREF(anchors);
michael@0 3541 PKIX_DECREF(targetSubjNames);
michael@0 3542 PKIX_DECREF(targetCert);
michael@0 3543 PKIX_DECREF(revChecker);
michael@0 3544 PKIX_DECREF(certStores);
michael@0 3545 PKIX_DECREF(certStore);
michael@0 3546 PKIX_DECREF(userCheckers);
michael@0 3547 PKIX_DECREF(hintCerts);
michael@0 3548 PKIX_DECREF(firstHintCert);
michael@0 3549 PKIX_DECREF(testDate);
michael@0 3550 PKIX_DECREF(targetPubKey);
michael@0 3551 PKIX_DECREF(tentativeChain);
michael@0 3552 PKIX_DECREF(valResult);
michael@0 3553 PKIX_DECREF(certList);
michael@0 3554 PKIX_DECREF(trustedCert);
michael@0 3555 PKIX_DECREF(state);
michael@0 3556 PKIX_DECREF(aiaMgr);
michael@0 3557
michael@0 3558 PKIX_RETURN(BUILD);
michael@0 3559 }
michael@0 3560
michael@0 3561 /*
michael@0 3562 * FUNCTION: pkix_Build_ResumeBuildChain
michael@0 3563 * DESCRIPTION:
michael@0 3564 *
michael@0 3565 * This function continues the search for a BuildChain, using the parameters
michael@0 3566 * provided in "procParams" and the ForwardBuilderState pointed to by "state".
michael@0 3567 *
michael@0 3568 * If a successful chain is built, this function stores the BuildResult at
michael@0 3569 * "pBuildResult". Alternatively, if an operation using non-blocking I/O
michael@0 3570 * is in progress and the operation has not been completed, this function
michael@0 3571 * stores the FowardBuilderState at "pState" and NULL at "pBuildResult".
michael@0 3572 * Finally, if chain building was unsuccessful, this function stores NULL
michael@0 3573 * at both "pState" and at "pBuildResult".
michael@0 3574 *
michael@0 3575 * PARAMETERS:
michael@0 3576 * "pNBIOContext"
michael@0 3577 * Address at which the NBIOContext is stored indicating whether the
michael@0 3578 * validation is complete. Must be non-NULL.
michael@0 3579 * "pState"
michael@0 3580 * Address at which the ForwardBuilderState is provided for resumption of
michael@0 3581 * the chain building attempt; also, the address at which the
michael@0 3582 * ForwardBuilderStateis stored, if the chain building is suspended for
michael@0 3583 * waiting I/O. Must be non-NULL.
michael@0 3584 * "pBuildResult"
michael@0 3585 * Address at which the BuildResult is stored, after a successful build.
michael@0 3586 * Must be non-NULL.
michael@0 3587 * "plContext"
michael@0 3588 * Platform-specific context pointer.
michael@0 3589 * THREAD SAFETY:
michael@0 3590 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
michael@0 3591 * RETURNS:
michael@0 3592 * Returns NULL if the function succeeds.
michael@0 3593 * Returns a Build Error if the function fails in a non-fatal way
michael@0 3594 * Returns a Fatal Error if the function fails in an unrecoverable way.
michael@0 3595 */
michael@0 3596 static PKIX_Error *
michael@0 3597 pkix_Build_ResumeBuildChain(
michael@0 3598 void **pNBIOContext,
michael@0 3599 PKIX_ForwardBuilderState *state,
michael@0 3600 PKIX_BuildResult **pBuildResult,
michael@0 3601 PKIX_VerifyNode **pVerifyNode,
michael@0 3602 void *plContext)
michael@0 3603 {
michael@0 3604 PKIX_ValidateResult *valResult = NULL;
michael@0 3605 PKIX_BuildResult *buildResult = NULL;
michael@0 3606 void *nbioContext = NULL;
michael@0 3607
michael@0 3608 PKIX_ENTER(BUILD, "pkix_Build_ResumeBuildChain");
michael@0 3609 PKIX_NULLCHECK_TWO(state, pBuildResult);
michael@0 3610
michael@0 3611 nbioContext = *pNBIOContext;
michael@0 3612 *pNBIOContext = NULL;
michael@0 3613
michael@0 3614 pkixErrorResult =
michael@0 3615 pkix_BuildForwardDepthFirstSearch(&nbioContext, state,
michael@0 3616 &valResult, plContext);
michael@0 3617
michael@0 3618 /* non-null nbioContext means the build would block */
michael@0 3619 if (pkixErrorResult == NULL && nbioContext != NULL) {
michael@0 3620
michael@0 3621 *pNBIOContext = nbioContext;
michael@0 3622 *pBuildResult = NULL;
michael@0 3623
michael@0 3624 /* no valResult means the build has failed */
michael@0 3625 } else {
michael@0 3626 if (pVerifyNode != NULL) {
michael@0 3627 PKIX_INCREF(state->verifyNode);
michael@0 3628 *pVerifyNode = state->verifyNode;
michael@0 3629 }
michael@0 3630
michael@0 3631 if (valResult == NULL || pkixErrorResult)
michael@0 3632 PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN);
michael@0 3633
michael@0 3634 PKIX_CHECK(
michael@0 3635 pkix_BuildResult_Create(valResult, state->trustChain,
michael@0 3636 &buildResult, plContext),
michael@0 3637 PKIX_BUILDRESULTCREATEFAILED);
michael@0 3638 *pBuildResult = buildResult;
michael@0 3639 }
michael@0 3640
michael@0 3641 cleanup:
michael@0 3642
michael@0 3643 PKIX_DECREF(valResult);
michael@0 3644
michael@0 3645 PKIX_RETURN(BUILD);
michael@0 3646 }
michael@0 3647
michael@0 3648 /* --Public-Functions--------------------------------------------- */
michael@0 3649
michael@0 3650 /*
michael@0 3651 * FUNCTION: PKIX_BuildChain (see comments in pkix.h)
michael@0 3652 */
michael@0 3653 PKIX_Error *
michael@0 3654 PKIX_BuildChain(
michael@0 3655 PKIX_ProcessingParams *procParams,
michael@0 3656 void **pNBIOContext,
michael@0 3657 void **pState,
michael@0 3658 PKIX_BuildResult **pBuildResult,
michael@0 3659 PKIX_VerifyNode **pVerifyNode,
michael@0 3660 void *plContext)
michael@0 3661 {
michael@0 3662 PKIX_ForwardBuilderState *state = NULL;
michael@0 3663 PKIX_BuildResult *buildResult = NULL;
michael@0 3664 void *nbioContext = NULL;
michael@0 3665
michael@0 3666 PKIX_ENTER(BUILD, "PKIX_BuildChain");
michael@0 3667 PKIX_NULLCHECK_FOUR(procParams, pNBIOContext, pState, pBuildResult);
michael@0 3668
michael@0 3669 nbioContext = *pNBIOContext;
michael@0 3670 *pNBIOContext = NULL;
michael@0 3671
michael@0 3672 if (*pState == NULL) {
michael@0 3673 PKIX_CHECK(pkix_Build_InitiateBuildChain
michael@0 3674 (procParams,
michael@0 3675 &nbioContext,
michael@0 3676 &state,
michael@0 3677 &buildResult,
michael@0 3678 pVerifyNode,
michael@0 3679 plContext),
michael@0 3680 PKIX_BUILDINITIATEBUILDCHAINFAILED);
michael@0 3681 } else {
michael@0 3682 state = (PKIX_ForwardBuilderState *)(*pState);
michael@0 3683 *pState = NULL; /* no net change in reference count */
michael@0 3684 if (state->status == BUILD_SHORTCUTPENDING) {
michael@0 3685 PKIX_CHECK(pkix_Build_InitiateBuildChain
michael@0 3686 (procParams,
michael@0 3687 &nbioContext,
michael@0 3688 &state,
michael@0 3689 &buildResult,
michael@0 3690 pVerifyNode,
michael@0 3691 plContext),
michael@0 3692 PKIX_BUILDINITIATEBUILDCHAINFAILED);
michael@0 3693 } else {
michael@0 3694 PKIX_CHECK(pkix_Build_ResumeBuildChain
michael@0 3695 (&nbioContext,
michael@0 3696 state,
michael@0 3697 &buildResult,
michael@0 3698 pVerifyNode,
michael@0 3699 plContext),
michael@0 3700 PKIX_BUILDINITIATEBUILDCHAINFAILED);
michael@0 3701 }
michael@0 3702 }
michael@0 3703
michael@0 3704 /* non-null nbioContext means the build would block */
michael@0 3705 if (nbioContext != NULL) {
michael@0 3706
michael@0 3707 *pNBIOContext = nbioContext;
michael@0 3708 *pState = state;
michael@0 3709 state = NULL;
michael@0 3710 *pBuildResult = NULL;
michael@0 3711
michael@0 3712 /* no buildResult means the build has failed */
michael@0 3713 } else if (buildResult == NULL) {
michael@0 3714 PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN);
michael@0 3715 } else {
michael@0 3716 /*
michael@0 3717 * If we made a successful chain by combining the target Cert
michael@0 3718 * with one of the Trust Anchors, we may have never created a
michael@0 3719 * validityDate. We treat this situation as
michael@0 3720 * canBeCached = PKIX_FALSE.
michael@0 3721 */
michael@0 3722 if ((state != NULL) &&
michael@0 3723 ((state->validityDate) != NULL) &&
michael@0 3724 (state->canBeCached)) {
michael@0 3725 PKIX_CHECK(pkix_CacheCertChain_Add
michael@0 3726 (state->buildConstants.targetCert,
michael@0 3727 state->buildConstants.anchors,
michael@0 3728 state->validityDate,
michael@0 3729 buildResult,
michael@0 3730 plContext),
michael@0 3731 PKIX_CACHECERTCHAINADDFAILED);
michael@0 3732 }
michael@0 3733
michael@0 3734 *pState = NULL;
michael@0 3735 *pBuildResult = buildResult;
michael@0 3736 buildResult = NULL;
michael@0 3737 }
michael@0 3738
michael@0 3739 cleanup:
michael@0 3740 PKIX_DECREF(buildResult);
michael@0 3741 PKIX_DECREF(state);
michael@0 3742
michael@0 3743 PKIX_RETURN(BUILD);
michael@0 3744 }

mercurial