| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 /* | |
| 5 * pkix_targetcertchecker.c | |
| 6 * | |
| 7 * Functions for target cert validation | |
| 8 * | |
| 9 */ | |
| 10 | |
| 11 | |
| 12 #include "pkix_targetcertchecker.h" | |
| 13 | |
| 14 /* --Private-TargetCertCheckerState-Functions------------------------------- */ | |
| 15 | |
| 16 /* | |
| 17 * FUNCTION: pkix_TargetCertCheckerState_Destroy | |
| 18 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) | |
| 19 */ | |
| 20 static PKIX_Error * | |
| 21 pkix_TargetCertCheckerState_Destroy( | |
| 22 PKIX_PL_Object *object, | |
| 23 void *plContext) | |
| 24 { | |
| 25 pkix_TargetCertCheckerState *state = NULL; | |
| 26 | |
| 27 PKIX_ENTER(TARGETCERTCHECKERSTATE, | |
| 28 "pkix_TargetCertCheckerState_Destroy"); | |
| 29 PKIX_NULLCHECK_ONE(object); | |
| 30 | |
| 31 /* Check that this object is a target cert checker state */ | |
| 32 PKIX_CHECK(pkix_CheckType | |
| 33 (object, PKIX_TARGETCERTCHECKERSTATE_TYPE, plContext), | |
| 34 PKIX_OBJECTNOTTARGETCERTCHECKERSTATE); | |
| 35 | |
| 36 state = (pkix_TargetCertCheckerState *)object; | |
| 37 | |
| 38 PKIX_DECREF(state->certSelector); | |
| 39 PKIX_DECREF(state->extKeyUsageOID); | |
| 40 PKIX_DECREF(state->subjAltNameOID); | |
| 41 PKIX_DECREF(state->pathToNameList); | |
| 42 PKIX_DECREF(state->extKeyUsageList); | |
| 43 PKIX_DECREF(state->subjAltNameList); | |
| 44 | |
| 45 cleanup: | |
| 46 | |
| 47 PKIX_RETURN(TARGETCERTCHECKERSTATE); | |
| 48 } | |
| 49 | |
| 50 /* | |
| 51 * FUNCTION: pkix_TargetCertCheckerState_RegisterSelf | |
| 52 * DESCRIPTION: | |
| 53 * Registers PKIX_TARGETCERTCHECKERSTATE_TYPE and its related functions with | |
| 54 * systemClasses[] | |
| 55 * THREAD SAFETY: | |
| 56 * Not Thread Safe - for performance and complexity reasons | |
| 57 * | |
| 58 * Since this function is only called by PKIX_PL_Initialize, which should | |
| 59 * only be called once, it is acceptable that this function is not | |
| 60 * thread-safe. | |
| 61 */ | |
| 62 PKIX_Error * | |
| 63 pkix_TargetCertCheckerState_RegisterSelf(void *plContext) | |
| 64 { | |
| 65 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; | |
| 66 pkix_ClassTable_Entry entry; | |
| 67 | |
| 68 PKIX_ENTER(TARGETCERTCHECKERSTATE, | |
| 69 "pkix_TargetCertCheckerState_RegisterSelf"); | |
| 70 | |
| 71 entry.description = "TargetCertCheckerState"; | |
| 72 entry.objCounter = 0; | |
| 73 entry.typeObjectSize = sizeof(pkix_TargetCertCheckerState); | |
| 74 entry.destructor = pkix_TargetCertCheckerState_Destroy; | |
| 75 entry.equalsFunction = NULL; | |
| 76 entry.hashcodeFunction = NULL; | |
| 77 entry.toStringFunction = NULL; | |
| 78 entry.comparator = NULL; | |
| 79 entry.duplicateFunction = NULL; | |
| 80 | |
| 81 systemClasses[PKIX_TARGETCERTCHECKERSTATE_TYPE] = entry; | |
| 82 | |
| 83 PKIX_RETURN(TARGETCERTCHECKERSTATE); | |
| 84 } | |
| 85 | |
| 86 /* | |
| 87 * FUNCTION: pkix_TargetCertCheckerState_Create | |
| 88 * DESCRIPTION: | |
| 89 * | |
| 90 * Creates a new TargetCertCheckerState using the CertSelector pointed to | |
| 91 * by "certSelector" and the number of certs represented by "certsRemaining" | |
| 92 * and stores it at "pState". | |
| 93 * | |
| 94 * PARAMETERS: | |
| 95 * "certSelector" | |
| 96 * Address of CertSelector representing the criteria against which the | |
| 97 * final certificate in a chain is to be matched. Must be non-NULL. | |
| 98 * "certsRemaining" | |
| 99 * Number of certificates remaining in the chain. | |
| 100 * "pState" | |
| 101 * Address where object pointer will be stored. Must be non-NULL. | |
| 102 * "plContext" | |
| 103 * Platform-specific context pointer. | |
| 104 * THREAD SAFETY: | |
| 105 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
| 106 * RETURNS: | |
| 107 * Returns NULL if the function succeeds. | |
| 108 * Returns a TargetCertCheckerState Error if the function fails in a | |
| 109 * non-fatal way. | |
| 110 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
| 111 */ | |
| 112 PKIX_Error * | |
| 113 pkix_TargetCertCheckerState_Create( | |
| 114 PKIX_CertSelector *certSelector, | |
| 115 PKIX_UInt32 certsRemaining, | |
| 116 pkix_TargetCertCheckerState **pState, | |
| 117 void *plContext) | |
| 118 { | |
| 119 pkix_TargetCertCheckerState *state = NULL; | |
| 120 PKIX_ComCertSelParams *certSelectorParams = NULL; | |
| 121 PKIX_List *pathToNameList = NULL; | |
| 122 PKIX_List *extKeyUsageList = NULL; | |
| 123 PKIX_List *subjAltNameList = NULL; | |
| 124 PKIX_PL_OID *extKeyUsageOID = NULL; | |
| 125 PKIX_PL_OID *subjAltNameOID = NULL; | |
| 126 PKIX_Boolean subjAltNameMatchAll = PKIX_TRUE; | |
| 127 | |
| 128 PKIX_ENTER(TARGETCERTCHECKERSTATE, | |
| 129 "pkix_TargetCertCheckerState_Create"); | |
| 130 PKIX_NULLCHECK_ONE(pState); | |
| 131 | |
| 132 PKIX_CHECK(PKIX_PL_OID_Create | |
| 133 (PKIX_EXTENDEDKEYUSAGE_OID, | |
| 134 &extKeyUsageOID, | |
| 135 plContext), | |
| 136 PKIX_OIDCREATEFAILED); | |
| 137 | |
| 138 PKIX_CHECK(PKIX_PL_OID_Create | |
| 139 (PKIX_CERTSUBJALTNAME_OID, | |
| 140 &subjAltNameOID, | |
| 141 plContext), | |
| 142 PKIX_OIDCREATEFAILED); | |
| 143 | |
| 144 PKIX_CHECK(PKIX_PL_Object_Alloc | |
| 145 (PKIX_TARGETCERTCHECKERSTATE_TYPE, | |
| 146 sizeof (pkix_TargetCertCheckerState), | |
| 147 (PKIX_PL_Object **)&state, | |
| 148 plContext), | |
| 149 PKIX_COULDNOTCREATETARGETCERTCHECKERSTATEOBJECT); | |
| 150 | |
| 151 /* initialize fields */ | |
| 152 | |
| 153 if (certSelector != NULL) { | |
| 154 | |
| 155 PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams | |
| 156 (certSelector, &certSelectorParams, plContext), | |
| 157 PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMFAILED); | |
| 158 | |
| 159 if (certSelectorParams != NULL) { | |
| 160 | |
| 161 PKIX_CHECK(PKIX_ComCertSelParams_GetPathToNames | |
| 162 (certSelectorParams, | |
| 163 &pathToNameList, | |
| 164 plContext), | |
| 165 PKIX_COMCERTSELPARAMSGETPATHTONAMESFAILED); | |
| 166 | |
| 167 PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage | |
| 168 (certSelectorParams, | |
| 169 &extKeyUsageList, | |
| 170 plContext), | |
| 171 PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); | |
| 172 | |
| 173 PKIX_CHECK(PKIX_ComCertSelParams_GetSubjAltNames | |
| 174 (certSelectorParams, | |
| 175 &subjAltNameList, | |
| 176 plContext), | |
| 177 PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED); | |
| 178 | |
| 179 PKIX_CHECK(PKIX_ComCertSelParams_GetMatchAllSubjAltNames | |
| 180 (certSelectorParams, | |
| 181 &subjAltNameMatchAll, | |
| 182 plContext), | |
| 183 PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED); | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 state->certsRemaining = certsRemaining; | |
| 188 state->subjAltNameMatchAll = subjAltNameMatchAll; | |
| 189 | |
| 190 PKIX_INCREF(certSelector); | |
| 191 state->certSelector = certSelector; | |
| 192 | |
| 193 state->pathToNameList = pathToNameList; | |
| 194 pathToNameList = NULL; | |
| 195 | |
| 196 state->extKeyUsageList = extKeyUsageList; | |
| 197 extKeyUsageList = NULL; | |
| 198 | |
| 199 state->subjAltNameList = subjAltNameList; | |
| 200 subjAltNameList = NULL; | |
| 201 | |
| 202 state->extKeyUsageOID = extKeyUsageOID; | |
| 203 extKeyUsageOID = NULL; | |
| 204 | |
| 205 state->subjAltNameOID = subjAltNameOID; | |
| 206 subjAltNameOID = NULL; | |
| 207 | |
| 208 *pState = state; | |
| 209 state = NULL; | |
| 210 | |
| 211 cleanup: | |
| 212 | |
| 213 PKIX_DECREF(extKeyUsageOID); | |
| 214 PKIX_DECREF(subjAltNameOID); | |
| 215 PKIX_DECREF(pathToNameList); | |
| 216 PKIX_DECREF(extKeyUsageList); | |
| 217 PKIX_DECREF(subjAltNameList); | |
| 218 PKIX_DECREF(state); | |
| 219 | |
| 220 PKIX_DECREF(certSelectorParams); | |
| 221 | |
| 222 PKIX_RETURN(TARGETCERTCHECKERSTATE); | |
| 223 | |
| 224 } | |
| 225 | |
| 226 /* --Private-TargetCertChecker-Functions------------------------------- */ | |
| 227 | |
| 228 /* | |
| 229 * FUNCTION: pkix_TargetCertChecker_Check | |
| 230 * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) | |
| 231 */ | |
| 232 PKIX_Error * | |
| 233 pkix_TargetCertChecker_Check( | |
| 234 PKIX_CertChainChecker *checker, | |
| 235 PKIX_PL_Cert *cert, | |
| 236 PKIX_List *unresolvedCriticalExtensions, | |
| 237 void **pNBIOContext, | |
| 238 void *plContext) | |
| 239 { | |
| 240 pkix_TargetCertCheckerState *state = NULL; | |
| 241 PKIX_CertSelector_MatchCallback certSelectorMatch = NULL; | |
| 242 PKIX_PL_CertNameConstraints *nameConstraints = NULL; | |
| 243 PKIX_List *certSubjAltNames = NULL; | |
| 244 PKIX_List *certExtKeyUsageList = NULL; | |
| 245 PKIX_PL_GeneralName *name = NULL; | |
| 246 PKIX_PL_X500Name *certSubjectName = NULL; | |
| 247 PKIX_Boolean checkPassed = PKIX_FALSE; | |
| 248 PKIX_UInt32 numItems, i; | |
| 249 PKIX_UInt32 matchCount = 0; | |
| 250 | |
| 251 PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Check"); | |
| 252 PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); | |
| 253 | |
| 254 *pNBIOContext = NULL; /* we never block on pending I/O */ | |
| 255 | |
| 256 PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState | |
| 257 (checker, (PKIX_PL_Object **)&state, plContext), | |
| 258 PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); | |
| 259 | |
| 260 (state->certsRemaining)--; | |
| 261 | |
| 262 if (state->pathToNameList != NULL) { | |
| 263 | |
| 264 PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints | |
| 265 (cert, &nameConstraints, plContext), | |
| 266 PKIX_CERTGETNAMECONSTRAINTSFAILED); | |
| 267 | |
| 268 /* | |
| 269 * XXX We should either make the following call a public one | |
| 270 * so it is legal to call from the portability layer or we | |
| 271 * should try to create pathToNameList as CertNameConstraints | |
| 272 * then call the existing check function. | |
| 273 */ | |
| 274 PKIX_CHECK(PKIX_PL_CertNameConstraints_CheckNamesInNameSpace | |
| 275 (state->pathToNameList, | |
| 276 nameConstraints, | |
| 277 &checkPassed, | |
| 278 plContext), | |
| 279 PKIX_CERTNAMECONSTRAINTSCHECKNAMEINNAMESPACEFAILED); | |
| 280 | |
| 281 if (checkPassed != PKIX_TRUE) { | |
| 282 PKIX_ERROR(PKIX_VALIDATIONFAILEDPATHTONAMECHECKFAILED); | |
| 283 } | |
| 284 | |
| 285 } | |
| 286 | |
| 287 PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames | |
| 288 (cert, &certSubjAltNames, plContext), | |
| 289 PKIX_CERTGETSUBJALTNAMESFAILED); | |
| 290 | |
| 291 if (state->subjAltNameList != NULL && certSubjAltNames != NULL) { | |
| 292 | |
| 293 PKIX_CHECK(PKIX_List_GetLength | |
| 294 (state->subjAltNameList, &numItems, plContext), | |
| 295 PKIX_LISTGETLENGTHFAILED); | |
| 296 | |
| 297 for (i = 0; i < numItems; i++) { | |
| 298 | |
| 299 PKIX_CHECK(PKIX_List_GetItem | |
| 300 (state->subjAltNameList, | |
| 301 i, | |
| 302 (PKIX_PL_Object **) &name, | |
| 303 plContext), | |
| 304 PKIX_LISTGETITEMFAILED); | |
| 305 | |
| 306 PKIX_CHECK(pkix_List_Contains | |
| 307 (certSubjAltNames, | |
| 308 (PKIX_PL_Object *) name, | |
| 309 &checkPassed, | |
| 310 plContext), | |
| 311 PKIX_LISTCONTAINSFAILED); | |
| 312 | |
| 313 PKIX_DECREF(name); | |
| 314 | |
| 315 if (checkPassed == PKIX_TRUE) { | |
| 316 | |
| 317 if (state->subjAltNameMatchAll == PKIX_FALSE) { | |
| 318 matchCount = numItems; | |
| 319 break; | |
| 320 } else { | |
| 321 /* else continue checking next */ | |
| 322 matchCount++; | |
| 323 } | |
| 324 | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 if (matchCount != numItems) { | |
| 329 PKIX_ERROR(PKIX_SUBJALTNAMECHECKFAILED); | |
| 330 | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 if (state->certsRemaining == 0) { | |
| 335 | |
| 336 if (state->certSelector != NULL) { | |
| 337 PKIX_CHECK(PKIX_CertSelector_GetMatchCallback | |
| 338 (state->certSelector, | |
| 339 &certSelectorMatch, | |
| 340 plContext), | |
| 341 PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); | |
| 342 | |
| 343 PKIX_CHECK(certSelectorMatch | |
| 344 (state->certSelector, | |
| 345 cert, | |
| 346 plContext), | |
| 347 PKIX_CERTSELECTORMATCHFAILED); | |
| 348 } else { | |
| 349 /* Check at least cert/key usages if target cert selector | |
| 350 * is not set. */ | |
| 351 PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, | |
| 352 PKIX_FALSE /* is chain cert*/, | |
| 353 plContext), | |
| 354 PKIX_CERTVERIFYCERTTYPEFAILED); | |
| 355 } | |
| 356 /* | |
| 357 * There are two Extended Key Usage Checkings | |
| 358 * available : | |
| 359 * 1) here at the targetcertchecker where we | |
| 360 * verify the Extended Key Usage OIDs application | |
| 361 * specifies via ComCertSelParams are included | |
| 362 * in Cert's Extended Key Usage OID's. Note, | |
| 363 * this is an OID to OID comparison and only last | |
| 364 * Cert is checked. | |
| 365 * 2) at user defined ekuchecker where checking | |
| 366 * is applied to all Certs on the chain and | |
| 367 * the NSS Extended Key Usage algorithm is | |
| 368 * used. In order to invoke this checking, not | |
| 369 * only does the ComCertSelparams needs to be | |
| 370 * set, the EKU initialize call is required to | |
| 371 * activate the checking. | |
| 372 * | |
| 373 * XXX We use the same ComCertSelParams Set/Get | |
| 374 * functions to set the parameters for both cases. | |
| 375 * We may want to separate them in the future. | |
| 376 */ | |
| 377 | |
| 378 PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage | |
| 379 (cert, &certExtKeyUsageList, plContext), | |
| 380 PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); | |
| 381 | |
| 382 | |
| 383 if (state->extKeyUsageList != NULL && | |
| 384 certExtKeyUsageList != NULL) { | |
| 385 | |
| 386 PKIX_CHECK(PKIX_List_GetLength | |
| 387 (state->extKeyUsageList, &numItems, plContext), | |
| 388 PKIX_LISTGETLENGTHFAILED); | |
| 389 | |
| 390 for (i = 0; i < numItems; i++) { | |
| 391 | |
| 392 PKIX_CHECK(PKIX_List_GetItem | |
| 393 (state->extKeyUsageList, | |
| 394 i, | |
| 395 (PKIX_PL_Object **) &name, | |
| 396 plContext), | |
| 397 PKIX_LISTGETITEMFAILED); | |
| 398 | |
| 399 PKIX_CHECK(pkix_List_Contains | |
| 400 (certExtKeyUsageList, | |
| 401 (PKIX_PL_Object *) name, | |
| 402 &checkPassed, | |
| 403 plContext), | |
| 404 PKIX_LISTCONTAINSFAILED); | |
| 405 | |
| 406 PKIX_DECREF(name); | |
| 407 | |
| 408 if (checkPassed != PKIX_TRUE) { | |
| 409 PKIX_ERROR | |
| 410 (PKIX_EXTENDEDKEYUSAGECHECKINGFAILED); | |
| 411 | |
| 412 } | |
| 413 } | |
| 414 } | |
| 415 } else { | |
| 416 /* Check key usage and cert type based on certificate usage. */ | |
| 417 PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, PKIX_TRUE, | |
| 418 plContext), | |
| 419 PKIX_CERTVERIFYCERTTYPEFAILED); | |
| 420 } | |
| 421 | |
| 422 /* Remove Critical Extension OID from list */ | |
| 423 if (unresolvedCriticalExtensions != NULL) { | |
| 424 | |
| 425 PKIX_CHECK(pkix_List_Remove | |
| 426 (unresolvedCriticalExtensions, | |
| 427 (PKIX_PL_Object *) state->extKeyUsageOID, | |
| 428 plContext), | |
| 429 PKIX_LISTREMOVEFAILED); | |
| 430 | |
| 431 PKIX_CHECK(PKIX_PL_Cert_GetSubject | |
| 432 (cert, &certSubjectName, plContext), | |
| 433 PKIX_CERTGETSUBJECTFAILED); | |
| 434 | |
| 435 if (certSubjAltNames != NULL) { | |
| 436 PKIX_CHECK(pkix_List_Remove | |
| 437 (unresolvedCriticalExtensions, | |
| 438 (PKIX_PL_Object *) state->subjAltNameOID, | |
| 439 plContext), | |
| 440 PKIX_LISTREMOVEFAILED); | |
| 441 } | |
| 442 | |
| 443 } | |
| 444 | |
| 445 cleanup: | |
| 446 | |
| 447 PKIX_DECREF(name); | |
| 448 PKIX_DECREF(nameConstraints); | |
| 449 PKIX_DECREF(certSubjAltNames); | |
| 450 PKIX_DECREF(certExtKeyUsageList); | |
| 451 PKIX_DECREF(certSubjectName); | |
| 452 PKIX_DECREF(state); | |
| 453 | |
| 454 PKIX_RETURN(CERTCHAINCHECKER); | |
| 455 | |
| 456 } | |
| 457 | |
| 458 /* | |
| 459 * FUNCTION: pkix_TargetCertChecker_Initialize | |
| 460 * DESCRIPTION: | |
| 461 * | |
| 462 * Creates a new CertChainChecker and stores it at "pChecker", where it will | |
| 463 * used by pkix_TargetCertChecker_Check to check that the final certificate | |
| 464 * of a chain meets the criteria of the CertSelector pointed to by | |
| 465 * "certSelector". The number of certs remaining in the chain, represented by | |
| 466 * "certsRemaining" is used to initialize the checker's state. | |
| 467 * | |
| 468 * PARAMETERS: | |
| 469 * "certSelector" | |
| 470 * Address of CertSelector representing the criteria against which the | |
| 471 * final certificate in a chain is to be matched. May be NULL. | |
| 472 * "certsRemaining" | |
| 473 * Number of certificates remaining in the chain. | |
| 474 * "pChecker" | |
| 475 * Address where object pointer will be stored. Must be non-NULL. | |
| 476 * "plContext" | |
| 477 * Platform-specific context pointer. | |
| 478 * THREAD SAFETY: | |
| 479 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
| 480 * RETURNS: | |
| 481 * Returns NULL if the function succeeds. | |
| 482 * Returns a CertChainChecker Error if the function fails in a non-fatal way. | |
| 483 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
| 484 */ | |
| 485 PKIX_Error * | |
| 486 pkix_TargetCertChecker_Initialize( | |
| 487 PKIX_CertSelector *certSelector, | |
| 488 PKIX_UInt32 certsRemaining, | |
| 489 PKIX_CertChainChecker **pChecker, | |
| 490 void *plContext) | |
| 491 { | |
| 492 pkix_TargetCertCheckerState *state = NULL; | |
| 493 | |
| 494 PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Initialize"); | |
| 495 PKIX_NULLCHECK_ONE(pChecker); | |
| 496 | |
| 497 PKIX_CHECK(pkix_TargetCertCheckerState_Create | |
| 498 (certSelector, certsRemaining, &state, plContext), | |
| 499 PKIX_TARGETCERTCHECKERSTATECREATEFAILED); | |
| 500 | |
| 501 PKIX_CHECK(PKIX_CertChainChecker_Create | |
| 502 (pkix_TargetCertChecker_Check, | |
| 503 PKIX_FALSE, | |
| 504 PKIX_FALSE, | |
| 505 NULL, | |
| 506 (PKIX_PL_Object *)state, | |
| 507 pChecker, | |
| 508 plContext), | |
| 509 PKIX_CERTCHAINCHECKERCREATEFAILED); | |
| 510 | |
| 511 cleanup: | |
| 512 | |
| 513 PKIX_DECREF(state); | |
| 514 | |
| 515 PKIX_RETURN(CERTCHAINCHECKER); | |
| 516 } | |
| OLD | NEW |