1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,443 @@ 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_signaturechecker.c 1.9 + * 1.10 + * Functions for signature validation 1.11 + * 1.12 + */ 1.13 + 1.14 +#include "pkix_signaturechecker.h" 1.15 + 1.16 +/* 1.17 + * FUNCTION: pkix_SignatureCheckerstate_Destroy 1.18 + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 1.19 + */ 1.20 +static PKIX_Error * 1.21 +pkix_SignatureCheckerState_Destroy( 1.22 + PKIX_PL_Object *object, 1.23 + void *plContext) 1.24 +{ 1.25 + pkix_SignatureCheckerState *state = NULL; 1.26 + 1.27 + PKIX_ENTER(SIGNATURECHECKERSTATE, 1.28 + "pkix_SignatureCheckerState_Destroy"); 1.29 + PKIX_NULLCHECK_ONE(object); 1.30 + 1.31 + /* Check that this object is a signature checker state */ 1.32 + PKIX_CHECK(pkix_CheckType 1.33 + (object, PKIX_SIGNATURECHECKERSTATE_TYPE, plContext), 1.34 + PKIX_OBJECTNOTSIGNATURECHECKERSTATE); 1.35 + 1.36 + state = (pkix_SignatureCheckerState *) object; 1.37 + 1.38 + state->prevCertCertSign = PKIX_FALSE; 1.39 + 1.40 + PKIX_DECREF(state->prevPublicKey); 1.41 + PKIX_DECREF(state->prevPublicKeyList); 1.42 + PKIX_DECREF(state->keyUsageOID); 1.43 + 1.44 +cleanup: 1.45 + 1.46 + PKIX_RETURN(SIGNATURECHECKERSTATE); 1.47 +} 1.48 + 1.49 +/* 1.50 + * FUNCTION: pkix_SignatureCheckerState_RegisterSelf 1.51 + * 1.52 + * DESCRIPTION: 1.53 + * Registers PKIX_SIGNATURECHECKERSTATE_TYPE and its related functions 1.54 + * with systemClasses[] 1.55 + * 1.56 + * THREAD SAFETY: 1.57 + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.58 + * 1.59 + * Since this function is only called by PKIX_PL_Initialize, which should 1.60 + * only be called once, it is acceptable that this function is not 1.61 + * thread-safe. 1.62 + */ 1.63 +PKIX_Error * 1.64 +pkix_SignatureCheckerState_RegisterSelf(void *plContext) 1.65 +{ 1.66 + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 1.67 + pkix_ClassTable_Entry entry; 1.68 + 1.69 + PKIX_ENTER(SIGNATURECHECKERSTATE, 1.70 + "pkix_SignatureCheckerState_RegisterSelf"); 1.71 + 1.72 + entry.description = "SignatureCheckerState"; 1.73 + entry.objCounter = 0; 1.74 + entry.typeObjectSize = sizeof(pkix_SignatureCheckerState); 1.75 + entry.destructor = pkix_SignatureCheckerState_Destroy; 1.76 + entry.equalsFunction = NULL; 1.77 + entry.hashcodeFunction = NULL; 1.78 + entry.toStringFunction = NULL; 1.79 + entry.comparator = NULL; 1.80 + entry.duplicateFunction = NULL; 1.81 + 1.82 + systemClasses[PKIX_SIGNATURECHECKERSTATE_TYPE] = entry; 1.83 + 1.84 + PKIX_RETURN(SIGNATURECHECKERSTATE); 1.85 +} 1.86 + 1.87 +/* 1.88 + * FUNCTION: pkix_SignatureCheckerState_Create 1.89 + * 1.90 + * DESCRIPTION: 1.91 + * Allocate and initialize SignatureChecker state data. 1.92 + * 1.93 + * PARAMETERS 1.94 + * "trustedPubKey" 1.95 + * Address of trusted Anchor Public Key for verifying first Cert in the 1.96 + * chain. Must be non-NULL. 1.97 + * "certsRemaining" 1.98 + * Number of certificates remaining in the chain. 1.99 + * "pCheckerState" 1.100 + * Address where SignatureCheckerState will be stored. Must be non-NULL. 1.101 + * "plContext" 1.102 + * Platform-specific context pointer. 1.103 + * 1.104 + * THREAD SAFETY: 1.105 + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.106 + * 1.107 + * RETURNS: 1.108 + * Returns NULL if the function succeeds. 1.109 + * Returns a SignatureCheckerState Error if the function fails in a 1.110 + * non-fatal way. 1.111 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.112 + */ 1.113 +static PKIX_Error * 1.114 +pkix_SignatureCheckerState_Create( 1.115 + PKIX_PL_PublicKey *trustedPubKey, 1.116 + PKIX_UInt32 certsRemaining, 1.117 + pkix_SignatureCheckerState **pCheckerState, 1.118 + void *plContext) 1.119 +{ 1.120 + pkix_SignatureCheckerState *state = NULL; 1.121 + PKIX_PL_OID *keyUsageOID = NULL; 1.122 + 1.123 + PKIX_ENTER(SIGNATURECHECKERSTATE, "pkix_SignatureCheckerState_Create"); 1.124 + PKIX_NULLCHECK_TWO(trustedPubKey, pCheckerState); 1.125 + 1.126 + PKIX_CHECK(PKIX_PL_Object_Alloc 1.127 + (PKIX_SIGNATURECHECKERSTATE_TYPE, 1.128 + sizeof (pkix_SignatureCheckerState), 1.129 + (PKIX_PL_Object **)&state, 1.130 + plContext), 1.131 + PKIX_COULDNOTCREATESIGNATURECHECKERSTATEOBJECT); 1.132 + 1.133 + /* Initialize fields */ 1.134 + 1.135 + state->prevCertCertSign = PKIX_TRUE; 1.136 + state->prevPublicKeyList = NULL; 1.137 + state->certsRemaining = certsRemaining; 1.138 + 1.139 + PKIX_INCREF(trustedPubKey); 1.140 + state->prevPublicKey = trustedPubKey; 1.141 + 1.142 + PKIX_CHECK(PKIX_PL_OID_Create 1.143 + (PKIX_CERTKEYUSAGE_OID, 1.144 + &keyUsageOID, 1.145 + plContext), 1.146 + PKIX_OIDCREATEFAILED); 1.147 + 1.148 + state->keyUsageOID = keyUsageOID; 1.149 + keyUsageOID = NULL; 1.150 + 1.151 + *pCheckerState = state; 1.152 + state = NULL; 1.153 + 1.154 +cleanup: 1.155 + 1.156 + PKIX_DECREF(keyUsageOID); 1.157 + PKIX_DECREF(state); 1.158 + 1.159 + PKIX_RETURN(SIGNATURECHECKERSTATE); 1.160 +} 1.161 + 1.162 +/* --Private-Functions-------------------------------------------- */ 1.163 + 1.164 +/* 1.165 + * FUNCTION: pkix_SignatureChecker_Check 1.166 + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) 1.167 + */ 1.168 +PKIX_Error * 1.169 +pkix_SignatureChecker_Check( 1.170 + PKIX_CertChainChecker *checker, 1.171 + PKIX_PL_Cert *cert, 1.172 + PKIX_List *unresolvedCriticalExtensions, 1.173 + void **pNBIOContext, 1.174 + void *plContext) 1.175 +{ 1.176 + pkix_SignatureCheckerState *state = NULL; 1.177 + PKIX_PL_PublicKey *prevPubKey = NULL; 1.178 + PKIX_PL_PublicKey *currPubKey = NULL; 1.179 + PKIX_PL_PublicKey *newPubKey = NULL; 1.180 + PKIX_PL_PublicKey *pKey = NULL; 1.181 + PKIX_PL_CertBasicConstraints *basicConstraints = NULL; 1.182 + PKIX_Error *checkKeyUsageFail = NULL; 1.183 + PKIX_Error *verifyFail = NULL; 1.184 + PKIX_Boolean certVerified = PKIX_FALSE; 1.185 + 1.186 + PKIX_ENTER(CERTCHAINCHECKER, "pkix_SignatureChecker_Check"); 1.187 + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); 1.188 + 1.189 + *pNBIOContext = NULL; /* we never block on pending I/O */ 1.190 + 1.191 + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState 1.192 + (checker, (PKIX_PL_Object **)&state, plContext), 1.193 + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); 1.194 + 1.195 + (state->certsRemaining)--; 1.196 + 1.197 + PKIX_INCREF(state->prevPublicKey); 1.198 + prevPubKey = state->prevPublicKey; 1.199 + 1.200 + /* 1.201 + * Previous Cert doesn't have CertSign bit on for signature 1.202 + * verification and it is not a self-issued Cert so there is no 1.203 + * old key saved. This is considered error. 1.204 + */ 1.205 + if (state->prevCertCertSign == PKIX_FALSE && 1.206 + state->prevPublicKeyList == NULL) { 1.207 + PKIX_ERROR(PKIX_KEYUSAGEKEYCERTSIGNBITNOTON); 1.208 + } 1.209 + 1.210 + /* Previous Cert is valid for signature verification, try it first */ 1.211 + if (state->prevCertCertSign == PKIX_TRUE) { 1.212 + verifyFail = PKIX_PL_Cert_VerifySignature 1.213 + (cert, prevPubKey, plContext); 1.214 + if (verifyFail == NULL) { 1.215 + certVerified = PKIX_TRUE; 1.216 + } else { 1.217 + certVerified = PKIX_FALSE; 1.218 + } 1.219 + } 1.220 + 1.221 +#ifdef NIST_TEST_4_5_4_AND_4_5_6 1.222 + 1.223 + /* 1.224 + * Following codes under this compiler flag is implemented for 1.225 + * special cases of NIST tests 4.5.4 and 4.5.6. We are not sure 1.226 + * we should handle these two tests as what is implemented so the 1.227 + * codes are commented out, and the tests fails (for now). 1.228 + * For Cert chain validation, our assumption is all the Certs on 1.229 + * the chain are using its previous Cert's public key to decode 1.230 + * its current key. But for thses two tests, keys are used not 1.231 + * in this precedent order, we can either 1.232 + * 1) Use what is implemented here: take in what Cert order NIST 1.233 + * specified and for continuous self-issued Certs, stacking up 1.234 + * their keys and tries all of them in FILO order. 1.235 + * But this method breaks the idea of chain key presdency. 1.236 + * 2) Use Build Chain facility: we will specify the valid Certs 1.237 + * order (means key precedency is kept) and count on Build Chain 1.238 + * to get the Certs that can fill for the needed keys. This may have 1.239 + * performance impact. 1.240 + * 3) Fetch Certs from CertStore: we will specifiy the valid Certs 1.241 + * order and use CertSelector on SubjectName to get a list of 1.242 + * candidates Certs to fill in for the needed keys. 1.243 + * Anyhow, the codes are kept around just in case we want to use 1.244 + * solution one... 1.245 + */ 1.246 + 1.247 + /* If failed and previous key is self-issued, try its old key(s) */ 1.248 + if (certVerified == PKIX_FALSE && state->prevPublicKeyList != NULL) { 1.249 + 1.250 + /* Verify from keys on the list */ 1.251 + PKIX_CHECK(PKIX_List_GetLength 1.252 + (state->prevPublicKeyList, &numKeys, plContext), 1.253 + PKIX_LISTGETLENGTHFAILED); 1.254 + 1.255 + for (i = numKeys - 1; i >= 0; i--) { 1.256 + 1.257 + PKIX_CHECK(PKIX_List_GetItem 1.258 + (state->prevPublicKeyList, 1.259 + i, 1.260 + (PKIX_PL_Object **) &pKey, 1.261 + plContext), 1.262 + PKIX_LISTGETITEMFAILED); 1.263 + 1.264 + PKIX_DECREF(verifyFail); 1.265 + verifyFail = PKIX_PL_Cert_VerifySignature 1.266 + (cert, pKey, plContext); 1.267 + 1.268 + if (verifyFail == NULL) { 1.269 + certVerified = PKIX_TRUE; 1.270 + break; 1.271 + } else { 1.272 + certVerified = PKIX_FALSE; 1.273 + } 1.274 + 1.275 + PKIX_DECREF(pKey); 1.276 + } 1.277 + } 1.278 +#endif 1.279 + 1.280 + if (certVerified == PKIX_FALSE) { 1.281 + pkixErrorResult = verifyFail; 1.282 + verifyFail = NULL; 1.283 + PKIX_ERROR(PKIX_VALIDATIONFAILEDCERTSIGNATURECHECKING); 1.284 + } 1.285 + 1.286 +#ifdef NIST_TEST_4_5_4_AND_4_5_6 1.287 + /* 1.288 + * Check if Cert is self-issued. If so, the old key(s) is saved, in 1.289 + * conjunction to the new key, for verifying CERT validity later. 1.290 + */ 1.291 + PKIX_CHECK(pkix_IsCertSelfIssued(cert, &selfIssued, plContext), 1.292 + PKIX_ISCERTSELFISSUEFAILED); 1.293 + 1.294 + /* 1.295 + * Check if Cert is self-issued. If so, the public key of the Cert 1.296 + * that issues this Cert (old key) can be used together with this 1.297 + * current key (new key) for key verification. If there are multiple 1.298 + * self-issued certs, keys of those Certs (old keys) can also be used 1.299 + * for key verification. Old key(s) is saved in a list (PrevPublickKey- 1.300 + * List) and cleared when a Cert is no longer self-issued. PrevPublic- 1.301 + * Key keep key of the previous Cert. 1.302 + */ 1.303 + if (selfIssued == PKIX_TRUE) { 1.304 + 1.305 + /* Make sure previous Cert is valid for signature verification */ 1.306 + if (state->prevCertCertSign == PKIX_TRUE) { 1.307 + 1.308 + if (state->prevPublicKeyList == NULL) { 1.309 + 1.310 + PKIX_CHECK(PKIX_List_Create 1.311 + (&state->prevPublicKeyList, plContext), 1.312 + PKIX_LISTCREATEFALIED); 1.313 + 1.314 + } 1.315 + 1.316 + PKIX_CHECK(PKIX_List_AppendItem 1.317 + (state->prevPublicKeyList, 1.318 + (PKIX_PL_Object *) state->prevPublicKey, 1.319 + plContext), 1.320 + PKIX_LISTAPPENDITEMFAILED); 1.321 + } 1.322 + 1.323 + } else { 1.324 + /* Not self-issued Cert any more, clear old key(s) saved */ 1.325 + PKIX_DECREF(state->prevPublicKeyList); 1.326 + } 1.327 +#endif 1.328 + 1.329 + /* Save current key as prevPublicKey */ 1.330 + PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey 1.331 + (cert, &currPubKey, plContext), 1.332 + PKIX_CERTGETSUBJECTPUBLICKEYFAILED); 1.333 + 1.334 + PKIX_CHECK(PKIX_PL_PublicKey_MakeInheritedDSAPublicKey 1.335 + (currPubKey, prevPubKey, &newPubKey, plContext), 1.336 + PKIX_PUBLICKEYMAKEINHERITEDDSAPUBLICKEYFAILED); 1.337 + 1.338 + if (newPubKey == NULL){ 1.339 + PKIX_INCREF(currPubKey); 1.340 + newPubKey = currPubKey; 1.341 + } 1.342 + 1.343 + PKIX_INCREF(newPubKey); 1.344 + PKIX_DECREF(state->prevPublicKey); 1.345 + 1.346 + state->prevPublicKey = newPubKey; 1.347 + 1.348 + /* Save this Cert key usage CertSign bit */ 1.349 + if (state->certsRemaining != 0) { 1.350 + checkKeyUsageFail = PKIX_PL_Cert_VerifyKeyUsage 1.351 + (cert, PKIX_KEY_CERT_SIGN, plContext); 1.352 + 1.353 + state->prevCertCertSign = (checkKeyUsageFail == NULL)? 1.354 + PKIX_TRUE:PKIX_FALSE; 1.355 + 1.356 + PKIX_DECREF(checkKeyUsageFail); 1.357 + } 1.358 + 1.359 + /* Remove Key Usage Extension OID from list */ 1.360 + if (unresolvedCriticalExtensions != NULL) { 1.361 + 1.362 + PKIX_CHECK(pkix_List_Remove 1.363 + (unresolvedCriticalExtensions, 1.364 + (PKIX_PL_Object *) state->keyUsageOID, 1.365 + plContext), 1.366 + PKIX_LISTREMOVEFAILED); 1.367 + } 1.368 + 1.369 + PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState 1.370 + (checker, (PKIX_PL_Object *)state, plContext), 1.371 + PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); 1.372 + 1.373 +cleanup: 1.374 + 1.375 + PKIX_DECREF(state); 1.376 + PKIX_DECREF(pKey); 1.377 + PKIX_DECREF(prevPubKey); 1.378 + PKIX_DECREF(currPubKey); 1.379 + PKIX_DECREF(newPubKey); 1.380 + PKIX_DECREF(basicConstraints); 1.381 + PKIX_DECREF(verifyFail); 1.382 + PKIX_DECREF(checkKeyUsageFail); 1.383 + 1.384 + PKIX_RETURN(CERTCHAINCHECKER); 1.385 + 1.386 +} 1.387 + 1.388 +/* 1.389 + * FUNCTION: pkix_SignatureChecker_Initialize 1.390 + * DESCRIPTION: 1.391 + * 1.392 + * Creates a new CertChainChecker and stores it at "pChecker", where it will 1.393 + * be used by pkix_SignatureChecker_Check to check that the public key in 1.394 + * the checker's state is able to successfully validate the certificate's 1.395 + * signature. The PublicKey pointed to by "trustedPubKey" is used to 1.396 + * initialize the checker's state. 1.397 + * 1.398 + * PARAMETERS: 1.399 + * "trustedPubKey" 1.400 + * Address of PublicKey representing the trusted public key used to 1.401 + * initialize the state of this checker. Must be non-NULL. 1.402 + * "certsRemaining" 1.403 + * Number of certificates remaining in the chain. 1.404 + * "pChecker" 1.405 + * Address where object pointer will be stored. Must be non-NULL. 1.406 + * "plContext" 1.407 + * Platform-specific context pointer. 1.408 + * THREAD SAFETY: 1.409 + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 1.410 + * RETURNS: 1.411 + * Returns NULL if the function succeeds. 1.412 + * Returns a CertChainChecker Error if the function fails in a non-fatal way. 1.413 + * Returns a Fatal Error if the function fails in an unrecoverable way. 1.414 + */ 1.415 +PKIX_Error * 1.416 +pkix_SignatureChecker_Initialize( 1.417 + PKIX_PL_PublicKey *trustedPubKey, 1.418 + PKIX_UInt32 certsRemaining, 1.419 + PKIX_CertChainChecker **pChecker, 1.420 + void *plContext) 1.421 +{ 1.422 + pkix_SignatureCheckerState* state = NULL; 1.423 + PKIX_ENTER(CERTCHAINCHECKER, "PKIX_SignatureChecker_Initialize"); 1.424 + PKIX_NULLCHECK_TWO(pChecker, trustedPubKey); 1.425 + 1.426 + PKIX_CHECK(pkix_SignatureCheckerState_Create 1.427 + (trustedPubKey, certsRemaining, &state, plContext), 1.428 + PKIX_SIGNATURECHECKERSTATECREATEFAILED); 1.429 + 1.430 + PKIX_CHECK(PKIX_CertChainChecker_Create 1.431 + (pkix_SignatureChecker_Check, 1.432 + PKIX_FALSE, 1.433 + PKIX_FALSE, 1.434 + NULL, 1.435 + (PKIX_PL_Object *) state, 1.436 + pChecker, 1.437 + plContext), 1.438 + PKIX_CERTCHAINCHECKERCREATEFAILED); 1.439 + 1.440 +cleanup: 1.441 + 1.442 + PKIX_DECREF(state); 1.443 + 1.444 + PKIX_RETURN(CERTCHAINCHECKER); 1.445 + 1.446 +}