Thu, 22 Jan 2015 13:21:57 +0100
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, ¶msNeeded, 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, ¤tIssuer, 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, ¬After, 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 | } |