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_validate.c |
michael@0 | 6 | * |
michael@0 | 7 | * Top level validateChain function |
michael@0 | 8 | * |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | #include "pkix_validate.h" |
michael@0 | 12 | #include "pkix_pl_common.h" |
michael@0 | 13 | |
michael@0 | 14 | /* --Private-Functions-------------------------------------------- */ |
michael@0 | 15 | |
michael@0 | 16 | /* |
michael@0 | 17 | * FUNCTION: pkix_AddToVerifyLog |
michael@0 | 18 | * DESCRIPTION: |
michael@0 | 19 | * |
michael@0 | 20 | * This function returns immediately if the address for the VerifyNode tree |
michael@0 | 21 | * pointed to by "pVerifyTree" is NULL. Otherwise it creates a new VerifyNode |
michael@0 | 22 | * from the Cert pointed to by "cert" and the Error pointed to by "error", |
michael@0 | 23 | * and inserts it at the depth in the VerifyNode tree determined by "depth". A |
michael@0 | 24 | * depth of zero means that this function creates the root node of a new tree. |
michael@0 | 25 | * |
michael@0 | 26 | * Note: this function does not include the means of choosing among branches |
michael@0 | 27 | * of a tree. It is intended for non-branching trees, that is, where each |
michael@0 | 28 | * parent node has only a single child node. |
michael@0 | 29 | * |
michael@0 | 30 | * PARAMETERS: |
michael@0 | 31 | * "cert" |
michael@0 | 32 | * The address of the Cert to be included in the new VerifyNode. Must be |
michael@0 | 33 | * non-NULL. |
michael@0 | 34 | * "depth" |
michael@0 | 35 | * The UInt32 value of the depth. |
michael@0 | 36 | * "error" |
michael@0 | 37 | * The address of the Error to be included in the new VerifyNode. |
michael@0 | 38 | * "pVerifyTree" |
michael@0 | 39 | * The address of the VerifyNode tree into which the created VerifyNode |
michael@0 | 40 | * is to be inserted. The node is not created if VerifyTree is NULL. |
michael@0 | 41 | * "plContext" |
michael@0 | 42 | * Platform-specific context pointer. |
michael@0 | 43 | * THREAD SAFETY: |
michael@0 | 44 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 45 | * RETURNS: |
michael@0 | 46 | * Returns NULL if the function succeeds. |
michael@0 | 47 | * Returns a Validate Error if the function fails in a non-fatal way. |
michael@0 | 48 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 49 | */ |
michael@0 | 50 | static PKIX_Error * |
michael@0 | 51 | pkix_AddToVerifyLog( |
michael@0 | 52 | PKIX_PL_Cert *cert, |
michael@0 | 53 | PKIX_UInt32 depth, |
michael@0 | 54 | PKIX_Error *error, |
michael@0 | 55 | PKIX_VerifyNode **pVerifyTree, |
michael@0 | 56 | void *plContext) |
michael@0 | 57 | { |
michael@0 | 58 | |
michael@0 | 59 | PKIX_VerifyNode *verifyNode = NULL; |
michael@0 | 60 | |
michael@0 | 61 | PKIX_ENTER(VALIDATE, "pkix_AddToVerifyLog"); |
michael@0 | 62 | PKIX_NULLCHECK_ONE(cert); |
michael@0 | 63 | |
michael@0 | 64 | if (pVerifyTree) { /* nothing to do if no address given for log */ |
michael@0 | 65 | |
michael@0 | 66 | PKIX_CHECK(pkix_VerifyNode_Create |
michael@0 | 67 | (cert, depth, error, &verifyNode, plContext), |
michael@0 | 68 | PKIX_VERIFYNODECREATEFAILED); |
michael@0 | 69 | |
michael@0 | 70 | if (depth == 0) { |
michael@0 | 71 | /* We just created the root node */ |
michael@0 | 72 | *pVerifyTree = verifyNode; |
michael@0 | 73 | } else { |
michael@0 | 74 | PKIX_CHECK(pkix_VerifyNode_AddToChain |
michael@0 | 75 | (*pVerifyTree, verifyNode, plContext), |
michael@0 | 76 | PKIX_VERIFYNODEADDTOCHAINFAILED); |
michael@0 | 77 | } |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | cleanup: |
michael@0 | 81 | |
michael@0 | 82 | PKIX_RETURN(VALIDATE); |
michael@0 | 83 | |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | /* |
michael@0 | 87 | * FUNCTION: pkix_CheckCert |
michael@0 | 88 | * DESCRIPTION: |
michael@0 | 89 | * |
michael@0 | 90 | * Checks whether the Cert pointed to by "cert" successfully validates |
michael@0 | 91 | * using the List of CertChainCheckers pointed to by "checkers". If the |
michael@0 | 92 | * certificate does not validate, an Error pointer is returned. |
michael@0 | 93 | * |
michael@0 | 94 | * This function should be called initially with the UInt32 pointed to by |
michael@0 | 95 | * "pCheckerIndex" containing zero, and the pointer at "pNBIOContext" |
michael@0 | 96 | * containing NULL. If a checker does non-blocking I/O, this function will |
michael@0 | 97 | * return with the index of that checker stored at "pCheckerIndex" and a |
michael@0 | 98 | * platform-dependent non-blocking I/O context stored at "pNBIOContext". |
michael@0 | 99 | * A subsequent call to this function with those values intact will allow the |
michael@0 | 100 | * checking to resume where it left off. This should be repeated until the |
michael@0 | 101 | * function returns with NULL stored at "pNBIOContext". |
michael@0 | 102 | * |
michael@0 | 103 | * PARAMETERS: |
michael@0 | 104 | * "cert" |
michael@0 | 105 | * Address of Cert to validate. Must be non-NULL. |
michael@0 | 106 | * "checkers" |
michael@0 | 107 | * List of CertChainCheckers which must each validate the certificate. |
michael@0 | 108 | * Must be non-NULL. |
michael@0 | 109 | * "checkedExtOIDs" |
michael@0 | 110 | * List of PKIX_PL_OID that has been processed. If called from building |
michael@0 | 111 | * chain, it is the list of critical extension OIDs that has been |
michael@0 | 112 | * processed prior to validation. May be NULL. |
michael@0 | 113 | * "pCheckerIndex" |
michael@0 | 114 | * Address at which is stored the the index, within the List "checkers", |
michael@0 | 115 | * of a checker whose processing was interrupted by non-blocking I/O. |
michael@0 | 116 | * Must be non-NULL. |
michael@0 | 117 | * "pNBIOContext" |
michael@0 | 118 | * Address at which is stored platform-specific non-blocking I/O context. |
michael@0 | 119 | * Must be non-NULL. |
michael@0 | 120 | * "plContext" |
michael@0 | 121 | * Platform-specific context pointer. |
michael@0 | 122 | * THREAD SAFETY: |
michael@0 | 123 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 124 | * RETURNS: |
michael@0 | 125 | * Returns NULL if the function succeeds. |
michael@0 | 126 | * Returns a Validate Error if the function fails in a non-fatal way. |
michael@0 | 127 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 128 | */ |
michael@0 | 129 | static PKIX_Error * |
michael@0 | 130 | pkix_CheckCert( |
michael@0 | 131 | PKIX_PL_Cert *cert, |
michael@0 | 132 | PKIX_List *checkers, |
michael@0 | 133 | PKIX_List *checkedExtOIDsList, |
michael@0 | 134 | PKIX_UInt32 *pCheckerIndex, |
michael@0 | 135 | void **pNBIOContext, |
michael@0 | 136 | void *plContext) |
michael@0 | 137 | { |
michael@0 | 138 | PKIX_CertChainChecker_CheckCallback checkerCheck = NULL; |
michael@0 | 139 | PKIX_CertChainChecker *checker = NULL; |
michael@0 | 140 | PKIX_List *unresCritExtOIDs = NULL; |
michael@0 | 141 | PKIX_UInt32 numCheckers; |
michael@0 | 142 | PKIX_UInt32 numUnresCritExtOIDs = 0; |
michael@0 | 143 | PKIX_UInt32 checkerIndex = 0; |
michael@0 | 144 | void *nbioContext = NULL; |
michael@0 | 145 | |
michael@0 | 146 | PKIX_ENTER(VALIDATE, "pkix_CheckCert"); |
michael@0 | 147 | PKIX_NULLCHECK_FOUR(cert, checkers, pCheckerIndex, pNBIOContext); |
michael@0 | 148 | |
michael@0 | 149 | nbioContext = *pNBIOContext; |
michael@0 | 150 | *pNBIOContext = NULL; /* prepare for case of error exit */ |
michael@0 | 151 | |
michael@0 | 152 | PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs |
michael@0 | 153 | (cert, &unresCritExtOIDs, plContext), |
michael@0 | 154 | PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED); |
michael@0 | 155 | |
michael@0 | 156 | PKIX_CHECK(PKIX_List_GetLength(checkers, &numCheckers, plContext), |
michael@0 | 157 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 158 | |
michael@0 | 159 | for (checkerIndex = *pCheckerIndex; |
michael@0 | 160 | checkerIndex < numCheckers; |
michael@0 | 161 | checkerIndex++) { |
michael@0 | 162 | |
michael@0 | 163 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 164 | (checkers, |
michael@0 | 165 | checkerIndex, |
michael@0 | 166 | (PKIX_PL_Object **)&checker, |
michael@0 | 167 | plContext), |
michael@0 | 168 | PKIX_LISTGETITEMFAILED); |
michael@0 | 169 | |
michael@0 | 170 | PKIX_CHECK(PKIX_CertChainChecker_GetCheckCallback |
michael@0 | 171 | (checker, &checkerCheck, plContext), |
michael@0 | 172 | PKIX_CERTCHAINCHECKERGETCHECKCALLBACKFAILED); |
michael@0 | 173 | |
michael@0 | 174 | PKIX_CHECK(checkerCheck(checker, cert, unresCritExtOIDs, |
michael@0 | 175 | &nbioContext, plContext), |
michael@0 | 176 | PKIX_CERTCHAINCHECKERCHECKFAILED); |
michael@0 | 177 | |
michael@0 | 178 | if (nbioContext != NULL) { |
michael@0 | 179 | *pCheckerIndex = checkerIndex; |
michael@0 | 180 | *pNBIOContext = nbioContext; |
michael@0 | 181 | goto cleanup; |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | PKIX_DECREF(checker); |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | if (unresCritExtOIDs){ |
michael@0 | 188 | |
michael@0 | 189 | #ifdef PKIX_VALIDATEDEBUG |
michael@0 | 190 | { |
michael@0 | 191 | PKIX_PL_String *oidString = NULL; |
michael@0 | 192 | PKIX_UInt32 length; |
michael@0 | 193 | char *oidAscii = NULL; |
michael@0 | 194 | PKIX_TOSTRING(unresCritExtOIDs, &oidString, plContext, |
michael@0 | 195 | PKIX_LISTTOSTRINGFAILED); |
michael@0 | 196 | PKIX_CHECK(PKIX_PL_String_GetEncoded |
michael@0 | 197 | (oidString, |
michael@0 | 198 | PKIX_ESCASCII, |
michael@0 | 199 | (void **) &oidAscii, |
michael@0 | 200 | &length, |
michael@0 | 201 | plContext), |
michael@0 | 202 | PKIX_STRINGGETENCODEDFAILED); |
michael@0 | 203 | PKIX_VALIDATE_DEBUG_ARG |
michael@0 | 204 | ("unrecognized critical extension OIDs:" |
michael@0 | 205 | " %s\n", oidAscii); |
michael@0 | 206 | PKIX_DECREF(oidString); |
michael@0 | 207 | PKIX_PL_Free(oidAscii, plContext); |
michael@0 | 208 | } |
michael@0 | 209 | #endif |
michael@0 | 210 | |
michael@0 | 211 | if (checkedExtOIDsList != NULL) { |
michael@0 | 212 | /* Take out OID's that had been processed, if any */ |
michael@0 | 213 | PKIX_CHECK(pkix_List_RemoveItems |
michael@0 | 214 | (unresCritExtOIDs, |
michael@0 | 215 | checkedExtOIDsList, |
michael@0 | 216 | plContext), |
michael@0 | 217 | PKIX_LISTREMOVEITEMSFAILED); |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | PKIX_CHECK(PKIX_List_GetLength |
michael@0 | 221 | (unresCritExtOIDs, &numUnresCritExtOIDs, plContext), |
michael@0 | 222 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 223 | |
michael@0 | 224 | if (numUnresCritExtOIDs != 0){ |
michael@0 | 225 | PKIX_ERROR(PKIX_UNRECOGNIZEDCRITICALEXTENSION); |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | cleanup: |
michael@0 | 231 | |
michael@0 | 232 | PKIX_DECREF(checker); |
michael@0 | 233 | PKIX_DECREF(unresCritExtOIDs); |
michael@0 | 234 | |
michael@0 | 235 | PKIX_RETURN(VALIDATE); |
michael@0 | 236 | |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | /* |
michael@0 | 240 | * FUNCTION: pkix_InitializeCheckers |
michael@0 | 241 | * DESCRIPTION: |
michael@0 | 242 | * |
michael@0 | 243 | * Creates several checkers and initializes them with values derived from the |
michael@0 | 244 | * TrustAnchor pointed to by "anchor", the ProcessingParams pointed to by |
michael@0 | 245 | * "procParams", and the number of Certs in the Chain, represented by |
michael@0 | 246 | * "numCerts". The List of checkers is stored at "pCheckers". |
michael@0 | 247 | * |
michael@0 | 248 | * PARAMETERS: |
michael@0 | 249 | * "anchor" |
michael@0 | 250 | * Address of TrustAnchor used to initialize the SignatureChecker and |
michael@0 | 251 | * NameChainingChecker. Must be non-NULL. |
michael@0 | 252 | * "procParams" |
michael@0 | 253 | * Address of ProcessingParams used to initialize the ExpirationChecker |
michael@0 | 254 | * and TargetCertChecker. Must be non-NULL. |
michael@0 | 255 | * "numCerts" |
michael@0 | 256 | * Number of certificates in the CertChain. |
michael@0 | 257 | * "pCheckers" |
michael@0 | 258 | * Address where object pointer will be stored. Must be non-NULL. |
michael@0 | 259 | * "plContext" |
michael@0 | 260 | * Platform-specific context pointer. |
michael@0 | 261 | * THREAD SAFETY: |
michael@0 | 262 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 263 | * RETURNS: |
michael@0 | 264 | * Returns NULL if the function succeeds. |
michael@0 | 265 | * Returns a Validate Error if the function fails in a non-fatal way. |
michael@0 | 266 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 267 | */ |
michael@0 | 268 | static PKIX_Error * |
michael@0 | 269 | pkix_InitializeCheckers( |
michael@0 | 270 | PKIX_TrustAnchor *anchor, |
michael@0 | 271 | PKIX_ProcessingParams *procParams, |
michael@0 | 272 | PKIX_UInt32 numCerts, |
michael@0 | 273 | PKIX_List **pCheckers, |
michael@0 | 274 | void *plContext) |
michael@0 | 275 | { |
michael@0 | 276 | PKIX_CertChainChecker *targetCertChecker = NULL; |
michael@0 | 277 | PKIX_CertChainChecker *expirationChecker = NULL; |
michael@0 | 278 | PKIX_CertChainChecker *nameChainingChecker = NULL; |
michael@0 | 279 | PKIX_CertChainChecker *nameConstraintsChecker = NULL; |
michael@0 | 280 | PKIX_CertChainChecker *basicConstraintsChecker = NULL; |
michael@0 | 281 | PKIX_CertChainChecker *policyChecker = NULL; |
michael@0 | 282 | PKIX_CertChainChecker *sigChecker = NULL; |
michael@0 | 283 | PKIX_CertChainChecker *defaultCrlChecker = NULL; |
michael@0 | 284 | PKIX_CertChainChecker *userChecker = NULL; |
michael@0 | 285 | PKIX_PL_X500Name *trustedCAName = NULL; |
michael@0 | 286 | PKIX_PL_PublicKey *trustedPubKey = NULL; |
michael@0 | 287 | PKIX_List *checkers = NULL; |
michael@0 | 288 | PKIX_PL_Date *testDate = NULL; |
michael@0 | 289 | PKIX_CertSelector *certSelector = NULL; |
michael@0 | 290 | PKIX_PL_Cert *trustedCert = NULL; |
michael@0 | 291 | PKIX_PL_CertNameConstraints *trustedNC = NULL; |
michael@0 | 292 | PKIX_List *initialPolicies = NULL; |
michael@0 | 293 | PKIX_Boolean policyQualifiersRejected = PKIX_FALSE; |
michael@0 | 294 | PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE; |
michael@0 | 295 | PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE; |
michael@0 | 296 | PKIX_Boolean initialExplicitPolicy = PKIX_FALSE; |
michael@0 | 297 | PKIX_List *userCheckersList = NULL; |
michael@0 | 298 | PKIX_List *certStores = NULL; |
michael@0 | 299 | PKIX_UInt32 numCertCheckers = 0; |
michael@0 | 300 | PKIX_UInt32 i; |
michael@0 | 301 | |
michael@0 | 302 | PKIX_ENTER(VALIDATE, "pkix_InitializeCheckers"); |
michael@0 | 303 | PKIX_NULLCHECK_THREE(anchor, procParams, pCheckers); |
michael@0 | 304 | PKIX_CHECK(PKIX_List_Create(&checkers, plContext), |
michael@0 | 305 | PKIX_LISTCREATEFAILED); |
michael@0 | 306 | |
michael@0 | 307 | /* |
michael@0 | 308 | * The TrustAnchor may have been created using CreateWithCert |
michael@0 | 309 | * (in which case GetCAPublicKey and GetCAName will return NULL) |
michael@0 | 310 | * or may have been created using CreateWithNameKeyPair (in which |
michael@0 | 311 | * case GetTrustedCert will return NULL. So we call GetTrustedCert |
michael@0 | 312 | * and populate trustedPubKey and trustedCAName accordingly. |
michael@0 | 313 | */ |
michael@0 | 314 | |
michael@0 | 315 | PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert |
michael@0 | 316 | (anchor, &trustedCert, plContext), |
michael@0 | 317 | PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); |
michael@0 | 318 | |
michael@0 | 319 | if (trustedCert){ |
michael@0 | 320 | PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey |
michael@0 | 321 | (trustedCert, &trustedPubKey, plContext), |
michael@0 | 322 | PKIX_CERTGETSUBJECTPUBLICKEYFAILED); |
michael@0 | 323 | |
michael@0 | 324 | PKIX_CHECK(PKIX_PL_Cert_GetSubject |
michael@0 | 325 | (trustedCert, &trustedCAName, plContext), |
michael@0 | 326 | PKIX_CERTGETSUBJECTFAILED); |
michael@0 | 327 | } else { |
michael@0 | 328 | PKIX_CHECK(PKIX_TrustAnchor_GetCAPublicKey |
michael@0 | 329 | (anchor, &trustedPubKey, plContext), |
michael@0 | 330 | PKIX_TRUSTANCHORGETCAPUBLICKEYFAILED); |
michael@0 | 331 | |
michael@0 | 332 | PKIX_CHECK(PKIX_TrustAnchor_GetCAName |
michael@0 | 333 | (anchor, &trustedCAName, plContext), |
michael@0 | 334 | PKIX_TRUSTANCHORGETCANAMEFAILED); |
michael@0 | 335 | } |
michael@0 | 336 | |
michael@0 | 337 | PKIX_NULLCHECK_TWO(trustedPubKey, trustedCAName); |
michael@0 | 338 | |
michael@0 | 339 | PKIX_CHECK(PKIX_TrustAnchor_GetNameConstraints |
michael@0 | 340 | (anchor, &trustedNC, plContext), |
michael@0 | 341 | PKIX_TRUSTANCHORGETNAMECONSTRAINTSFAILED); |
michael@0 | 342 | |
michael@0 | 343 | PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints |
michael@0 | 344 | (procParams, &certSelector, plContext), |
michael@0 | 345 | PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); |
michael@0 | 346 | |
michael@0 | 347 | PKIX_CHECK(PKIX_ProcessingParams_GetDate |
michael@0 | 348 | (procParams, &testDate, plContext), |
michael@0 | 349 | PKIX_PROCESSINGPARAMSGETDATEFAILED); |
michael@0 | 350 | |
michael@0 | 351 | PKIX_CHECK(PKIX_ProcessingParams_GetInitialPolicies |
michael@0 | 352 | (procParams, &initialPolicies, plContext), |
michael@0 | 353 | PKIX_PROCESSINGPARAMSGETINITIALPOLICIESFAILED); |
michael@0 | 354 | |
michael@0 | 355 | PKIX_CHECK(PKIX_ProcessingParams_GetPolicyQualifiersRejected |
michael@0 | 356 | (procParams, &policyQualifiersRejected, plContext), |
michael@0 | 357 | PKIX_PROCESSINGPARAMSGETPOLICYQUALIFIERSREJECTEDFAILED); |
michael@0 | 358 | |
michael@0 | 359 | PKIX_CHECK(PKIX_ProcessingParams_IsPolicyMappingInhibited |
michael@0 | 360 | (procParams, &initialPolicyMappingInhibit, plContext), |
michael@0 | 361 | PKIX_PROCESSINGPARAMSISPOLICYMAPPINGINHIBITEDFAILED); |
michael@0 | 362 | |
michael@0 | 363 | PKIX_CHECK(PKIX_ProcessingParams_IsAnyPolicyInhibited |
michael@0 | 364 | (procParams, &initialAnyPolicyInhibit, plContext), |
michael@0 | 365 | PKIX_PROCESSINGPARAMSISANYPOLICYINHIBITEDFAILED); |
michael@0 | 366 | |
michael@0 | 367 | PKIX_CHECK(PKIX_ProcessingParams_IsExplicitPolicyRequired |
michael@0 | 368 | (procParams, &initialExplicitPolicy, plContext), |
michael@0 | 369 | PKIX_PROCESSINGPARAMSISEXPLICITPOLICYREQUIREDFAILED); |
michael@0 | 370 | |
michael@0 | 371 | PKIX_CHECK(PKIX_ProcessingParams_GetCertStores |
michael@0 | 372 | (procParams, &certStores, plContext), |
michael@0 | 373 | PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); |
michael@0 | 374 | |
michael@0 | 375 | PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers |
michael@0 | 376 | (procParams, &userCheckersList, plContext), |
michael@0 | 377 | PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); |
michael@0 | 378 | |
michael@0 | 379 | /* now, initialize all the checkers */ |
michael@0 | 380 | PKIX_CHECK(pkix_TargetCertChecker_Initialize |
michael@0 | 381 | (certSelector, numCerts, &targetCertChecker, plContext), |
michael@0 | 382 | PKIX_TARGETCERTCHECKERINITIALIZEFAILED); |
michael@0 | 383 | |
michael@0 | 384 | PKIX_CHECK(pkix_ExpirationChecker_Initialize |
michael@0 | 385 | (testDate, &expirationChecker, plContext), |
michael@0 | 386 | PKIX_EXPIRATIONCHECKERINITIALIZEFAILED); |
michael@0 | 387 | |
michael@0 | 388 | PKIX_CHECK(pkix_NameChainingChecker_Initialize |
michael@0 | 389 | (trustedCAName, &nameChainingChecker, plContext), |
michael@0 | 390 | PKIX_NAMECHAININGCHECKERINITIALIZEFAILED); |
michael@0 | 391 | |
michael@0 | 392 | PKIX_CHECK(pkix_NameConstraintsChecker_Initialize |
michael@0 | 393 | (trustedNC, numCerts, &nameConstraintsChecker, plContext), |
michael@0 | 394 | PKIX_NAMECONSTRAINTSCHECKERINITIALIZEFAILED); |
michael@0 | 395 | |
michael@0 | 396 | PKIX_CHECK(pkix_BasicConstraintsChecker_Initialize |
michael@0 | 397 | (numCerts, &basicConstraintsChecker, plContext), |
michael@0 | 398 | PKIX_BASICCONSTRAINTSCHECKERINITIALIZEFAILED); |
michael@0 | 399 | |
michael@0 | 400 | PKIX_CHECK(pkix_PolicyChecker_Initialize |
michael@0 | 401 | (initialPolicies, |
michael@0 | 402 | policyQualifiersRejected, |
michael@0 | 403 | initialPolicyMappingInhibit, |
michael@0 | 404 | initialExplicitPolicy, |
michael@0 | 405 | initialAnyPolicyInhibit, |
michael@0 | 406 | numCerts, |
michael@0 | 407 | &policyChecker, |
michael@0 | 408 | plContext), |
michael@0 | 409 | PKIX_POLICYCHECKERINITIALIZEFAILED); |
michael@0 | 410 | |
michael@0 | 411 | PKIX_CHECK(pkix_SignatureChecker_Initialize |
michael@0 | 412 | (trustedPubKey, numCerts, &sigChecker, plContext), |
michael@0 | 413 | PKIX_SIGNATURECHECKERINITIALIZEFAILED); |
michael@0 | 414 | |
michael@0 | 415 | if (userCheckersList != NULL) { |
michael@0 | 416 | |
michael@0 | 417 | PKIX_CHECK(PKIX_List_GetLength |
michael@0 | 418 | (userCheckersList, &numCertCheckers, plContext), |
michael@0 | 419 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 420 | |
michael@0 | 421 | for (i = 0; i < numCertCheckers; i++) { |
michael@0 | 422 | |
michael@0 | 423 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 424 | (userCheckersList, |
michael@0 | 425 | i, |
michael@0 | 426 | (PKIX_PL_Object **) &userChecker, |
michael@0 | 427 | plContext), |
michael@0 | 428 | PKIX_LISTGETITEMFAILED); |
michael@0 | 429 | |
michael@0 | 430 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 431 | (checkers, |
michael@0 | 432 | (PKIX_PL_Object *)userChecker, |
michael@0 | 433 | plContext), |
michael@0 | 434 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 435 | |
michael@0 | 436 | PKIX_DECREF(userChecker); |
michael@0 | 437 | } |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 441 | (checkers, (PKIX_PL_Object *)targetCertChecker, plContext), |
michael@0 | 442 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 443 | |
michael@0 | 444 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 445 | (checkers, (PKIX_PL_Object *)expirationChecker, plContext), |
michael@0 | 446 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 447 | |
michael@0 | 448 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 449 | (checkers, (PKIX_PL_Object *)nameChainingChecker, plContext), |
michael@0 | 450 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 451 | |
michael@0 | 452 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 453 | (checkers, (PKIX_PL_Object *)nameConstraintsChecker, plContext), |
michael@0 | 454 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 455 | |
michael@0 | 456 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 457 | (checkers, (PKIX_PL_Object *)basicConstraintsChecker, plContext), |
michael@0 | 458 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 459 | |
michael@0 | 460 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 461 | (checkers, (PKIX_PL_Object *)policyChecker, plContext), |
michael@0 | 462 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 463 | |
michael@0 | 464 | PKIX_CHECK(PKIX_List_AppendItem |
michael@0 | 465 | (checkers, (PKIX_PL_Object *)sigChecker, plContext), |
michael@0 | 466 | PKIX_LISTAPPENDITEMFAILED); |
michael@0 | 467 | |
michael@0 | 468 | *pCheckers = checkers; |
michael@0 | 469 | |
michael@0 | 470 | cleanup: |
michael@0 | 471 | |
michael@0 | 472 | if (PKIX_ERROR_RECEIVED){ |
michael@0 | 473 | PKIX_DECREF(checkers); |
michael@0 | 474 | } |
michael@0 | 475 | |
michael@0 | 476 | PKIX_DECREF(certSelector); |
michael@0 | 477 | PKIX_DECREF(testDate); |
michael@0 | 478 | PKIX_DECREF(initialPolicies); |
michael@0 | 479 | PKIX_DECREF(targetCertChecker); |
michael@0 | 480 | PKIX_DECREF(expirationChecker); |
michael@0 | 481 | PKIX_DECREF(nameChainingChecker); |
michael@0 | 482 | PKIX_DECREF(nameConstraintsChecker); |
michael@0 | 483 | PKIX_DECREF(basicConstraintsChecker); |
michael@0 | 484 | PKIX_DECREF(policyChecker); |
michael@0 | 485 | PKIX_DECREF(sigChecker); |
michael@0 | 486 | PKIX_DECREF(trustedCAName); |
michael@0 | 487 | PKIX_DECREF(trustedPubKey); |
michael@0 | 488 | PKIX_DECREF(trustedNC); |
michael@0 | 489 | PKIX_DECREF(trustedCert); |
michael@0 | 490 | PKIX_DECREF(defaultCrlChecker); |
michael@0 | 491 | PKIX_DECREF(userCheckersList); |
michael@0 | 492 | PKIX_DECREF(certStores); |
michael@0 | 493 | PKIX_DECREF(userChecker); |
michael@0 | 494 | |
michael@0 | 495 | PKIX_RETURN(VALIDATE); |
michael@0 | 496 | } |
michael@0 | 497 | |
michael@0 | 498 | /* |
michael@0 | 499 | * FUNCTION: pkix_RetrieveOutputs |
michael@0 | 500 | * DESCRIPTION: |
michael@0 | 501 | * |
michael@0 | 502 | * This function queries the respective states of the List of checkers in |
michael@0 | 503 | * "checkers" to to obtain the final public key from the SignatureChecker |
michael@0 | 504 | * and the policy tree from the PolicyChecker, storing those values at |
michael@0 | 505 | * "pFinalSubjPubKey" and "pPolicyTree", respectively. |
michael@0 | 506 | * |
michael@0 | 507 | * PARAMETERS: |
michael@0 | 508 | * "checkers" |
michael@0 | 509 | * Address of List of checkers to be queried. Must be non-NULL. |
michael@0 | 510 | * "pFinalSubjPubKey" |
michael@0 | 511 | * Address where final public key will be stored. Must be non-NULL. |
michael@0 | 512 | * "pPolicyTree" |
michael@0 | 513 | * Address where policy tree will be stored. Must be non-NULL. |
michael@0 | 514 | * "plContext" |
michael@0 | 515 | * Platform-specific context pointer. |
michael@0 | 516 | * THREAD SAFETY: |
michael@0 | 517 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 518 | * RETURNS: |
michael@0 | 519 | * Returns NULL if the function succeeds. |
michael@0 | 520 | * Returns a Validate Error if the function fails in a non-fatal way. |
michael@0 | 521 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 522 | */ |
michael@0 | 523 | static PKIX_Error * |
michael@0 | 524 | pkix_RetrieveOutputs( |
michael@0 | 525 | PKIX_List *checkers, |
michael@0 | 526 | PKIX_PL_PublicKey **pFinalSubjPubKey, |
michael@0 | 527 | PKIX_PolicyNode **pPolicyTree, |
michael@0 | 528 | void *plContext) |
michael@0 | 529 | { |
michael@0 | 530 | PKIX_PL_PublicKey *finalSubjPubKey = NULL; |
michael@0 | 531 | PKIX_PolicyNode *validPolicyTree = NULL; |
michael@0 | 532 | PKIX_CertChainChecker *checker = NULL; |
michael@0 | 533 | PKIX_PL_Object *state = NULL; |
michael@0 | 534 | PKIX_UInt32 numCheckers = 0; |
michael@0 | 535 | PKIX_UInt32 type; |
michael@0 | 536 | PKIX_Int32 j; |
michael@0 | 537 | |
michael@0 | 538 | PKIX_ENTER(VALIDATE, "pkix_RetrieveOutputs"); |
michael@0 | 539 | |
michael@0 | 540 | PKIX_NULLCHECK_TWO(checkers, pPolicyTree); |
michael@0 | 541 | |
michael@0 | 542 | /* |
michael@0 | 543 | * To optimize the search, we guess that the sigChecker is |
michael@0 | 544 | * last in the tree and is preceded by the policyChecker. We |
michael@0 | 545 | * search toward the front of the chain. Remember that List |
michael@0 | 546 | * items are indexed 0..(numItems - 1). |
michael@0 | 547 | */ |
michael@0 | 548 | |
michael@0 | 549 | PKIX_CHECK(PKIX_List_GetLength(checkers, &numCheckers, plContext), |
michael@0 | 550 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 551 | |
michael@0 | 552 | for (j = numCheckers - 1; j >= 0; j--){ |
michael@0 | 553 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 554 | (checkers, j, (PKIX_PL_Object **)&checker, plContext), |
michael@0 | 555 | PKIX_LISTGETITEMFAILED); |
michael@0 | 556 | |
michael@0 | 557 | PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState |
michael@0 | 558 | (checker, &state, plContext), |
michael@0 | 559 | PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); |
michael@0 | 560 | |
michael@0 | 561 | /* user defined checker may have no state */ |
michael@0 | 562 | if (state != NULL) { |
michael@0 | 563 | |
michael@0 | 564 | PKIX_CHECK(PKIX_PL_Object_GetType(state, &type, plContext), |
michael@0 | 565 | PKIX_OBJECTGETTYPEFAILED); |
michael@0 | 566 | |
michael@0 | 567 | if (type == PKIX_SIGNATURECHECKERSTATE_TYPE){ |
michael@0 | 568 | /* final pubKey will include any inherited DSA params */ |
michael@0 | 569 | finalSubjPubKey = |
michael@0 | 570 | ((pkix_SignatureCheckerState *)state)-> |
michael@0 | 571 | prevPublicKey; |
michael@0 | 572 | PKIX_INCREF(finalSubjPubKey); |
michael@0 | 573 | *pFinalSubjPubKey = finalSubjPubKey; |
michael@0 | 574 | } |
michael@0 | 575 | |
michael@0 | 576 | if (type == PKIX_CERTPOLICYCHECKERSTATE_TYPE) { |
michael@0 | 577 | validPolicyTree = |
michael@0 | 578 | ((PKIX_PolicyCheckerState *)state)->validPolicyTree; |
michael@0 | 579 | break; |
michael@0 | 580 | } |
michael@0 | 581 | } |
michael@0 | 582 | |
michael@0 | 583 | PKIX_DECREF(checker); |
michael@0 | 584 | PKIX_DECREF(state); |
michael@0 | 585 | } |
michael@0 | 586 | |
michael@0 | 587 | PKIX_INCREF(validPolicyTree); |
michael@0 | 588 | *pPolicyTree = validPolicyTree; |
michael@0 | 589 | |
michael@0 | 590 | cleanup: |
michael@0 | 591 | |
michael@0 | 592 | PKIX_DECREF(checker); |
michael@0 | 593 | PKIX_DECREF(state); |
michael@0 | 594 | |
michael@0 | 595 | PKIX_RETURN(VALIDATE); |
michael@0 | 596 | |
michael@0 | 597 | } |
michael@0 | 598 | |
michael@0 | 599 | /* |
michael@0 | 600 | * FUNCTION: pkix_CheckChain |
michael@0 | 601 | * DESCRIPTION: |
michael@0 | 602 | * |
michael@0 | 603 | * Checks whether the List of Certs pointed to by "certs", containing |
michael@0 | 604 | * "numCerts" entries, successfully validates using each CertChainChecker in |
michael@0 | 605 | * the List pointed to by "checkers" and has not been revoked, according to any |
michael@0 | 606 | * of the Revocation Checkers in the List pointed to by "revChecker". Checkers |
michael@0 | 607 | * are expected to remove from "removeCheckedExtOIDs" and extensions that they |
michael@0 | 608 | * process. Indices to the certChain and the checkerChain are obtained and |
michael@0 | 609 | * returned in "pCertCheckedIndex" and "pCheckerIndex", respectively. These |
michael@0 | 610 | * should be set to zero prior to the initial call, but may be changed (and |
michael@0 | 611 | * must be supplied on subsequent calls) if processing is suspended for non- |
michael@0 | 612 | * blocking I/O. Each time a Cert passes from being validated by one of the |
michael@0 | 613 | * CertChainCheckers to being checked by a Revocation Checker, the Boolean |
michael@0 | 614 | * stored at "pRevChecking" is changed from FALSE to TRUE. If the Cert is |
michael@0 | 615 | * rejected by a Revocation Checker, its reason code is returned at |
michael@0 | 616 | * "pReasonCode. If the List of Certs successfully validates, the public key i |
michael@0 | 617 | * the final certificate is obtained and stored at "pFinalSubjPubKey" and the |
michael@0 | 618 | * validPolicyTree, which could be NULL, is stored at pPolicyTree. If the List |
michael@0 | 619 | * of Certs fails to validate, an Error pointer is returned. |
michael@0 | 620 | * |
michael@0 | 621 | * If "pVerifyTree" is non-NULL, a chain of VerifyNodes is created which |
michael@0 | 622 | * tracks the results of the validation. That is, either each node in the |
michael@0 | 623 | * chain has a NULL Error component, or the last node contains an Error |
michael@0 | 624 | * which indicates why the validation failed. |
michael@0 | 625 | * |
michael@0 | 626 | * The number of Certs in the List, represented by "numCerts", is used to |
michael@0 | 627 | * determine which Cert is the final Cert. |
michael@0 | 628 | * |
michael@0 | 629 | * PARAMETERS: |
michael@0 | 630 | * "certs" |
michael@0 | 631 | * Address of List of Certs to validate. Must be non-NULL. |
michael@0 | 632 | * "numCerts" |
michael@0 | 633 | * Number of certificates in the List of certificates. |
michael@0 | 634 | * "checkers" |
michael@0 | 635 | * List of CertChainCheckers which must each validate the List of |
michael@0 | 636 | * certificates. Must be non-NULL. |
michael@0 | 637 | * "revChecker" |
michael@0 | 638 | * List of RevocationCheckers which must each not reject the List of |
michael@0 | 639 | * certificates. May be empty, but must be non-NULL. |
michael@0 | 640 | * "removeCheckedExtOIDs" |
michael@0 | 641 | * List of PKIX_PL_OID that has been processed. If called from building |
michael@0 | 642 | * chain, it is the list of critical extension OIDs that has been |
michael@0 | 643 | * processed prior to validation. Extension OIDs that may be processed by |
michael@0 | 644 | * user defined checker processes are also in the list. May be NULL. |
michael@0 | 645 | * "procParams" |
michael@0 | 646 | * Address of ProcessingParams used to initialize various checkers. Must |
michael@0 | 647 | * be non-NULL. |
michael@0 | 648 | * "pCertCheckedIndex" |
michael@0 | 649 | * Address where Int32 index to the Cert chain is obtained and |
michael@0 | 650 | * returned. Must be non-NULL. |
michael@0 | 651 | * "pCheckerIndex" |
michael@0 | 652 | * Address where Int32 index to the CheckerChain is obtained and |
michael@0 | 653 | * returned. Must be non-NULL. |
michael@0 | 654 | * "pRevChecking" |
michael@0 | 655 | * Address where Boolean is obtained and returned, indicating, if FALSE, |
michael@0 | 656 | * that CertChainCheckers are being called; or, if TRUE, that RevChecker |
michael@0 | 657 | * are being called. Must be non-NULL. |
michael@0 | 658 | * "pReasonCode" |
michael@0 | 659 | * Address where UInt32 results of revocation checking are stored. Must be |
michael@0 | 660 | * non-NULL. |
michael@0 | 661 | * "pNBIOContext" |
michael@0 | 662 | * Address where platform-dependent context is stored if checking is |
michael@0 | 663 | * suspended for non-blocking I/O. Must be non-NULL. |
michael@0 | 664 | * "pFinalSubjPubKey" |
michael@0 | 665 | * Address where the final public key will be stored. Must be non-NULL. |
michael@0 | 666 | * "pPolicyTree" |
michael@0 | 667 | * Address where the final validPolicyTree is stored. Must be non-NULL. |
michael@0 | 668 | * "pVerifyTree" |
michael@0 | 669 | * Address where a VerifyTree is stored, if non-NULL. |
michael@0 | 670 | * "plContext" |
michael@0 | 671 | * Platform-specific context pointer. |
michael@0 | 672 | * THREAD SAFETY: |
michael@0 | 673 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 674 | * RETURNS: |
michael@0 | 675 | * Returns NULL if the function succeeds. |
michael@0 | 676 | * Returns a Validate Error if the function fails in a non-fatal way. |
michael@0 | 677 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 678 | */ |
michael@0 | 679 | PKIX_Error * |
michael@0 | 680 | pkix_CheckChain( |
michael@0 | 681 | PKIX_List *certs, |
michael@0 | 682 | PKIX_UInt32 numCerts, |
michael@0 | 683 | PKIX_TrustAnchor *anchor, |
michael@0 | 684 | PKIX_List *checkers, |
michael@0 | 685 | PKIX_RevocationChecker *revChecker, |
michael@0 | 686 | PKIX_List *removeCheckedExtOIDs, |
michael@0 | 687 | PKIX_ProcessingParams *procParams, |
michael@0 | 688 | PKIX_UInt32 *pCertCheckedIndex, |
michael@0 | 689 | PKIX_UInt32 *pCheckerIndex, |
michael@0 | 690 | PKIX_Boolean *pRevChecking, |
michael@0 | 691 | PKIX_UInt32 *pReasonCode, |
michael@0 | 692 | void **pNBIOContext, |
michael@0 | 693 | PKIX_PL_PublicKey **pFinalSubjPubKey, |
michael@0 | 694 | PKIX_PolicyNode **pPolicyTree, |
michael@0 | 695 | PKIX_VerifyNode **pVerifyTree, |
michael@0 | 696 | void *plContext) |
michael@0 | 697 | { |
michael@0 | 698 | PKIX_UInt32 j = 0; |
michael@0 | 699 | PKIX_Boolean revChecking = PKIX_FALSE; |
michael@0 | 700 | PKIX_Error *checkCertError = NULL; |
michael@0 | 701 | void *nbioContext = NULL; |
michael@0 | 702 | PKIX_PL_Cert *cert = NULL; |
michael@0 | 703 | PKIX_PL_Cert *issuer = NULL; |
michael@0 | 704 | PKIX_PL_NssContext *nssContext = NULL; |
michael@0 | 705 | CERTCertList *certList = NULL; |
michael@0 | 706 | const CERTChainVerifyCallback *chainVerifyCallback = NULL; |
michael@0 | 707 | CERTCertificate *nssCert = NULL; |
michael@0 | 708 | |
michael@0 | 709 | PKIX_ENTER(VALIDATE, "pkix_CheckChain"); |
michael@0 | 710 | PKIX_NULLCHECK_FOUR(certs, checkers, revChecker, pCertCheckedIndex); |
michael@0 | 711 | PKIX_NULLCHECK_FOUR(pCheckerIndex, pRevChecking, pReasonCode, anchor); |
michael@0 | 712 | PKIX_NULLCHECK_THREE(pNBIOContext, pFinalSubjPubKey, pPolicyTree); |
michael@0 | 713 | |
michael@0 | 714 | nbioContext = *pNBIOContext; |
michael@0 | 715 | *pNBIOContext = NULL; |
michael@0 | 716 | revChecking = *pRevChecking; |
michael@0 | 717 | nssContext = (PKIX_PL_NssContext *)plContext; |
michael@0 | 718 | chainVerifyCallback = &nssContext->chainVerifyCallback; |
michael@0 | 719 | |
michael@0 | 720 | if (chainVerifyCallback->isChainValid != NULL) { |
michael@0 | 721 | PRBool chainOK = PR_FALSE; /*assume failure*/ |
michael@0 | 722 | SECStatus rv; |
michael@0 | 723 | |
michael@0 | 724 | certList = CERT_NewCertList(); |
michael@0 | 725 | if (certList == NULL) { |
michael@0 | 726 | PKIX_ERROR_ALLOC_ERROR(); |
michael@0 | 727 | } |
michael@0 | 728 | |
michael@0 | 729 | /* Add the trust anchor to the list */ |
michael@0 | 730 | PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert |
michael@0 | 731 | (anchor, &cert, plContext), |
michael@0 | 732 | PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); |
michael@0 | 733 | |
michael@0 | 734 | PKIX_CHECK( |
michael@0 | 735 | PKIX_PL_Cert_GetCERTCertificate(cert, &nssCert, plContext), |
michael@0 | 736 | PKIX_CERTGETCERTCERTIFICATEFAILED); |
michael@0 | 737 | |
michael@0 | 738 | rv = CERT_AddCertToListHead(certList, nssCert); |
michael@0 | 739 | if (rv != SECSuccess) { |
michael@0 | 740 | PKIX_ERROR_ALLOC_ERROR(); |
michael@0 | 741 | } |
michael@0 | 742 | /* the certList takes ownership of nssCert on success */ |
michael@0 | 743 | nssCert = NULL; |
michael@0 | 744 | PKIX_DECREF(cert); |
michael@0 | 745 | |
michael@0 | 746 | /* Add the rest of the chain to the list */ |
michael@0 | 747 | for (j = *pCertCheckedIndex; j < numCerts; j++) { |
michael@0 | 748 | PKIX_CHECK(PKIX_List_GetItem( |
michael@0 | 749 | certs, j, (PKIX_PL_Object **)&cert, plContext), |
michael@0 | 750 | PKIX_LISTGETITEMFAILED); |
michael@0 | 751 | |
michael@0 | 752 | PKIX_CHECK( |
michael@0 | 753 | PKIX_PL_Cert_GetCERTCertificate(cert, &nssCert, plContext), |
michael@0 | 754 | PKIX_CERTGETCERTCERTIFICATEFAILED); |
michael@0 | 755 | |
michael@0 | 756 | rv = CERT_AddCertToListHead(certList, nssCert); |
michael@0 | 757 | if (rv != SECSuccess) { |
michael@0 | 758 | PKIX_ERROR_ALLOC_ERROR(); |
michael@0 | 759 | } |
michael@0 | 760 | /* the certList takes ownership of nssCert on success */ |
michael@0 | 761 | nssCert = NULL; |
michael@0 | 762 | PKIX_DECREF(cert); |
michael@0 | 763 | } |
michael@0 | 764 | |
michael@0 | 765 | rv = (*chainVerifyCallback->isChainValid) |
michael@0 | 766 | (chainVerifyCallback->isChainValidArg, certList, &chainOK); |
michael@0 | 767 | if (rv != SECSuccess) { |
michael@0 | 768 | PKIX_ERROR_FATAL(PKIX_CHAINVERIFYCALLBACKFAILED); |
michael@0 | 769 | } |
michael@0 | 770 | |
michael@0 | 771 | if (!chainOK) { |
michael@0 | 772 | PKIX_ERROR(PKIX_CHAINVERIFYCALLBACKFAILED); |
michael@0 | 773 | } |
michael@0 | 774 | |
michael@0 | 775 | } |
michael@0 | 776 | |
michael@0 | 777 | PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert |
michael@0 | 778 | (anchor, &cert, plContext), |
michael@0 | 779 | PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); |
michael@0 | 780 | |
michael@0 | 781 | for (j = *pCertCheckedIndex; j < numCerts; j++) { |
michael@0 | 782 | |
michael@0 | 783 | PORT_Assert(cert); |
michael@0 | 784 | PKIX_DECREF(issuer); |
michael@0 | 785 | issuer = cert; |
michael@0 | 786 | cert = NULL; |
michael@0 | 787 | |
michael@0 | 788 | PKIX_CHECK(PKIX_List_GetItem( |
michael@0 | 789 | certs, j, (PKIX_PL_Object **)&cert, plContext), |
michael@0 | 790 | PKIX_LISTGETITEMFAILED); |
michael@0 | 791 | |
michael@0 | 792 | /* check if cert pointer is valid */ |
michael@0 | 793 | PORT_Assert(cert); |
michael@0 | 794 | if (cert == NULL) { |
michael@0 | 795 | continue; |
michael@0 | 796 | } |
michael@0 | 797 | |
michael@0 | 798 | if (revChecking == PKIX_FALSE) { |
michael@0 | 799 | |
michael@0 | 800 | PKIX_CHECK(pkix_CheckCert |
michael@0 | 801 | (cert, |
michael@0 | 802 | checkers, |
michael@0 | 803 | removeCheckedExtOIDs, |
michael@0 | 804 | pCheckerIndex, |
michael@0 | 805 | &nbioContext, |
michael@0 | 806 | plContext), |
michael@0 | 807 | PKIX_CHECKCERTFAILED); |
michael@0 | 808 | |
michael@0 | 809 | if (nbioContext != NULL) { |
michael@0 | 810 | *pCertCheckedIndex = j; |
michael@0 | 811 | *pRevChecking = revChecking; |
michael@0 | 812 | *pNBIOContext = nbioContext; |
michael@0 | 813 | goto cleanup; |
michael@0 | 814 | } |
michael@0 | 815 | |
michael@0 | 816 | revChecking = PKIX_TRUE; |
michael@0 | 817 | *pCheckerIndex = 0; |
michael@0 | 818 | } |
michael@0 | 819 | |
michael@0 | 820 | if (revChecking == PKIX_TRUE) { |
michael@0 | 821 | PKIX_RevocationStatus revStatus; |
michael@0 | 822 | pkixErrorResult = |
michael@0 | 823 | PKIX_RevocationChecker_Check( |
michael@0 | 824 | cert, issuer, revChecker, |
michael@0 | 825 | procParams, PKIX_TRUE, |
michael@0 | 826 | (j == numCerts - 1) ? PKIX_TRUE : PKIX_FALSE, |
michael@0 | 827 | &revStatus, pReasonCode, |
michael@0 | 828 | &nbioContext, plContext); |
michael@0 | 829 | if (nbioContext != NULL) { |
michael@0 | 830 | *pCertCheckedIndex = j; |
michael@0 | 831 | *pRevChecking = revChecking; |
michael@0 | 832 | *pNBIOContext = nbioContext; |
michael@0 | 833 | goto cleanup; |
michael@0 | 834 | } |
michael@0 | 835 | if (revStatus == PKIX_RevStatus_Revoked || |
michael@0 | 836 | pkixErrorResult) { |
michael@0 | 837 | if (!pkixErrorResult) { |
michael@0 | 838 | /* if pkixErrorResult is returned then |
michael@0 | 839 | * use it as it has a detailed revocation |
michael@0 | 840 | * error code. Otherwise create a new error */ |
michael@0 | 841 | PKIX_ERROR_CREATE(VALIDATE, |
michael@0 | 842 | PKIX_CERTIFICATEREVOKED, |
michael@0 | 843 | pkixErrorResult); |
michael@0 | 844 | } |
michael@0 | 845 | goto cleanup; |
michael@0 | 846 | } |
michael@0 | 847 | revChecking = PKIX_FALSE; |
michael@0 | 848 | *pCheckerIndex = 0; |
michael@0 | 849 | } |
michael@0 | 850 | |
michael@0 | 851 | PKIX_CHECK(pkix_AddToVerifyLog |
michael@0 | 852 | (cert, j, NULL, pVerifyTree, plContext), |
michael@0 | 853 | PKIX_ADDTOVERIFYLOGFAILED); |
michael@0 | 854 | } |
michael@0 | 855 | |
michael@0 | 856 | PKIX_CHECK(pkix_RetrieveOutputs |
michael@0 | 857 | (checkers, pFinalSubjPubKey, pPolicyTree, plContext), |
michael@0 | 858 | PKIX_RETRIEVEOUTPUTSFAILED); |
michael@0 | 859 | |
michael@0 | 860 | *pNBIOContext = NULL; |
michael@0 | 861 | |
michael@0 | 862 | cleanup: |
michael@0 | 863 | if (PKIX_ERROR_RECEIVED && cert) { |
michael@0 | 864 | checkCertError = pkixErrorResult; |
michael@0 | 865 | |
michael@0 | 866 | PKIX_CHECK_FATAL( |
michael@0 | 867 | pkix_AddToVerifyLog(cert, j, checkCertError, pVerifyTree, |
michael@0 | 868 | plContext), |
michael@0 | 869 | PKIX_ADDTOVERIFYLOGFAILED); |
michael@0 | 870 | pkixErrorResult = checkCertError; |
michael@0 | 871 | pkixErrorCode = pkixErrorResult->errCode; |
michael@0 | 872 | checkCertError = NULL; |
michael@0 | 873 | } |
michael@0 | 874 | |
michael@0 | 875 | fatal: |
michael@0 | 876 | if (nssCert) { |
michael@0 | 877 | CERT_DestroyCertificate(nssCert); |
michael@0 | 878 | } |
michael@0 | 879 | |
michael@0 | 880 | if (certList) { |
michael@0 | 881 | CERT_DestroyCertList(certList); |
michael@0 | 882 | } |
michael@0 | 883 | |
michael@0 | 884 | PKIX_DECREF(checkCertError); |
michael@0 | 885 | PKIX_DECREF(cert); |
michael@0 | 886 | PKIX_DECREF(issuer); |
michael@0 | 887 | |
michael@0 | 888 | PKIX_RETURN(VALIDATE); |
michael@0 | 889 | } |
michael@0 | 890 | |
michael@0 | 891 | /* |
michael@0 | 892 | * FUNCTION: pkix_ExtractParameters |
michael@0 | 893 | * DESCRIPTION: |
michael@0 | 894 | * |
michael@0 | 895 | * Extracts several parameters from the ValidateParams object pointed to by |
michael@0 | 896 | * "valParams" and stores the CertChain at "pChain", the List of Certs at |
michael@0 | 897 | * "pCerts", the number of Certs in the chain at "pNumCerts", the |
michael@0 | 898 | * ProcessingParams object at "pProcParams", the List of TrustAnchors at |
michael@0 | 899 | * "pAnchors", and the number of TrustAnchors at "pNumAnchors". |
michael@0 | 900 | * |
michael@0 | 901 | * PARAMETERS: |
michael@0 | 902 | * "valParams" |
michael@0 | 903 | * Address of ValidateParams from which the parameters are extracted. |
michael@0 | 904 | * Must be non-NULL. |
michael@0 | 905 | * "pCerts" |
michael@0 | 906 | * Address where object pointer for List of Certs will be stored. |
michael@0 | 907 | * Must be non-NULL. |
michael@0 | 908 | * "pNumCerts" |
michael@0 | 909 | * Address where number of Certs will be stored. Must be non-NULL. |
michael@0 | 910 | * "pProcParams" |
michael@0 | 911 | * Address where object pointer for ProcessingParams will be stored. |
michael@0 | 912 | * Must be non-NULL. |
michael@0 | 913 | * "pAnchors" |
michael@0 | 914 | * Address where object pointer for List of Anchors will be stored. |
michael@0 | 915 | * Must be non-NULL. |
michael@0 | 916 | * "pNumAnchors" |
michael@0 | 917 | * Address where number of Anchors will be stored. Must be non-NULL. |
michael@0 | 918 | * "plContext" |
michael@0 | 919 | * Platform-specific context pointer. |
michael@0 | 920 | * THREAD SAFETY: |
michael@0 | 921 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 922 | * RETURNS: |
michael@0 | 923 | * Returns NULL if the function succeeds. |
michael@0 | 924 | * Returns a Validate Error if the function fails in a non-fatal way. |
michael@0 | 925 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 926 | */ |
michael@0 | 927 | static PKIX_Error * |
michael@0 | 928 | pkix_ExtractParameters( |
michael@0 | 929 | PKIX_ValidateParams *valParams, |
michael@0 | 930 | PKIX_List **pCerts, |
michael@0 | 931 | PKIX_UInt32 *pNumCerts, |
michael@0 | 932 | PKIX_ProcessingParams **pProcParams, |
michael@0 | 933 | PKIX_List **pAnchors, |
michael@0 | 934 | PKIX_UInt32 *pNumAnchors, |
michael@0 | 935 | void *plContext) |
michael@0 | 936 | { |
michael@0 | 937 | PKIX_ENTER(VALIDATE, "pkix_ExtractParameters"); |
michael@0 | 938 | PKIX_NULLCHECK_THREE(valParams, pCerts, pNumCerts); |
michael@0 | 939 | PKIX_NULLCHECK_THREE(pProcParams, pAnchors, pNumAnchors); |
michael@0 | 940 | |
michael@0 | 941 | /* extract relevant parameters from chain */ |
michael@0 | 942 | PKIX_CHECK(PKIX_ValidateParams_GetCertChain |
michael@0 | 943 | (valParams, pCerts, plContext), |
michael@0 | 944 | PKIX_VALIDATEPARAMSGETCERTCHAINFAILED); |
michael@0 | 945 | |
michael@0 | 946 | PKIX_CHECK(PKIX_List_GetLength(*pCerts, pNumCerts, plContext), |
michael@0 | 947 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 948 | |
michael@0 | 949 | /* extract relevant parameters from procParams */ |
michael@0 | 950 | PKIX_CHECK(PKIX_ValidateParams_GetProcessingParams |
michael@0 | 951 | (valParams, pProcParams, plContext), |
michael@0 | 952 | PKIX_VALIDATEPARAMSGETPROCESSINGPARAMSFAILED); |
michael@0 | 953 | |
michael@0 | 954 | PKIX_CHECK(PKIX_ProcessingParams_GetTrustAnchors |
michael@0 | 955 | (*pProcParams, pAnchors, plContext), |
michael@0 | 956 | PKIX_PROCESSINGPARAMSGETTRUSTANCHORSFAILED); |
michael@0 | 957 | |
michael@0 | 958 | PKIX_CHECK(PKIX_List_GetLength(*pAnchors, pNumAnchors, plContext), |
michael@0 | 959 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 960 | |
michael@0 | 961 | cleanup: |
michael@0 | 962 | |
michael@0 | 963 | PKIX_RETURN(VALIDATE); |
michael@0 | 964 | } |
michael@0 | 965 | |
michael@0 | 966 | /* --Public-Functions--------------------------------------------- */ |
michael@0 | 967 | |
michael@0 | 968 | /* |
michael@0 | 969 | * FUNCTION: PKIX_ValidateChain (see comments in pkix.h) |
michael@0 | 970 | */ |
michael@0 | 971 | PKIX_Error * |
michael@0 | 972 | PKIX_ValidateChain( |
michael@0 | 973 | PKIX_ValidateParams *valParams, |
michael@0 | 974 | PKIX_ValidateResult **pResult, |
michael@0 | 975 | PKIX_VerifyNode **pVerifyTree, |
michael@0 | 976 | void *plContext) |
michael@0 | 977 | { |
michael@0 | 978 | PKIX_Error *chainFailed = NULL; |
michael@0 | 979 | |
michael@0 | 980 | PKIX_ProcessingParams *procParams = NULL; |
michael@0 | 981 | PKIX_CertChainChecker *userChecker = NULL; |
michael@0 | 982 | PKIX_RevocationChecker *revChecker = NULL; |
michael@0 | 983 | PKIX_List *certs = NULL; |
michael@0 | 984 | PKIX_List *checkers = NULL; |
michael@0 | 985 | PKIX_List *anchors = NULL; |
michael@0 | 986 | PKIX_List *userCheckers = NULL; |
michael@0 | 987 | PKIX_List *userCheckerExtOIDs = NULL; |
michael@0 | 988 | PKIX_List *validateCheckedCritExtOIDsList = NULL; |
michael@0 | 989 | PKIX_TrustAnchor *anchor = NULL; |
michael@0 | 990 | PKIX_ValidateResult *valResult = NULL; |
michael@0 | 991 | PKIX_PL_PublicKey *finalPubKey = NULL; |
michael@0 | 992 | PKIX_PolicyNode *validPolicyTree = NULL; |
michael@0 | 993 | PKIX_Boolean supportForwarding = PKIX_FALSE; |
michael@0 | 994 | PKIX_Boolean revChecking = PKIX_FALSE; |
michael@0 | 995 | PKIX_UInt32 i, numCerts, numAnchors; |
michael@0 | 996 | PKIX_UInt32 numUserCheckers = 0; |
michael@0 | 997 | PKIX_UInt32 certCheckedIndex = 0; |
michael@0 | 998 | PKIX_UInt32 checkerIndex = 0; |
michael@0 | 999 | PKIX_UInt32 reasonCode = 0; |
michael@0 | 1000 | void *nbioContext = NULL; |
michael@0 | 1001 | |
michael@0 | 1002 | PKIX_ENTER(VALIDATE, "PKIX_ValidateChain"); |
michael@0 | 1003 | PKIX_NULLCHECK_TWO(valParams, pResult); |
michael@0 | 1004 | |
michael@0 | 1005 | /* extract various parameters from valParams */ |
michael@0 | 1006 | PKIX_CHECK(pkix_ExtractParameters |
michael@0 | 1007 | (valParams, |
michael@0 | 1008 | &certs, |
michael@0 | 1009 | &numCerts, |
michael@0 | 1010 | &procParams, |
michael@0 | 1011 | &anchors, |
michael@0 | 1012 | &numAnchors, |
michael@0 | 1013 | plContext), |
michael@0 | 1014 | PKIX_EXTRACTPARAMETERSFAILED); |
michael@0 | 1015 | |
michael@0 | 1016 | /* |
michael@0 | 1017 | * setup an extension OID list that user had defined for his checker |
michael@0 | 1018 | * processing. User checker is not responsible for taking out OIDs |
michael@0 | 1019 | * from unresolved critical extension list as the libpkix checker |
michael@0 | 1020 | * is doing. Here we add those user checkers' OIDs to the removal |
michael@0 | 1021 | * list to be taken out by CheckChain |
michael@0 | 1022 | */ |
michael@0 | 1023 | PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers |
michael@0 | 1024 | (procParams, &userCheckers, plContext), |
michael@0 | 1025 | PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); |
michael@0 | 1026 | |
michael@0 | 1027 | if (userCheckers != NULL) { |
michael@0 | 1028 | |
michael@0 | 1029 | PKIX_CHECK(PKIX_List_Create |
michael@0 | 1030 | (&validateCheckedCritExtOIDsList, |
michael@0 | 1031 | plContext), |
michael@0 | 1032 | PKIX_LISTCREATEFAILED); |
michael@0 | 1033 | |
michael@0 | 1034 | PKIX_CHECK(PKIX_List_GetLength |
michael@0 | 1035 | (userCheckers, &numUserCheckers, plContext), |
michael@0 | 1036 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 1037 | |
michael@0 | 1038 | for (i = 0; i < numUserCheckers; i++) { |
michael@0 | 1039 | |
michael@0 | 1040 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 1041 | (userCheckers, |
michael@0 | 1042 | i, |
michael@0 | 1043 | (PKIX_PL_Object **) &userChecker, |
michael@0 | 1044 | plContext), |
michael@0 | 1045 | PKIX_LISTGETITEMFAILED); |
michael@0 | 1046 | |
michael@0 | 1047 | PKIX_CHECK |
michael@0 | 1048 | (PKIX_CertChainChecker_IsForwardCheckingSupported |
michael@0 | 1049 | (userChecker, &supportForwarding, plContext), |
michael@0 | 1050 | PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED); |
michael@0 | 1051 | |
michael@0 | 1052 | if (supportForwarding == PKIX_FALSE) { |
michael@0 | 1053 | |
michael@0 | 1054 | PKIX_CHECK |
michael@0 | 1055 | (PKIX_CertChainChecker_GetSupportedExtensions |
michael@0 | 1056 | (userChecker, &userCheckerExtOIDs, plContext), |
michael@0 | 1057 | PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED); |
michael@0 | 1058 | |
michael@0 | 1059 | if (userCheckerExtOIDs != NULL) { |
michael@0 | 1060 | PKIX_CHECK(pkix_List_AppendList |
michael@0 | 1061 | (validateCheckedCritExtOIDsList, |
michael@0 | 1062 | userCheckerExtOIDs, |
michael@0 | 1063 | plContext), |
michael@0 | 1064 | PKIX_LISTAPPENDLISTFAILED); |
michael@0 | 1065 | } |
michael@0 | 1066 | } |
michael@0 | 1067 | |
michael@0 | 1068 | PKIX_DECREF(userCheckerExtOIDs); |
michael@0 | 1069 | PKIX_DECREF(userChecker); |
michael@0 | 1070 | } |
michael@0 | 1071 | } |
michael@0 | 1072 | |
michael@0 | 1073 | PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker |
michael@0 | 1074 | (procParams, &revChecker, plContext), |
michael@0 | 1075 | PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED); |
michael@0 | 1076 | |
michael@0 | 1077 | /* try to validate the chain with each anchor */ |
michael@0 | 1078 | for (i = 0; i < numAnchors; i++){ |
michael@0 | 1079 | |
michael@0 | 1080 | /* get trust anchor */ |
michael@0 | 1081 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 1082 | (anchors, i, (PKIX_PL_Object **)&anchor, plContext), |
michael@0 | 1083 | PKIX_LISTGETITEMFAILED); |
michael@0 | 1084 | |
michael@0 | 1085 | /* initialize checkers using information from trust anchor */ |
michael@0 | 1086 | PKIX_CHECK(pkix_InitializeCheckers |
michael@0 | 1087 | (anchor, procParams, numCerts, &checkers, plContext), |
michael@0 | 1088 | PKIX_INITIALIZECHECKERSFAILED); |
michael@0 | 1089 | |
michael@0 | 1090 | /* |
michael@0 | 1091 | * Validate the chain using this trust anchor and these |
michael@0 | 1092 | * checkers. (WARNING: checkers that use non-blocking I/O |
michael@0 | 1093 | * are not currently supported.) |
michael@0 | 1094 | */ |
michael@0 | 1095 | certCheckedIndex = 0; |
michael@0 | 1096 | checkerIndex = 0; |
michael@0 | 1097 | revChecking = PKIX_FALSE; |
michael@0 | 1098 | chainFailed = pkix_CheckChain |
michael@0 | 1099 | (certs, |
michael@0 | 1100 | numCerts, |
michael@0 | 1101 | anchor, |
michael@0 | 1102 | checkers, |
michael@0 | 1103 | revChecker, |
michael@0 | 1104 | validateCheckedCritExtOIDsList, |
michael@0 | 1105 | procParams, |
michael@0 | 1106 | &certCheckedIndex, |
michael@0 | 1107 | &checkerIndex, |
michael@0 | 1108 | &revChecking, |
michael@0 | 1109 | &reasonCode, |
michael@0 | 1110 | &nbioContext, |
michael@0 | 1111 | &finalPubKey, |
michael@0 | 1112 | &validPolicyTree, |
michael@0 | 1113 | pVerifyTree, |
michael@0 | 1114 | plContext); |
michael@0 | 1115 | |
michael@0 | 1116 | if (chainFailed) { |
michael@0 | 1117 | |
michael@0 | 1118 | /* cert chain failed to validate */ |
michael@0 | 1119 | |
michael@0 | 1120 | PKIX_DECREF(chainFailed); |
michael@0 | 1121 | PKIX_DECREF(anchor); |
michael@0 | 1122 | PKIX_DECREF(checkers); |
michael@0 | 1123 | PKIX_DECREF(validPolicyTree); |
michael@0 | 1124 | |
michael@0 | 1125 | /* if last anchor, we fail; else, we try next anchor */ |
michael@0 | 1126 | if (i == (numAnchors - 1)) { /* last anchor */ |
michael@0 | 1127 | PKIX_ERROR(PKIX_VALIDATECHAINFAILED); |
michael@0 | 1128 | } |
michael@0 | 1129 | |
michael@0 | 1130 | } else { |
michael@0 | 1131 | |
michael@0 | 1132 | /* XXX Remove this assertion after 2014-12-31. |
michael@0 | 1133 | * See bug 946984. */ |
michael@0 | 1134 | PORT_Assert(reasonCode == 0); |
michael@0 | 1135 | |
michael@0 | 1136 | /* cert chain successfully validated! */ |
michael@0 | 1137 | PKIX_CHECK(pkix_ValidateResult_Create |
michael@0 | 1138 | (finalPubKey, |
michael@0 | 1139 | anchor, |
michael@0 | 1140 | validPolicyTree, |
michael@0 | 1141 | &valResult, |
michael@0 | 1142 | plContext), |
michael@0 | 1143 | PKIX_VALIDATERESULTCREATEFAILED); |
michael@0 | 1144 | |
michael@0 | 1145 | *pResult = valResult; |
michael@0 | 1146 | |
michael@0 | 1147 | /* no need to try any more anchors in the loop */ |
michael@0 | 1148 | goto cleanup; |
michael@0 | 1149 | } |
michael@0 | 1150 | } |
michael@0 | 1151 | |
michael@0 | 1152 | cleanup: |
michael@0 | 1153 | |
michael@0 | 1154 | PKIX_DECREF(finalPubKey); |
michael@0 | 1155 | PKIX_DECREF(certs); |
michael@0 | 1156 | PKIX_DECREF(anchors); |
michael@0 | 1157 | PKIX_DECREF(anchor); |
michael@0 | 1158 | PKIX_DECREF(checkers); |
michael@0 | 1159 | PKIX_DECREF(revChecker); |
michael@0 | 1160 | PKIX_DECREF(validPolicyTree); |
michael@0 | 1161 | PKIX_DECREF(chainFailed); |
michael@0 | 1162 | PKIX_DECREF(procParams); |
michael@0 | 1163 | PKIX_DECREF(userCheckers); |
michael@0 | 1164 | PKIX_DECREF(validateCheckedCritExtOIDsList); |
michael@0 | 1165 | |
michael@0 | 1166 | PKIX_RETURN(VALIDATE); |
michael@0 | 1167 | } |
michael@0 | 1168 | |
michael@0 | 1169 | /* |
michael@0 | 1170 | * FUNCTION: pkix_Validate_BuildUserOIDs |
michael@0 | 1171 | * DESCRIPTION: |
michael@0 | 1172 | * |
michael@0 | 1173 | * This function creates a List of the OIDs that are processed by the user |
michael@0 | 1174 | * checkers in the List pointed to by "userCheckers", storing the resulting |
michael@0 | 1175 | * List at "pUserCritOIDs". If the List of userCheckers is NULL, the output |
michael@0 | 1176 | * List will be NULL. Otherwise the output List will be non-NULL, but may be |
michael@0 | 1177 | * empty. |
michael@0 | 1178 | * |
michael@0 | 1179 | * PARAMETERS: |
michael@0 | 1180 | * "userCheckers" |
michael@0 | 1181 | * The address of the List of userCheckers. |
michael@0 | 1182 | * "pUserCritOIDs" |
michael@0 | 1183 | * The address at which the List is stored. Must be non-NULL. |
michael@0 | 1184 | * "plContext" |
michael@0 | 1185 | * Platform-specific context pointer. |
michael@0 | 1186 | * THREAD SAFETY: |
michael@0 | 1187 | * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
michael@0 | 1188 | * RETURNS: |
michael@0 | 1189 | * Returns NULL if the function succeeds. |
michael@0 | 1190 | * Returns a VALIDATE Error if the function fails in a non-fatal way. |
michael@0 | 1191 | * Returns a Fatal Error if the function fails in an unrecoverable way. |
michael@0 | 1192 | */ |
michael@0 | 1193 | static PKIX_Error * |
michael@0 | 1194 | pkix_Validate_BuildUserOIDs( |
michael@0 | 1195 | PKIX_List *userCheckers, |
michael@0 | 1196 | PKIX_List **pUserCritOIDs, |
michael@0 | 1197 | void *plContext) |
michael@0 | 1198 | { |
michael@0 | 1199 | PKIX_UInt32 numUserCheckers = 0; |
michael@0 | 1200 | PKIX_UInt32 i = 0; |
michael@0 | 1201 | PKIX_List *userCritOIDs = NULL; |
michael@0 | 1202 | PKIX_List *userCheckerExtOIDs = NULL; |
michael@0 | 1203 | PKIX_Boolean supportForwarding = PKIX_FALSE; |
michael@0 | 1204 | PKIX_CertChainChecker *userChecker = NULL; |
michael@0 | 1205 | |
michael@0 | 1206 | PKIX_ENTER(VALIDATE, "pkix_Validate_BuildUserOIDs"); |
michael@0 | 1207 | PKIX_NULLCHECK_ONE(pUserCritOIDs); |
michael@0 | 1208 | |
michael@0 | 1209 | if (userCheckers != NULL) { |
michael@0 | 1210 | PKIX_CHECK(PKIX_List_Create(&userCritOIDs, plContext), |
michael@0 | 1211 | PKIX_LISTCREATEFAILED); |
michael@0 | 1212 | |
michael@0 | 1213 | PKIX_CHECK(PKIX_List_GetLength |
michael@0 | 1214 | (userCheckers, &numUserCheckers, plContext), |
michael@0 | 1215 | PKIX_LISTGETLENGTHFAILED); |
michael@0 | 1216 | |
michael@0 | 1217 | for (i = 0; i < numUserCheckers; i++) { |
michael@0 | 1218 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 1219 | (userCheckers, |
michael@0 | 1220 | i, |
michael@0 | 1221 | (PKIX_PL_Object **) &userChecker, |
michael@0 | 1222 | plContext), |
michael@0 | 1223 | PKIX_LISTGETITEMFAILED); |
michael@0 | 1224 | |
michael@0 | 1225 | PKIX_CHECK(PKIX_CertChainChecker_IsForwardCheckingSupported |
michael@0 | 1226 | (userChecker, &supportForwarding, plContext), |
michael@0 | 1227 | PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED); |
michael@0 | 1228 | |
michael@0 | 1229 | if (supportForwarding == PKIX_FALSE) { |
michael@0 | 1230 | |
michael@0 | 1231 | PKIX_CHECK(PKIX_CertChainChecker_GetSupportedExtensions |
michael@0 | 1232 | (userChecker, &userCheckerExtOIDs, plContext), |
michael@0 | 1233 | PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED); |
michael@0 | 1234 | |
michael@0 | 1235 | if (userCheckerExtOIDs != NULL) { |
michael@0 | 1236 | PKIX_CHECK(pkix_List_AppendList |
michael@0 | 1237 | (userCritOIDs, userCheckerExtOIDs, plContext), |
michael@0 | 1238 | PKIX_LISTAPPENDLISTFAILED); |
michael@0 | 1239 | } |
michael@0 | 1240 | } |
michael@0 | 1241 | |
michael@0 | 1242 | PKIX_DECREF(userCheckerExtOIDs); |
michael@0 | 1243 | PKIX_DECREF(userChecker); |
michael@0 | 1244 | } |
michael@0 | 1245 | } |
michael@0 | 1246 | |
michael@0 | 1247 | *pUserCritOIDs = userCritOIDs; |
michael@0 | 1248 | |
michael@0 | 1249 | cleanup: |
michael@0 | 1250 | |
michael@0 | 1251 | if (PKIX_ERROR_RECEIVED){ |
michael@0 | 1252 | PKIX_DECREF(userCritOIDs); |
michael@0 | 1253 | } |
michael@0 | 1254 | |
michael@0 | 1255 | PKIX_DECREF(userCheckerExtOIDs); |
michael@0 | 1256 | PKIX_DECREF(userChecker); |
michael@0 | 1257 | |
michael@0 | 1258 | PKIX_RETURN(VALIDATE); |
michael@0 | 1259 | } |
michael@0 | 1260 | |
michael@0 | 1261 | /* |
michael@0 | 1262 | * FUNCTION: PKIX_ValidateChain_nb (see comments in pkix.h) |
michael@0 | 1263 | */ |
michael@0 | 1264 | PKIX_Error * |
michael@0 | 1265 | PKIX_ValidateChain_NB( |
michael@0 | 1266 | PKIX_ValidateParams *valParams, |
michael@0 | 1267 | PKIX_UInt32 *pCertIndex, |
michael@0 | 1268 | PKIX_UInt32 *pAnchorIndex, |
michael@0 | 1269 | PKIX_UInt32 *pCheckerIndex, |
michael@0 | 1270 | PKIX_Boolean *pRevChecking, |
michael@0 | 1271 | PKIX_List **pCheckers, |
michael@0 | 1272 | void **pNBIOContext, |
michael@0 | 1273 | PKIX_ValidateResult **pResult, |
michael@0 | 1274 | PKIX_VerifyNode **pVerifyTree, |
michael@0 | 1275 | void *plContext) |
michael@0 | 1276 | { |
michael@0 | 1277 | PKIX_UInt32 numCerts = 0; |
michael@0 | 1278 | PKIX_UInt32 numAnchors = 0; |
michael@0 | 1279 | PKIX_UInt32 i = 0; |
michael@0 | 1280 | PKIX_UInt32 certIndex = 0; |
michael@0 | 1281 | PKIX_UInt32 anchorIndex = 0; |
michael@0 | 1282 | PKIX_UInt32 checkerIndex = 0; |
michael@0 | 1283 | PKIX_UInt32 reasonCode = 0; |
michael@0 | 1284 | PKIX_Boolean revChecking = PKIX_FALSE; |
michael@0 | 1285 | PKIX_List *certs = NULL; |
michael@0 | 1286 | PKIX_List *anchors = NULL; |
michael@0 | 1287 | PKIX_List *checkers = NULL; |
michael@0 | 1288 | PKIX_List *userCheckers = NULL; |
michael@0 | 1289 | PKIX_List *validateCheckedCritExtOIDsList = NULL; |
michael@0 | 1290 | PKIX_TrustAnchor *anchor = NULL; |
michael@0 | 1291 | PKIX_ValidateResult *valResult = NULL; |
michael@0 | 1292 | PKIX_PL_PublicKey *finalPubKey = NULL; |
michael@0 | 1293 | PKIX_PolicyNode *validPolicyTree = NULL; |
michael@0 | 1294 | PKIX_ProcessingParams *procParams = NULL; |
michael@0 | 1295 | PKIX_RevocationChecker *revChecker = NULL; |
michael@0 | 1296 | PKIX_Error *chainFailed = NULL; |
michael@0 | 1297 | void *nbioContext = NULL; |
michael@0 | 1298 | |
michael@0 | 1299 | PKIX_ENTER(VALIDATE, "PKIX_ValidateChain_NB"); |
michael@0 | 1300 | PKIX_NULLCHECK_FOUR |
michael@0 | 1301 | (valParams, pCertIndex, pAnchorIndex, pCheckerIndex); |
michael@0 | 1302 | PKIX_NULLCHECK_FOUR(pRevChecking, pCheckers, pNBIOContext, pResult); |
michael@0 | 1303 | |
michael@0 | 1304 | nbioContext = *pNBIOContext; |
michael@0 | 1305 | *pNBIOContext = NULL; |
michael@0 | 1306 | |
michael@0 | 1307 | /* extract various parameters from valParams */ |
michael@0 | 1308 | PKIX_CHECK(pkix_ExtractParameters |
michael@0 | 1309 | (valParams, |
michael@0 | 1310 | &certs, |
michael@0 | 1311 | &numCerts, |
michael@0 | 1312 | &procParams, |
michael@0 | 1313 | &anchors, |
michael@0 | 1314 | &numAnchors, |
michael@0 | 1315 | plContext), |
michael@0 | 1316 | PKIX_EXTRACTPARAMETERSFAILED); |
michael@0 | 1317 | |
michael@0 | 1318 | /* |
michael@0 | 1319 | * Create a List of the OIDs that will be processed by the user |
michael@0 | 1320 | * checkers. User checkers are not responsible for removing OIDs from |
michael@0 | 1321 | * the List of unresolved critical extensions, as libpkix checkers are. |
michael@0 | 1322 | * So we add those user checkers' OIDs to the removal list to be taken |
michael@0 | 1323 | * out by CheckChain. |
michael@0 | 1324 | */ |
michael@0 | 1325 | PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers |
michael@0 | 1326 | (procParams, &userCheckers, plContext), |
michael@0 | 1327 | PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); |
michael@0 | 1328 | |
michael@0 | 1329 | PKIX_CHECK(pkix_Validate_BuildUserOIDs |
michael@0 | 1330 | (userCheckers, &validateCheckedCritExtOIDsList, plContext), |
michael@0 | 1331 | PKIX_VALIDATEBUILDUSEROIDSFAILED); |
michael@0 | 1332 | |
michael@0 | 1333 | PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker |
michael@0 | 1334 | (procParams, &revChecker, plContext), |
michael@0 | 1335 | PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED); |
michael@0 | 1336 | |
michael@0 | 1337 | /* Are we resuming after a WOULDBLOCK return, or starting anew ? */ |
michael@0 | 1338 | if (nbioContext != NULL) { |
michael@0 | 1339 | /* Resuming */ |
michael@0 | 1340 | certIndex = *pCertIndex; |
michael@0 | 1341 | anchorIndex = *pAnchorIndex; |
michael@0 | 1342 | checkerIndex = *pCheckerIndex; |
michael@0 | 1343 | revChecking = *pRevChecking; |
michael@0 | 1344 | checkers = *pCheckers; |
michael@0 | 1345 | *pCheckers = NULL; |
michael@0 | 1346 | } |
michael@0 | 1347 | |
michael@0 | 1348 | /* try to validate the chain with each anchor */ |
michael@0 | 1349 | for (i = anchorIndex; i < numAnchors; i++) { |
michael@0 | 1350 | |
michael@0 | 1351 | /* get trust anchor */ |
michael@0 | 1352 | PKIX_CHECK(PKIX_List_GetItem |
michael@0 | 1353 | (anchors, i, (PKIX_PL_Object **)&anchor, plContext), |
michael@0 | 1354 | PKIX_LISTGETITEMFAILED); |
michael@0 | 1355 | |
michael@0 | 1356 | /* initialize checkers using information from trust anchor */ |
michael@0 | 1357 | if (nbioContext == NULL) { |
michael@0 | 1358 | PKIX_CHECK(pkix_InitializeCheckers |
michael@0 | 1359 | (anchor, |
michael@0 | 1360 | procParams, |
michael@0 | 1361 | numCerts, |
michael@0 | 1362 | &checkers, |
michael@0 | 1363 | plContext), |
michael@0 | 1364 | PKIX_INITIALIZECHECKERSFAILED); |
michael@0 | 1365 | } |
michael@0 | 1366 | |
michael@0 | 1367 | /* |
michael@0 | 1368 | * Validate the chain using this trust anchor and these |
michael@0 | 1369 | * checkers. |
michael@0 | 1370 | */ |
michael@0 | 1371 | chainFailed = pkix_CheckChain |
michael@0 | 1372 | (certs, |
michael@0 | 1373 | numCerts, |
michael@0 | 1374 | anchor, |
michael@0 | 1375 | checkers, |
michael@0 | 1376 | revChecker, |
michael@0 | 1377 | validateCheckedCritExtOIDsList, |
michael@0 | 1378 | procParams, |
michael@0 | 1379 | &certIndex, |
michael@0 | 1380 | &checkerIndex, |
michael@0 | 1381 | &revChecking, |
michael@0 | 1382 | &reasonCode, |
michael@0 | 1383 | &nbioContext, |
michael@0 | 1384 | &finalPubKey, |
michael@0 | 1385 | &validPolicyTree, |
michael@0 | 1386 | pVerifyTree, |
michael@0 | 1387 | plContext); |
michael@0 | 1388 | |
michael@0 | 1389 | if (nbioContext != NULL) { |
michael@0 | 1390 | *pCertIndex = certIndex; |
michael@0 | 1391 | *pAnchorIndex = anchorIndex; |
michael@0 | 1392 | *pCheckerIndex = checkerIndex; |
michael@0 | 1393 | *pRevChecking = revChecking; |
michael@0 | 1394 | PKIX_INCREF(checkers); |
michael@0 | 1395 | *pCheckers = checkers; |
michael@0 | 1396 | *pNBIOContext = nbioContext; |
michael@0 | 1397 | goto cleanup; |
michael@0 | 1398 | } |
michael@0 | 1399 | |
michael@0 | 1400 | if (chainFailed) { |
michael@0 | 1401 | |
michael@0 | 1402 | /* cert chain failed to validate */ |
michael@0 | 1403 | |
michael@0 | 1404 | PKIX_DECREF(chainFailed); |
michael@0 | 1405 | PKIX_DECREF(anchor); |
michael@0 | 1406 | PKIX_DECREF(checkers); |
michael@0 | 1407 | PKIX_DECREF(validPolicyTree); |
michael@0 | 1408 | |
michael@0 | 1409 | /* if last anchor, we fail; else, we try next anchor */ |
michael@0 | 1410 | if (i == (numAnchors - 1)) { /* last anchor */ |
michael@0 | 1411 | PKIX_ERROR(PKIX_VALIDATECHAINFAILED); |
michael@0 | 1412 | } |
michael@0 | 1413 | |
michael@0 | 1414 | } else { |
michael@0 | 1415 | |
michael@0 | 1416 | /* XXX Remove this assertion after 2014-12-31. |
michael@0 | 1417 | * See bug 946984. */ |
michael@0 | 1418 | PORT_Assert(reasonCode == 0); |
michael@0 | 1419 | |
michael@0 | 1420 | /* cert chain successfully validated! */ |
michael@0 | 1421 | PKIX_CHECK(pkix_ValidateResult_Create |
michael@0 | 1422 | (finalPubKey, |
michael@0 | 1423 | anchor, |
michael@0 | 1424 | validPolicyTree, |
michael@0 | 1425 | &valResult, |
michael@0 | 1426 | plContext), |
michael@0 | 1427 | PKIX_VALIDATERESULTCREATEFAILED); |
michael@0 | 1428 | |
michael@0 | 1429 | *pResult = valResult; |
michael@0 | 1430 | |
michael@0 | 1431 | /* no need to try any more anchors in the loop */ |
michael@0 | 1432 | goto cleanup; |
michael@0 | 1433 | } |
michael@0 | 1434 | } |
michael@0 | 1435 | |
michael@0 | 1436 | cleanup: |
michael@0 | 1437 | |
michael@0 | 1438 | PKIX_DECREF(finalPubKey); |
michael@0 | 1439 | PKIX_DECREF(certs); |
michael@0 | 1440 | PKIX_DECREF(anchors); |
michael@0 | 1441 | PKIX_DECREF(anchor); |
michael@0 | 1442 | PKIX_DECREF(checkers); |
michael@0 | 1443 | PKIX_DECREF(revChecker); |
michael@0 | 1444 | PKIX_DECREF(validPolicyTree); |
michael@0 | 1445 | PKIX_DECREF(chainFailed); |
michael@0 | 1446 | PKIX_DECREF(procParams); |
michael@0 | 1447 | PKIX_DECREF(userCheckers); |
michael@0 | 1448 | PKIX_DECREF(validateCheckedCritExtOIDsList); |
michael@0 | 1449 | |
michael@0 | 1450 | PKIX_RETURN(VALIDATE); |
michael@0 | 1451 | } |