1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,516 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * pkix_targetcertchecker.c 1.9 + * 1.10 + * Functions for target cert validation 1.11 + * 1.12 + */ 1.13 + 1.14 + 1.15 +#include "pkix_targetcertchecker.h" 1.16 + 1.17 +/* --Private-TargetCertCheckerState-Functions------------------------------- */ 1.18 + 1.19 +/* 1.20 + * FUNCTION: pkix_TargetCertCheckerState_Destroy 1.21 + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 1.22 + */ 1.23 +static PKIX_Error * 1.24 +pkix_TargetCertCheckerState_Destroy( 1.25 + PKIX_PL_Object *object, 1.26 + void *plContext) 1.27 +{ 1.28 + pkix_TargetCertCheckerState *state = NULL; 1.29 + 1.30 + PKIX_ENTER(TARGETCERTCHECKERSTATE, 1.31 + "pkix_TargetCertCheckerState_Destroy"); 1.32 + PKIX_NULLCHECK_ONE(object); 1.33 + 1.34 + /* Check that this object is a target cert checker state */ 1.35 + PKIX_CHECK(pkix_CheckType 1.36 + (object, PKIX_TARGETCERTCHECKERSTATE_TYPE, plContext), 1.37 + PKIX_OBJECTNOTTARGETCERTCHECKERSTATE); 1.38 + 1.39 + state = (pkix_TargetCertCheckerState *)object; 1.40 + 1.41 + PKIX_DECREF(state->certSelector); 1.42 + PKIX_DECREF(state->extKeyUsageOID); 1.43 + PKIX_DECREF(state->subjAltNameOID); 1.44 + PKIX_DECREF(state->pathToNameList); 1.45 + PKIX_DECREF(state->extKeyUsageList); 1.46 + PKIX_DECREF(state->subjAltNameList); 1.47 + 1.48 +cleanup: 1.49 + 1.50 + PKIX_RETURN(TARGETCERTCHECKERSTATE); 1.51 +} 1.52 + 1.53 +/* 1.54 + * FUNCTION: pkix_TargetCertCheckerState_RegisterSelf 1.55 + * DESCRIPTION: 1.56 + * Registers PKIX_TARGETCERTCHECKERSTATE_TYPE and its related functions with 1.57 + * systemClasses[] 1.58 + * THREAD SAFETY: 1.59 + * Not Thread Safe - for performance and complexity reasons 1.60 + * 1.61 + * Since this function is only called by PKIX_PL_Initialize, which should 1.62 + * only be called once, it is acceptable that this function is not 1.63 + * thread-safe. 1.64 + */ 1.65 +PKIX_Error * 1.66 +pkix_TargetCertCheckerState_RegisterSelf(void *plContext) 1.67 +{ 1.68 + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 1.69 + pkix_ClassTable_Entry entry; 1.70 + 1.71 + PKIX_ENTER(TARGETCERTCHECKERSTATE, 1.72 + "pkix_TargetCertCheckerState_RegisterSelf"); 1.73 + 1.74 + entry.description = "TargetCertCheckerState"; 1.75 + entry.objCounter = 0; 1.76 + entry.typeObjectSize = sizeof(pkix_TargetCertCheckerState); 1.77 + entry.destructor = pkix_TargetCertCheckerState_Destroy; 1.78 + entry.equalsFunction = NULL; 1.79 + entry.hashcodeFunction = NULL; 1.80 + entry.toStringFunction = NULL; 1.81 + entry.comparator = NULL; 1.82 + entry.duplicateFunction = NULL; 1.83 + 1.84 + systemClasses[PKIX_TARGETCERTCHECKERSTATE_TYPE] = entry; 1.85 + 1.86 + PKIX_RETURN(TARGETCERTCHECKERSTATE); 1.87 +} 1.88 + 1.89 +/* 1.90 + * FUNCTION: pkix_TargetCertCheckerState_Create 1.91 + * DESCRIPTION: 1.92 + * 1.93 + * Creates a new TargetCertCheckerState using the CertSelector pointed to 1.94 + * by "certSelector" and the number of certs represented by "certsRemaining" 1.95 + * and stores it at "pState". 1.96 + * 1.97 + * PARAMETERS: 1.98 + * "certSelector" 1.99 + * Address of CertSelector representing the criteria against which the 1.100 + * final certificate in a chain is to be matched. Must be non-NULL. 1.101 + * "certsRemaining" 1.102 + * Number of certificates remaining in the chain. 1.103 + * "pState" 1.104 + * Address where object pointer will be stored. Must be non-NULL. 1.105 + * "plContext" 1.106 + * Platform-specific context pointer. 1.107 + * THREAD SAFETY: 1.108 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.109 + * RETURNS: 1.110 + * Returns NULL if the function succeeds. 1.111 + * Returns a TargetCertCheckerState Error if the function fails in a 1.112 + * non-fatal way. 1.113 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.114 + */ 1.115 +PKIX_Error * 1.116 +pkix_TargetCertCheckerState_Create( 1.117 + PKIX_CertSelector *certSelector, 1.118 + PKIX_UInt32 certsRemaining, 1.119 + pkix_TargetCertCheckerState **pState, 1.120 + void *plContext) 1.121 +{ 1.122 + pkix_TargetCertCheckerState *state = NULL; 1.123 + PKIX_ComCertSelParams *certSelectorParams = NULL; 1.124 + PKIX_List *pathToNameList = NULL; 1.125 + PKIX_List *extKeyUsageList = NULL; 1.126 + PKIX_List *subjAltNameList = NULL; 1.127 + PKIX_PL_OID *extKeyUsageOID = NULL; 1.128 + PKIX_PL_OID *subjAltNameOID = NULL; 1.129 + PKIX_Boolean subjAltNameMatchAll = PKIX_TRUE; 1.130 + 1.131 + PKIX_ENTER(TARGETCERTCHECKERSTATE, 1.132 + "pkix_TargetCertCheckerState_Create"); 1.133 + PKIX_NULLCHECK_ONE(pState); 1.134 + 1.135 + PKIX_CHECK(PKIX_PL_OID_Create 1.136 + (PKIX_EXTENDEDKEYUSAGE_OID, 1.137 + &extKeyUsageOID, 1.138 + plContext), 1.139 + PKIX_OIDCREATEFAILED); 1.140 + 1.141 + PKIX_CHECK(PKIX_PL_OID_Create 1.142 + (PKIX_CERTSUBJALTNAME_OID, 1.143 + &subjAltNameOID, 1.144 + plContext), 1.145 + PKIX_OIDCREATEFAILED); 1.146 + 1.147 + PKIX_CHECK(PKIX_PL_Object_Alloc 1.148 + (PKIX_TARGETCERTCHECKERSTATE_TYPE, 1.149 + sizeof (pkix_TargetCertCheckerState), 1.150 + (PKIX_PL_Object **)&state, 1.151 + plContext), 1.152 + PKIX_COULDNOTCREATETARGETCERTCHECKERSTATEOBJECT); 1.153 + 1.154 + /* initialize fields */ 1.155 + 1.156 + if (certSelector != NULL) { 1.157 + 1.158 + PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams 1.159 + (certSelector, &certSelectorParams, plContext), 1.160 + PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMFAILED); 1.161 + 1.162 + if (certSelectorParams != NULL) { 1.163 + 1.164 + PKIX_CHECK(PKIX_ComCertSelParams_GetPathToNames 1.165 + (certSelectorParams, 1.166 + &pathToNameList, 1.167 + plContext), 1.168 + PKIX_COMCERTSELPARAMSGETPATHTONAMESFAILED); 1.169 + 1.170 + PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage 1.171 + (certSelectorParams, 1.172 + &extKeyUsageList, 1.173 + plContext), 1.174 + PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); 1.175 + 1.176 + PKIX_CHECK(PKIX_ComCertSelParams_GetSubjAltNames 1.177 + (certSelectorParams, 1.178 + &subjAltNameList, 1.179 + plContext), 1.180 + PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED); 1.181 + 1.182 + PKIX_CHECK(PKIX_ComCertSelParams_GetMatchAllSubjAltNames 1.183 + (certSelectorParams, 1.184 + &subjAltNameMatchAll, 1.185 + plContext), 1.186 + PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED); 1.187 + } 1.188 + } 1.189 + 1.190 + state->certsRemaining = certsRemaining; 1.191 + state->subjAltNameMatchAll = subjAltNameMatchAll; 1.192 + 1.193 + PKIX_INCREF(certSelector); 1.194 + state->certSelector = certSelector; 1.195 + 1.196 + state->pathToNameList = pathToNameList; 1.197 + pathToNameList = NULL; 1.198 + 1.199 + state->extKeyUsageList = extKeyUsageList; 1.200 + extKeyUsageList = NULL; 1.201 + 1.202 + state->subjAltNameList = subjAltNameList; 1.203 + subjAltNameList = NULL; 1.204 + 1.205 + state->extKeyUsageOID = extKeyUsageOID; 1.206 + extKeyUsageOID = NULL; 1.207 + 1.208 + state->subjAltNameOID = subjAltNameOID; 1.209 + subjAltNameOID = NULL; 1.210 + 1.211 + *pState = state; 1.212 + state = NULL; 1.213 + 1.214 +cleanup: 1.215 + 1.216 + PKIX_DECREF(extKeyUsageOID); 1.217 + PKIX_DECREF(subjAltNameOID); 1.218 + PKIX_DECREF(pathToNameList); 1.219 + PKIX_DECREF(extKeyUsageList); 1.220 + PKIX_DECREF(subjAltNameList); 1.221 + PKIX_DECREF(state); 1.222 + 1.223 + PKIX_DECREF(certSelectorParams); 1.224 + 1.225 + PKIX_RETURN(TARGETCERTCHECKERSTATE); 1.226 + 1.227 +} 1.228 + 1.229 +/* --Private-TargetCertChecker-Functions------------------------------- */ 1.230 + 1.231 +/* 1.232 + * FUNCTION: pkix_TargetCertChecker_Check 1.233 + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) 1.234 + */ 1.235 +PKIX_Error * 1.236 +pkix_TargetCertChecker_Check( 1.237 + PKIX_CertChainChecker *checker, 1.238 + PKIX_PL_Cert *cert, 1.239 + PKIX_List *unresolvedCriticalExtensions, 1.240 + void **pNBIOContext, 1.241 + void *plContext) 1.242 +{ 1.243 + pkix_TargetCertCheckerState *state = NULL; 1.244 + PKIX_CertSelector_MatchCallback certSelectorMatch = NULL; 1.245 + PKIX_PL_CertNameConstraints *nameConstraints = NULL; 1.246 + PKIX_List *certSubjAltNames = NULL; 1.247 + PKIX_List *certExtKeyUsageList = NULL; 1.248 + PKIX_PL_GeneralName *name = NULL; 1.249 + PKIX_PL_X500Name *certSubjectName = NULL; 1.250 + PKIX_Boolean checkPassed = PKIX_FALSE; 1.251 + PKIX_UInt32 numItems, i; 1.252 + PKIX_UInt32 matchCount = 0; 1.253 + 1.254 + PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Check"); 1.255 + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); 1.256 + 1.257 + *pNBIOContext = NULL; /* we never block on pending I/O */ 1.258 + 1.259 + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState 1.260 + (checker, (PKIX_PL_Object **)&state, plContext), 1.261 + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); 1.262 + 1.263 + (state->certsRemaining)--; 1.264 + 1.265 + if (state->pathToNameList != NULL) { 1.266 + 1.267 + PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints 1.268 + (cert, &nameConstraints, plContext), 1.269 + PKIX_CERTGETNAMECONSTRAINTSFAILED); 1.270 + 1.271 + /* 1.272 + * XXX We should either make the following call a public one 1.273 + * so it is legal to call from the portability layer or we 1.274 + * should try to create pathToNameList as CertNameConstraints 1.275 + * then call the existing check function. 1.276 + */ 1.277 + PKIX_CHECK(PKIX_PL_CertNameConstraints_CheckNamesInNameSpace 1.278 + (state->pathToNameList, 1.279 + nameConstraints, 1.280 + &checkPassed, 1.281 + plContext), 1.282 + PKIX_CERTNAMECONSTRAINTSCHECKNAMEINNAMESPACEFAILED); 1.283 + 1.284 + if (checkPassed != PKIX_TRUE) { 1.285 + PKIX_ERROR(PKIX_VALIDATIONFAILEDPATHTONAMECHECKFAILED); 1.286 + } 1.287 + 1.288 + } 1.289 + 1.290 + PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames 1.291 + (cert, &certSubjAltNames, plContext), 1.292 + PKIX_CERTGETSUBJALTNAMESFAILED); 1.293 + 1.294 + if (state->subjAltNameList != NULL && certSubjAltNames != NULL) { 1.295 + 1.296 + PKIX_CHECK(PKIX_List_GetLength 1.297 + (state->subjAltNameList, &numItems, plContext), 1.298 + PKIX_LISTGETLENGTHFAILED); 1.299 + 1.300 + for (i = 0; i < numItems; i++) { 1.301 + 1.302 + PKIX_CHECK(PKIX_List_GetItem 1.303 + (state->subjAltNameList, 1.304 + i, 1.305 + (PKIX_PL_Object **) &name, 1.306 + plContext), 1.307 + PKIX_LISTGETITEMFAILED); 1.308 + 1.309 + PKIX_CHECK(pkix_List_Contains 1.310 + (certSubjAltNames, 1.311 + (PKIX_PL_Object *) name, 1.312 + &checkPassed, 1.313 + plContext), 1.314 + PKIX_LISTCONTAINSFAILED); 1.315 + 1.316 + PKIX_DECREF(name); 1.317 + 1.318 + if (checkPassed == PKIX_TRUE) { 1.319 + 1.320 + if (state->subjAltNameMatchAll == PKIX_FALSE) { 1.321 + matchCount = numItems; 1.322 + break; 1.323 + } else { 1.324 + /* else continue checking next */ 1.325 + matchCount++; 1.326 + } 1.327 + 1.328 + } 1.329 + } 1.330 + 1.331 + if (matchCount != numItems) { 1.332 + PKIX_ERROR(PKIX_SUBJALTNAMECHECKFAILED); 1.333 + 1.334 + } 1.335 + } 1.336 + 1.337 + if (state->certsRemaining == 0) { 1.338 + 1.339 + if (state->certSelector != NULL) { 1.340 + PKIX_CHECK(PKIX_CertSelector_GetMatchCallback 1.341 + (state->certSelector, 1.342 + &certSelectorMatch, 1.343 + plContext), 1.344 + PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); 1.345 + 1.346 + PKIX_CHECK(certSelectorMatch 1.347 + (state->certSelector, 1.348 + cert, 1.349 + plContext), 1.350 + PKIX_CERTSELECTORMATCHFAILED); 1.351 + } else { 1.352 + /* Check at least cert/key usages if target cert selector 1.353 + * is not set. */ 1.354 + PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, 1.355 + PKIX_FALSE /* is chain cert*/, 1.356 + plContext), 1.357 + PKIX_CERTVERIFYCERTTYPEFAILED); 1.358 + } 1.359 + /* 1.360 + * There are two Extended Key Usage Checkings 1.361 + * available : 1.362 + * 1) here at the targetcertchecker where we 1.363 + * verify the Extended Key Usage OIDs application 1.364 + * specifies via ComCertSelParams are included 1.365 + * in Cert's Extended Key Usage OID's. Note, 1.366 + * this is an OID to OID comparison and only last 1.367 + * Cert is checked. 1.368 + * 2) at user defined ekuchecker where checking 1.369 + * is applied to all Certs on the chain and 1.370 + * the NSS Extended Key Usage algorithm is 1.371 + * used. In order to invoke this checking, not 1.372 + * only does the ComCertSelparams needs to be 1.373 + * set, the EKU initialize call is required to 1.374 + * activate the checking. 1.375 + * 1.376 + * XXX We use the same ComCertSelParams Set/Get 1.377 + * functions to set the parameters for both cases. 1.378 + * We may want to separate them in the future. 1.379 + */ 1.380 + 1.381 + PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage 1.382 + (cert, &certExtKeyUsageList, plContext), 1.383 + PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); 1.384 + 1.385 + 1.386 + if (state->extKeyUsageList != NULL && 1.387 + certExtKeyUsageList != NULL) { 1.388 + 1.389 + PKIX_CHECK(PKIX_List_GetLength 1.390 + (state->extKeyUsageList, &numItems, plContext), 1.391 + PKIX_LISTGETLENGTHFAILED); 1.392 + 1.393 + for (i = 0; i < numItems; i++) { 1.394 + 1.395 + PKIX_CHECK(PKIX_List_GetItem 1.396 + (state->extKeyUsageList, 1.397 + i, 1.398 + (PKIX_PL_Object **) &name, 1.399 + plContext), 1.400 + PKIX_LISTGETITEMFAILED); 1.401 + 1.402 + PKIX_CHECK(pkix_List_Contains 1.403 + (certExtKeyUsageList, 1.404 + (PKIX_PL_Object *) name, 1.405 + &checkPassed, 1.406 + plContext), 1.407 + PKIX_LISTCONTAINSFAILED); 1.408 + 1.409 + PKIX_DECREF(name); 1.410 + 1.411 + if (checkPassed != PKIX_TRUE) { 1.412 + PKIX_ERROR 1.413 + (PKIX_EXTENDEDKEYUSAGECHECKINGFAILED); 1.414 + 1.415 + } 1.416 + } 1.417 + } 1.418 + } else { 1.419 + /* Check key usage and cert type based on certificate usage. */ 1.420 + PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, PKIX_TRUE, 1.421 + plContext), 1.422 + PKIX_CERTVERIFYCERTTYPEFAILED); 1.423 + } 1.424 + 1.425 + /* Remove Critical Extension OID from list */ 1.426 + if (unresolvedCriticalExtensions != NULL) { 1.427 + 1.428 + PKIX_CHECK(pkix_List_Remove 1.429 + (unresolvedCriticalExtensions, 1.430 + (PKIX_PL_Object *) state->extKeyUsageOID, 1.431 + plContext), 1.432 + PKIX_LISTREMOVEFAILED); 1.433 + 1.434 + PKIX_CHECK(PKIX_PL_Cert_GetSubject 1.435 + (cert, &certSubjectName, plContext), 1.436 + PKIX_CERTGETSUBJECTFAILED); 1.437 + 1.438 + if (certSubjAltNames != NULL) { 1.439 + PKIX_CHECK(pkix_List_Remove 1.440 + (unresolvedCriticalExtensions, 1.441 + (PKIX_PL_Object *) state->subjAltNameOID, 1.442 + plContext), 1.443 + PKIX_LISTREMOVEFAILED); 1.444 + } 1.445 + 1.446 + } 1.447 + 1.448 +cleanup: 1.449 + 1.450 + PKIX_DECREF(name); 1.451 + PKIX_DECREF(nameConstraints); 1.452 + PKIX_DECREF(certSubjAltNames); 1.453 + PKIX_DECREF(certExtKeyUsageList); 1.454 + PKIX_DECREF(certSubjectName); 1.455 + PKIX_DECREF(state); 1.456 + 1.457 + PKIX_RETURN(CERTCHAINCHECKER); 1.458 + 1.459 +} 1.460 + 1.461 +/* 1.462 + * FUNCTION: pkix_TargetCertChecker_Initialize 1.463 + * DESCRIPTION: 1.464 + * 1.465 + * Creates a new CertChainChecker and stores it at "pChecker", where it will 1.466 + * used by pkix_TargetCertChecker_Check to check that the final certificate 1.467 + * of a chain meets the criteria of the CertSelector pointed to by 1.468 + * "certSelector". The number of certs remaining in the chain, represented by 1.469 + * "certsRemaining" is used to initialize the checker's state. 1.470 + * 1.471 + * PARAMETERS: 1.472 + * "certSelector" 1.473 + * Address of CertSelector representing the criteria against which the 1.474 + * final certificate in a chain is to be matched. May be NULL. 1.475 + * "certsRemaining" 1.476 + * Number of certificates remaining in the chain. 1.477 + * "pChecker" 1.478 + * Address where object pointer will be stored. Must be non-NULL. 1.479 + * "plContext" 1.480 + * Platform-specific context pointer. 1.481 + * THREAD SAFETY: 1.482 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.483 + * RETURNS: 1.484 + * Returns NULL if the function succeeds. 1.485 + * Returns a CertChainChecker Error if the function fails in a non-fatal way. 1.486 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.487 + */ 1.488 +PKIX_Error * 1.489 +pkix_TargetCertChecker_Initialize( 1.490 + PKIX_CertSelector *certSelector, 1.491 + PKIX_UInt32 certsRemaining, 1.492 + PKIX_CertChainChecker **pChecker, 1.493 + void *plContext) 1.494 +{ 1.495 + pkix_TargetCertCheckerState *state = NULL; 1.496 + 1.497 + PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Initialize"); 1.498 + PKIX_NULLCHECK_ONE(pChecker); 1.499 + 1.500 + PKIX_CHECK(pkix_TargetCertCheckerState_Create 1.501 + (certSelector, certsRemaining, &state, plContext), 1.502 + PKIX_TARGETCERTCHECKERSTATECREATEFAILED); 1.503 + 1.504 + PKIX_CHECK(PKIX_CertChainChecker_Create 1.505 + (pkix_TargetCertChecker_Check, 1.506 + PKIX_FALSE, 1.507 + PKIX_FALSE, 1.508 + NULL, 1.509 + (PKIX_PL_Object *)state, 1.510 + pChecker, 1.511 + plContext), 1.512 + PKIX_CERTCHAINCHECKERCREATEFAILED); 1.513 + 1.514 +cleanup: 1.515 + 1.516 + PKIX_DECREF(state); 1.517 + 1.518 + PKIX_RETURN(CERTCHAINCHECKER); 1.519 +}