pkix_targetcertchecker.c (18702B)
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 }