| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 #include "nspr.h" | |
| 5 #include "secerr.h" | |
| 6 #include "secport.h" | |
| 7 #include "seccomon.h" | |
| 8 #include "secoid.h" | |
| 9 #include "genname.h" | |
| 10 #include "keyhi.h" | |
| 11 #include "cert.h" | |
| 12 #include "certdb.h" | |
| 13 #include "certi.h" | |
| 14 #include "cryptohi.h" | |
| 15 #ifndef NSS_DISABLE_LIBPKIX | |
| 16 #include "pkix.h" | |
| 17 /*#include "pkix_sample_modules.h" */ | |
| 18 #include "pkix_pl_cert.h" | |
| 19 #endif /* NSS_DISABLE_LIBPKIX */ | |
| 20 | |
| 21 #include "nsspki.h" | |
| 22 #include "pkitm.h" | |
| 23 #include "pkim.h" | |
| 24 #include "pki3hack.h" | |
| 25 #include "base.h" | |
| 26 #include "keyhi.h" | |
| 27 | |
| 28 #ifdef NSS_DISABLE_LIBPKIX | |
| 29 SECStatus | |
| 30 cert_VerifyCertChainPkix( | |
| 31 CERTCertificate *cert, | |
| 32 PRBool checkSig, | |
| 33 SECCertUsage requiredUsage, | |
| 34 PRTime time, | |
| 35 void *wincx, | |
| 36 CERTVerifyLog *log, | |
| 37 PRBool *pSigerror, | |
| 38 PRBool *pRevoked) | |
| 39 { | |
| 40 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
| 41 return SECFailure; | |
| 42 } | |
| 43 | |
| 44 SECStatus | |
| 45 CERT_SetUsePKIXForValidation(PRBool enable) | |
| 46 { | |
| 47 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
| 48 return SECFailure; | |
| 49 } | |
| 50 | |
| 51 PRBool | |
| 52 CERT_GetUsePKIXForValidation() | |
| 53 { | |
| 54 return PR_FALSE; | |
| 55 } | |
| 56 | |
| 57 SECStatus CERT_PKIXVerifyCert( | |
| 58 CERTCertificate *cert, | |
| 59 SECCertificateUsage usages, | |
| 60 CERTValInParam *paramsIn, | |
| 61 CERTValOutParam *paramsOut, | |
| 62 void *wincx) | |
| 63 { | |
| 64 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
| 65 return SECFailure; | |
| 66 } | |
| 67 #endif /* NSS_DISABLE_LIBPKIX */ | |
| 68 | |
| 69 /* | |
| 70 * Check the validity times of a certificate | |
| 71 */ | |
| 72 SECStatus | |
| 73 CERT_CertTimesValid(CERTCertificate *c) | |
| 74 { | |
| 75 SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE); | |
| 76 return (valid == secCertTimeValid) ? SECSuccess : SECFailure; | |
| 77 } | |
| 78 | |
| 79 SECStatus | |
| 80 checkKeyParams(const SECAlgorithmID *sigAlgorithm, const SECKEYPublicKey *key) | |
| 81 { | |
| 82 SECStatus rv; | |
| 83 SECOidTag sigAlg; | |
| 84 SECOidTag curve; | |
| 85 PRUint32 policyFlags = 0; | |
| 86 PRInt32 minLen, len; | |
| 87 | |
| 88 sigAlg = SECOID_GetAlgorithmTag(sigAlgorithm); | |
| 89 | |
| 90 switch (sigAlg) { | |
| 91 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: | |
| 92 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: | |
| 93 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: | |
| 94 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: | |
| 95 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: | |
| 96 if (key->keyType != ecKey) { | |
| 97 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 98 return SECFailure; | |
| 99 } | |
| 100 | |
| 101 curve = SECKEY_GetECCOid(&key->u.ec.DEREncodedParams); | |
| 102 if (curve != 0) { | |
| 103 if (NSS_GetAlgorithmPolicy(curve, &policyFlags) == SECFailure || | |
| 104 !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) { | |
| 105 PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); | |
| 106 return SECFailure; | |
| 107 } else { | |
| 108 return SECSuccess; | |
| 109 } | |
| 110 } else { | |
| 111 PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| 112 return SECFailure; | |
| 113 } | |
| 114 return SECSuccess; | |
| 115 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | |
| 116 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: | |
| 117 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: | |
| 118 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: | |
| 119 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: | |
| 120 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: | |
| 121 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: | |
| 122 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: | |
| 123 if (key->keyType != rsaKey && key->keyType != rsaPssKey) { | |
| 124 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 125 return SECFailure; | |
| 126 } | |
| 127 | |
| 128 len = 8 * key->u.rsa.modulus.len; | |
| 129 | |
| 130 rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minLen); | |
| 131 if (rv != SECSuccess) { | |
| 132 return SECFailure; | |
| 133 } | |
| 134 | |
| 135 if (len < minLen) { | |
| 136 return SECFailure; | |
| 137 } | |
| 138 | |
| 139 return SECSuccess; | |
| 140 case SEC_OID_ANSIX9_DSA_SIGNATURE: | |
| 141 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
| 142 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
| 143 case SEC_OID_SDN702_DSA_SIGNATURE: | |
| 144 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: | |
| 145 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: | |
| 146 if (key->keyType != dsaKey) { | |
| 147 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 148 return SECFailure; | |
| 149 } | |
| 150 | |
| 151 len = 8 * key->u.dsa.params.prime.len; | |
| 152 | |
| 153 rv = NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minLen); | |
| 154 if (rv != SECSuccess) { | |
| 155 return SECFailure; | |
| 156 } | |
| 157 | |
| 158 if (len < minLen) { | |
| 159 return SECFailure; | |
| 160 } | |
| 161 | |
| 162 return SECSuccess; | |
| 163 default: | |
| 164 return SECSuccess; | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 /* | |
| 169 * verify the signature of a signed data object with the given DER publickey | |
| 170 */ | |
| 171 SECStatus | |
| 172 CERT_VerifySignedDataWithPublicKey(const CERTSignedData *sd, | |
| 173 SECKEYPublicKey *pubKey, | |
| 174 void *wincx) | |
| 175 { | |
| 176 SECStatus rv; | |
| 177 SECItem sig; | |
| 178 SECOidTag hashAlg = SEC_OID_UNKNOWN; | |
| 179 | |
| 180 if (!pubKey || !sd) { | |
| 181 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); | |
| 182 return SECFailure; | |
| 183 } | |
| 184 /* check the signature */ | |
| 185 sig = sd->signature; | |
| 186 /* convert sig->len from bit counts to byte count. */ | |
| 187 DER_ConvertBitString(&sig); | |
| 188 | |
| 189 rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, | |
| 190 &sig, &sd->signatureAlgorithm, &hashAlg,
wincx); | |
| 191 if (rv == SECSuccess) { | |
| 192 /* Are we honoring signatures for this algorithm? */ | |
| 193 PRUint32 policyFlags = 0; | |
| 194 rv = checkKeyParams(&sd->signatureAlgorithm, pubKey); | |
| 195 if (rv != SECSuccess) { | |
| 196 PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); | |
| 197 return SECFailure; | |
| 198 } | |
| 199 | |
| 200 rv = NSS_GetAlgorithmPolicy(hashAlg, &policyFlags); | |
| 201 if (rv == SECSuccess && | |
| 202 !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) { | |
| 203 PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); | |
| 204 return SECFailure; | |
| 205 } | |
| 206 } | |
| 207 return rv; | |
| 208 } | |
| 209 | |
| 210 /* | |
| 211 * verify the signature of a signed data object with the given DER publickey | |
| 212 */ | |
| 213 SECStatus | |
| 214 CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd, | |
| 215 CERTSubjectPublicKeyInfo *pubKeyInfo, | |
| 216 void *wincx) | |
| 217 { | |
| 218 SECKEYPublicKey *pubKey; | |
| 219 SECStatus rv = SECFailure; | |
| 220 | |
| 221 /* get cert's public key */ | |
| 222 pubKey = SECKEY_ExtractPublicKey(pubKeyInfo); | |
| 223 if (pubKey) { | |
| 224 rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); | |
| 225 SECKEY_DestroyPublicKey(pubKey); | |
| 226 } | |
| 227 return rv; | |
| 228 } | |
| 229 | |
| 230 /* | |
| 231 * verify the signature of a signed data object with the given certificate | |
| 232 */ | |
| 233 SECStatus | |
| 234 CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert, | |
| 235 PRTime t, void *wincx) | |
| 236 { | |
| 237 SECKEYPublicKey *pubKey = 0; | |
| 238 SECStatus rv = SECFailure; | |
| 239 SECCertTimeValidity validity; | |
| 240 | |
| 241 /* check the certificate's validity */ | |
| 242 validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE); | |
| 243 if (validity != secCertTimeValid) { | |
| 244 return rv; | |
| 245 } | |
| 246 | |
| 247 /* get cert's public key */ | |
| 248 pubKey = CERT_ExtractPublicKey(cert); | |
| 249 if (pubKey) { | |
| 250 rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); | |
| 251 SECKEY_DestroyPublicKey(pubKey); | |
| 252 } | |
| 253 return rv; | |
| 254 } | |
| 255 | |
| 256 SECStatus | |
| 257 SEC_CheckCRL(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 258 CERTCertificate *caCert, PRTime t, void *wincx) | |
| 259 { | |
| 260 return CERT_CheckCRL(cert, caCert, NULL, t, wincx); | |
| 261 } | |
| 262 | |
| 263 /* | |
| 264 * Find the issuer of a cert. Use the authorityKeyID if it exists. | |
| 265 */ | |
| 266 CERTCertificate * | |
| 267 CERT_FindCertIssuer(CERTCertificate *cert, PRTime validTime, SECCertUsage usage) | |
| 268 { | |
| 269 NSSCertificate *me; | |
| 270 NSSTime *nssTime; | |
| 271 NSSTrustDomain *td; | |
| 272 NSSCryptoContext *cc; | |
| 273 NSSCertificate *chain[3]; | |
| 274 NSSUsage nssUsage; | |
| 275 PRStatus status; | |
| 276 | |
| 277 me = STAN_GetNSSCertificate(cert); | |
| 278 if (!me) { | |
| 279 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 280 return NULL; | |
| 281 } | |
| 282 nssTime = NSSTime_SetPRTime(NULL, validTime); | |
| 283 nssUsage.anyUsage = PR_FALSE; | |
| 284 nssUsage.nss3usage = usage; | |
| 285 nssUsage.nss3lookingForCA = PR_TRUE; | |
| 286 memset(chain, 0, 3 * sizeof(NSSCertificate *)); | |
| 287 td = STAN_GetDefaultTrustDomain(); | |
| 288 cc = STAN_GetDefaultCryptoContext(); | |
| 289 (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL, | |
| 290 chain, 2, NULL, &status, td, cc); | |
| 291 nss_ZFreeIf(nssTime); | |
| 292 if (status == PR_SUCCESS) { | |
| 293 PORT_Assert(me == chain[0]); | |
| 294 /* if it's a root, the chain will only have one cert */ | |
| 295 if (!chain[1]) { | |
| 296 /* already has a reference from the call to BuildChain */ | |
| 297 return cert; | |
| 298 } | |
| 299 NSSCertificate_Destroy(chain[0]); /* the first cert in the chain
*/ | |
| 300 return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */ | |
| 301 } | |
| 302 if (chain[0]) { | |
| 303 PORT_Assert(me == chain[0]); | |
| 304 NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ | |
| 305 } | |
| 306 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); | |
| 307 return NULL; | |
| 308 } | |
| 309 | |
| 310 /* | |
| 311 * return required trust flags for various cert usages for CAs | |
| 312 */ | |
| 313 SECStatus | |
| 314 CERT_TrustFlagsForCACertUsage(SECCertUsage usage, | |
| 315 unsigned int *retFlags, | |
| 316 SECTrustType *retTrustType) | |
| 317 { | |
| 318 unsigned int requiredFlags; | |
| 319 SECTrustType trustType; | |
| 320 | |
| 321 switch (usage) { | |
| 322 case certUsageSSLClient: | |
| 323 requiredFlags = CERTDB_TRUSTED_CLIENT_CA; | |
| 324 trustType = trustSSL; | |
| 325 break; | |
| 326 case certUsageSSLServer: | |
| 327 case certUsageSSLCA: | |
| 328 requiredFlags = CERTDB_TRUSTED_CA; | |
| 329 trustType = trustSSL; | |
| 330 break; | |
| 331 case certUsageSSLServerWithStepUp: | |
| 332 requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA; | |
| 333 trustType = trustSSL; | |
| 334 break; | |
| 335 case certUsageEmailSigner: | |
| 336 case certUsageEmailRecipient: | |
| 337 requiredFlags = CERTDB_TRUSTED_CA; | |
| 338 trustType = trustEmail; | |
| 339 break; | |
| 340 case certUsageObjectSigner: | |
| 341 requiredFlags = CERTDB_TRUSTED_CA; | |
| 342 trustType = trustObjectSigning; | |
| 343 break; | |
| 344 case certUsageVerifyCA: | |
| 345 case certUsageAnyCA: | |
| 346 case certUsageStatusResponder: | |
| 347 requiredFlags = CERTDB_TRUSTED_CA; | |
| 348 trustType = trustTypeNone; | |
| 349 break; | |
| 350 default: | |
| 351 PORT_Assert(0); | |
| 352 goto loser; | |
| 353 } | |
| 354 if (retFlags != NULL) { | |
| 355 *retFlags = requiredFlags; | |
| 356 } | |
| 357 if (retTrustType != NULL) { | |
| 358 *retTrustType = trustType; | |
| 359 } | |
| 360 | |
| 361 return (SECSuccess); | |
| 362 loser: | |
| 363 return (SECFailure); | |
| 364 } | |
| 365 | |
| 366 void | |
| 367 cert_AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, long error, | |
| 368 unsigned int depth, void *arg) | |
| 369 { | |
| 370 CERTVerifyLogNode *node, *tnode; | |
| 371 | |
| 372 PORT_Assert(log != NULL); | |
| 373 | |
| 374 node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena, | |
| 375 sizeof(CERTVerifyLogNode)); | |
| 376 if (node != NULL) { | |
| 377 node->cert = CERT_DupCertificate(cert); | |
| 378 node->error = error; | |
| 379 node->depth = depth; | |
| 380 node->arg = arg; | |
| 381 | |
| 382 if (log->tail == NULL) { | |
| 383 /* empty list */ | |
| 384 log->head = log->tail = node; | |
| 385 node->prev = NULL; | |
| 386 node->next = NULL; | |
| 387 } else if (depth >= log->tail->depth) { | |
| 388 /* add to tail */ | |
| 389 node->prev = log->tail; | |
| 390 log->tail->next = node; | |
| 391 log->tail = node; | |
| 392 node->next = NULL; | |
| 393 } else if (depth < log->head->depth) { | |
| 394 /* add at head */ | |
| 395 node->prev = NULL; | |
| 396 node->next = log->head; | |
| 397 log->head->prev = node; | |
| 398 log->head = node; | |
| 399 } else { | |
| 400 /* add in middle */ | |
| 401 tnode = log->tail; | |
| 402 while (tnode != NULL) { | |
| 403 if (depth >= tnode->depth) { | |
| 404 /* insert after tnode */ | |
| 405 node->prev = tnode; | |
| 406 node->next = tnode->next; | |
| 407 tnode->next->prev = node; | |
| 408 tnode->next = node; | |
| 409 break; | |
| 410 } | |
| 411 | |
| 412 tnode = tnode->prev; | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 log->count++; | |
| 417 } | |
| 418 return; | |
| 419 } | |
| 420 | |
| 421 #define EXIT_IF_NOT_LOGGING(log) \ | |
| 422 if (log == NULL) { \ | |
| 423 goto loser; \ | |
| 424 } | |
| 425 | |
| 426 #define LOG_ERROR_OR_EXIT(log, cert, depth, arg) \ | |
| 427 if (log != NULL) { \ | |
| 428 cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \ | |
| 429 (void *)(PRWord)arg); \ | |
| 430 } else { \ | |
| 431 goto loser; \ | |
| 432 } | |
| 433 | |
| 434 #define LOG_ERROR(log, cert, depth, arg) \ | |
| 435 if (log != NULL) { \ | |
| 436 cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \ | |
| 437 (void *)(PRWord)arg); \ | |
| 438 } | |
| 439 | |
| 440 static SECStatus | |
| 441 cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 442 PRBool checkSig, PRBool *sigerror, | |
| 443 SECCertUsage certUsage, PRTime t, void *wincx, | |
| 444 CERTVerifyLog *log, PRBool *revoked) | |
| 445 { | |
| 446 SECTrustType trustType; | |
| 447 CERTBasicConstraints basicConstraint; | |
| 448 CERTCertificate *issuerCert = NULL; | |
| 449 CERTCertificate *subjectCert = NULL; | |
| 450 CERTCertificate *badCert = NULL; | |
| 451 PRBool isca; | |
| 452 SECStatus rv; | |
| 453 SECStatus rvFinal = SECSuccess; | |
| 454 int count; | |
| 455 int currentPathLen = 0; | |
| 456 int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; | |
| 457 unsigned int caCertType; | |
| 458 unsigned int requiredCAKeyUsage; | |
| 459 unsigned int requiredFlags; | |
| 460 PLArenaPool *arena = NULL; | |
| 461 CERTGeneralName *namesList = NULL; | |
| 462 CERTCertificate **certsList = NULL; | |
| 463 int certsListLen = 16; | |
| 464 int namesCount = 0; | |
| 465 PRBool subjectCertIsSelfIssued; | |
| 466 CERTCertTrust issuerTrust; | |
| 467 | |
| 468 if (revoked) { | |
| 469 *revoked = PR_FALSE; | |
| 470 } | |
| 471 | |
| 472 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, | |
| 473 &requiredCAKeyUsage, | |
| 474 &caCertType) != | |
| 475 SECSuccess) { | |
| 476 PORT_Assert(0); | |
| 477 EXIT_IF_NOT_LOGGING(log); | |
| 478 requiredCAKeyUsage = 0; | |
| 479 caCertType = 0; | |
| 480 } | |
| 481 | |
| 482 switch (certUsage) { | |
| 483 case certUsageSSLClient: | |
| 484 case certUsageSSLServer: | |
| 485 case certUsageSSLCA: | |
| 486 case certUsageSSLServerWithStepUp: | |
| 487 case certUsageEmailSigner: | |
| 488 case certUsageEmailRecipient: | |
| 489 case certUsageObjectSigner: | |
| 490 case certUsageVerifyCA: | |
| 491 case certUsageAnyCA: | |
| 492 case certUsageStatusResponder: | |
| 493 if (CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, | |
| 494 &trustType) != SECSuccess) { | |
| 495 PORT_Assert(0); | |
| 496 EXIT_IF_NOT_LOGGING(log); | |
| 497 /* XXX continuing with requiredFlags = 0 seems wrong. It'll | |
| 498 * cause the following test to be true incorrectly: | |
| 499 * flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType); | |
| 500 * if (( flags & requiredFlags ) == requiredFlags) { | |
| 501 * rv = rvFinal; | |
| 502 * goto done; | |
| 503 * } | |
| 504 * There are three other instances of this problem. | |
| 505 */ | |
| 506 requiredFlags = 0; | |
| 507 trustType = trustSSL; | |
| 508 } | |
| 509 break; | |
| 510 default: | |
| 511 PORT_Assert(0); | |
| 512 EXIT_IF_NOT_LOGGING(log); | |
| 513 requiredFlags = 0; | |
| 514 trustType = trustSSL; /* This used to be 0, but we need something | |
| 515 * that matches the enumeration type. | |
| 516 */ | |
| 517 caCertType = 0; | |
| 518 } | |
| 519 | |
| 520 subjectCert = CERT_DupCertificate(cert); | |
| 521 if (subjectCert == NULL) { | |
| 522 goto loser; | |
| 523 } | |
| 524 | |
| 525 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 526 if (arena == NULL) { | |
| 527 goto loser; | |
| 528 } | |
| 529 | |
| 530 certsList = PORT_ZNewArray(CERTCertificate *, certsListLen); | |
| 531 if (certsList == NULL) | |
| 532 goto loser; | |
| 533 | |
| 534 /* RFC 3280 says that the name constraints will apply to the names | |
| 535 ** in the leaf (EE) cert, whether it is self issued or not, so | |
| 536 ** we pretend that it is not. | |
| 537 */ | |
| 538 subjectCertIsSelfIssued = PR_FALSE; | |
| 539 for (count = 0; count < CERT_MAX_CERT_CHAIN; count++) { | |
| 540 PRBool validCAOverride = PR_FALSE; | |
| 541 | |
| 542 /* Construct a list of names for the current and all previous | |
| 543 * certifcates (except leaf (EE) certs, root CAs, and self-issued | |
| 544 * intermediate CAs) to be verified against the name constraints | |
| 545 * extension of the issuer certificate. | |
| 546 */ | |
| 547 if (subjectCertIsSelfIssued == PR_FALSE) { | |
| 548 CERTGeneralName *subjectNameList; | |
| 549 int subjectNameListLen; | |
| 550 int i; | |
| 551 PRBool getSubjectCN = (!count && certUsage == certUsageSSLServer); | |
| 552 subjectNameList = | |
| 553 CERT_GetConstrainedCertificateNames(subjectCert, arena, | |
| 554 getSubjectCN); | |
| 555 if (!subjectNameList) | |
| 556 goto loser; | |
| 557 subjectNameListLen = CERT_GetNamesLength(subjectNameList); | |
| 558 if (!subjectNameListLen) | |
| 559 goto loser; | |
| 560 if (certsListLen <= namesCount + subjectNameListLen) { | |
| 561 CERTCertificate **tmpCertsList; | |
| 562 certsListLen = (namesCount + subjectNameListLen) * 2; | |
| 563 tmpCertsList = | |
| 564 (CERTCertificate **)PORT_Realloc(certsList, | |
| 565 certsListLen * | |
| 566 sizeof(CERTCertificate
*)); | |
| 567 if (tmpCertsList == NULL) { | |
| 568 goto loser; | |
| 569 } | |
| 570 certsList = tmpCertsList; | |
| 571 } | |
| 572 for (i = 0; i < subjectNameListLen; i++) { | |
| 573 certsList[namesCount + i] = subjectCert; | |
| 574 } | |
| 575 namesCount += subjectNameListLen; | |
| 576 namesList = cert_CombineNamesLists(namesList, subjectNameList); | |
| 577 } | |
| 578 | |
| 579 /* check if the cert has an unsupported critical extension */ | |
| 580 if (subjectCert->options.bits.hasUnsupportedCriticalExt) { | |
| 581 PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); | |
| 582 LOG_ERROR_OR_EXIT(log, subjectCert, count, 0); | |
| 583 } | |
| 584 | |
| 585 /* find the certificate of the issuer */ | |
| 586 issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage); | |
| 587 if (!issuerCert) { | |
| 588 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); | |
| 589 LOG_ERROR(log, subjectCert, count, 0); | |
| 590 goto loser; | |
| 591 } | |
| 592 | |
| 593 /* verify the signature on the cert */ | |
| 594 if (checkSig) { | |
| 595 rv = CERT_VerifySignedData(&subjectCert->signatureWrap, | |
| 596 issuerCert, t, wincx); | |
| 597 | |
| 598 if (rv != SECSuccess) { | |
| 599 if (sigerror) { | |
| 600 *sigerror = PR_TRUE; | |
| 601 } | |
| 602 if (PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE) { | |
| 603 PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE); | |
| 604 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, 0); | |
| 605 } else { | |
| 606 if (PORT_GetError() != | |
| 607 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) { | |
| 608 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 609 } | |
| 610 LOG_ERROR_OR_EXIT(log, subjectCert, count, 0); | |
| 611 } | |
| 612 } | |
| 613 } | |
| 614 | |
| 615 /* If the basicConstraint extension is included in an immediate CA | |
| 616 * certificate, make sure that the isCA flag is on. If the | |
| 617 * pathLenConstraint component exists, it must be greater than the | |
| 618 * number of CA certificates we have seen so far. If the extension | |
| 619 * is omitted, we will assume that this is a CA certificate with | |
| 620 * an unlimited pathLenConstraint (since it already passes the | |
| 621 * netscape-cert-type extension checking). | |
| 622 */ | |
| 623 | |
| 624 rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint); | |
| 625 if (rv != SECSuccess) { | |
| 626 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { | |
| 627 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, 0); | |
| 628 } | |
| 629 pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; | |
| 630 /* no basic constraints found, we aren't (yet) a CA. */ | |
| 631 isca = PR_FALSE; | |
| 632 } else { | |
| 633 if (basicConstraint.isCA == PR_FALSE) { | |
| 634 PORT_SetError(SEC_ERROR_CA_CERT_INVALID); | |
| 635 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, 0); | |
| 636 } | |
| 637 pathLengthLimit = basicConstraint.pathLenConstraint; | |
| 638 isca = PR_TRUE; | |
| 639 } | |
| 640 /* make sure that the path len constraint is properly set.*/ | |
| 641 if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) { | |
| 642 PORT_SetError(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); | |
| 643 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, pathLengthLimit); | |
| 644 } | |
| 645 | |
| 646 /* make sure that the entire chain is within the name space of the | |
| 647 * current issuer certificate. | |
| 648 */ | |
| 649 rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, | |
| 650 arena, &badCert); | |
| 651 if (rv != SECSuccess || badCert != NULL) { | |
| 652 PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE); | |
| 653 LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0); | |
| 654 goto loser; | |
| 655 } | |
| 656 | |
| 657 /* XXX - the error logging may need to go down into CRL stuff at some | |
| 658 * point | |
| 659 */ | |
| 660 /* check revoked list (issuer) */ | |
| 661 rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx); | |
| 662 if (rv == SECFailure) { | |
| 663 if (revoked) { | |
| 664 *revoked = PR_TRUE; | |
| 665 } | |
| 666 LOG_ERROR_OR_EXIT(log, subjectCert, count, 0); | |
| 667 } else if (rv == SECWouldBlock) { | |
| 668 /* We found something fishy, so we intend to issue an | |
| 669 * error to the user, but the user may wish to continue | |
| 670 * processing, in which case we better make sure nothing | |
| 671 * worse has happened... so keep cranking the loop */ | |
| 672 rvFinal = SECFailure; | |
| 673 if (revoked) { | |
| 674 *revoked = PR_TRUE; | |
| 675 } | |
| 676 LOG_ERROR(log, subjectCert, count, 0); | |
| 677 } | |
| 678 | |
| 679 if (CERT_GetCertTrust(issuerCert, &issuerTrust) == SECSuccess) { | |
| 680 /* we have some trust info, but this does NOT imply that this | |
| 681 * cert is actually trusted for any purpose. The cert may be | |
| 682 * explicitly UNtrusted. We won't know until we examine the | |
| 683 * trust bits. | |
| 684 */ | |
| 685 unsigned int flags; | |
| 686 | |
| 687 if (certUsage != certUsageAnyCA && | |
| 688 certUsage != certUsageStatusResponder) { | |
| 689 | |
| 690 /* | |
| 691 * XXX This choice of trustType seems arbitrary. | |
| 692 */ | |
| 693 if (certUsage == certUsageVerifyCA) { | |
| 694 if (subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) { | |
| 695 trustType = trustEmail; | |
| 696 } else if (subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA) { | |
| 697 trustType = trustSSL; | |
| 698 } else { | |
| 699 trustType = trustObjectSigning; | |
| 700 } | |
| 701 } | |
| 702 | |
| 703 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); | |
| 704 if ((flags & requiredFlags) == requiredFlags) { | |
| 705 /* we found a trusted one, so return */ | |
| 706 rv = rvFinal; | |
| 707 goto done; | |
| 708 } | |
| 709 if (flags & CERTDB_VALID_CA) { | |
| 710 validCAOverride = PR_TRUE; | |
| 711 } | |
| 712 /* is it explicitly distrusted? */ | |
| 713 if ((flags & CERTDB_TERMINAL_RECORD) && | |
| 714 ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0)) { | |
| 715 /* untrusted -- the cert is explicitly untrusted, not | |
| 716 * just that it doesn't chain to a trusted cert */ | |
| 717 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); | |
| 718 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, flags); | |
| 719 } | |
| 720 } else { | |
| 721 /* Check if we have any valid trust when cheching for | |
| 722 * certUsageAnyCA or certUsageStatusResponder. */ | |
| 723 for (trustType = trustSSL; trustType < trustTypeNone; | |
| 724 trustType++) { | |
| 725 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); | |
| 726 if ((flags & requiredFlags) == requiredFlags) { | |
| 727 rv = rvFinal; | |
| 728 goto done; | |
| 729 } | |
| 730 if (flags & CERTDB_VALID_CA) | |
| 731 validCAOverride = PR_TRUE; | |
| 732 } | |
| 733 /* We have 2 separate loops because we want any single trust | |
| 734 * bit to allow this usage to return trusted. Only if none of | |
| 735 * the trust bits are on do we check to see if the cert is | |
| 736 * untrusted */ | |
| 737 for (trustType = trustSSL; trustType < trustTypeNone; | |
| 738 trustType++) { | |
| 739 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); | |
| 740 /* is it explicitly distrusted? */ | |
| 741 if ((flags & CERTDB_TERMINAL_RECORD) && | |
| 742 ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0)) { | |
| 743 /* untrusted -- the cert is explicitly untrusted, not | |
| 744 * just that it doesn't chain to a trusted cert */ | |
| 745 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); | |
| 746 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, flags); | |
| 747 } | |
| 748 } | |
| 749 } | |
| 750 } | |
| 751 | |
| 752 if (!validCAOverride) { | |
| 753 /* | |
| 754 * Make sure that if this is an intermediate CA in the chain that | |
| 755 * it was given permission by its signer to be a CA. | |
| 756 */ | |
| 757 /* | |
| 758 * if basicConstraints says it is a ca, then we check the | |
| 759 * nsCertType. If the nsCertType has any CA bits set, then | |
| 760 * it must have the right one. | |
| 761 */ | |
| 762 if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) { | |
| 763 isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALS
E; | |
| 764 } | |
| 765 | |
| 766 if (!isca) { | |
| 767 PORT_SetError(SEC_ERROR_CA_CERT_INVALID); | |
| 768 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, 0); | |
| 769 } | |
| 770 | |
| 771 /* make sure key usage allows cert signing */ | |
| 772 if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess
) { | |
| 773 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); | |
| 774 LOG_ERROR_OR_EXIT(log, issuerCert, count + 1, requiredCAKeyUsage
); | |
| 775 } | |
| 776 } | |
| 777 | |
| 778 /* make sure that the issuer is not self signed. If it is, then | |
| 779 * stop here to prevent looping. | |
| 780 */ | |
| 781 if (issuerCert->isRoot) { | |
| 782 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); | |
| 783 LOG_ERROR(log, issuerCert, count + 1, 0); | |
| 784 goto loser; | |
| 785 } | |
| 786 /* The issuer cert will be the subject cert in the next loop. | |
| 787 * A cert is self-issued if its subject and issuer are equal and | |
| 788 * both are of non-zero length. | |
| 789 */ | |
| 790 subjectCertIsSelfIssued = (PRBool) | |
| 791 SECITEM_ItemsAreEqual(&issuerCert->derIssu
er, | |
| 792 &issuerCert->derSubj
ect) && | |
| 793 issuerCert->derSubject.len > | |
| 794 0; | |
| 795 if (subjectCertIsSelfIssued == PR_FALSE) { | |
| 796 /* RFC 3280 says only non-self-issued intermediate CA certs | |
| 797 * count in path length. | |
| 798 */ | |
| 799 ++currentPathLen; | |
| 800 } | |
| 801 | |
| 802 CERT_DestroyCertificate(subjectCert); | |
| 803 subjectCert = issuerCert; | |
| 804 issuerCert = NULL; | |
| 805 } | |
| 806 | |
| 807 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); | |
| 808 LOG_ERROR(log, subjectCert, count, 0); | |
| 809 loser: | |
| 810 rv = SECFailure; | |
| 811 done: | |
| 812 if (certsList != NULL) { | |
| 813 PORT_Free(certsList); | |
| 814 } | |
| 815 if (issuerCert) { | |
| 816 CERT_DestroyCertificate(issuerCert); | |
| 817 } | |
| 818 | |
| 819 if (subjectCert) { | |
| 820 CERT_DestroyCertificate(subjectCert); | |
| 821 } | |
| 822 | |
| 823 if (arena != NULL) { | |
| 824 PORT_FreeArena(arena, PR_FALSE); | |
| 825 } | |
| 826 return rv; | |
| 827 } | |
| 828 | |
| 829 SECStatus | |
| 830 cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 831 PRBool checkSig, PRBool *sigerror, | |
| 832 SECCertUsage certUsage, PRTime t, void *wincx, | |
| 833 CERTVerifyLog *log, PRBool *revoked) | |
| 834 { | |
| 835 if (CERT_GetUsePKIXForValidation()) { | |
| 836 return cert_VerifyCertChainPkix(cert, checkSig, certUsage, t, | |
| 837 wincx, log, sigerror, revoked); | |
| 838 } | |
| 839 return cert_VerifyCertChainOld(handle, cert, checkSig, sigerror, | |
| 840 certUsage, t, wincx, log, revoked); | |
| 841 } | |
| 842 | |
| 843 SECStatus | |
| 844 CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 845 PRBool checkSig, SECCertUsage certUsage, PRTime t, | |
| 846 void *wincx, CERTVerifyLog *log) | |
| 847 { | |
| 848 return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t, | |
| 849 wincx, log, NULL); | |
| 850 } | |
| 851 | |
| 852 /* | |
| 853 * verify that a CA can sign a certificate with the requested usage. | |
| 854 */ | |
| 855 SECStatus | |
| 856 CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 857 PRBool checkSig, SECCertUsage certUsage, PRTime t, | |
| 858 void *wincx, CERTVerifyLog *log) | |
| 859 { | |
| 860 SECTrustType trustType; | |
| 861 CERTBasicConstraints basicConstraint; | |
| 862 PRBool isca; | |
| 863 PRBool validCAOverride = PR_FALSE; | |
| 864 SECStatus rv; | |
| 865 SECStatus rvFinal = SECSuccess; | |
| 866 unsigned int flags; | |
| 867 unsigned int caCertType; | |
| 868 unsigned int requiredCAKeyUsage; | |
| 869 unsigned int requiredFlags; | |
| 870 CERTCertificate *issuerCert; | |
| 871 CERTCertTrust certTrust; | |
| 872 | |
| 873 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, | |
| 874 &requiredCAKeyUsage, | |
| 875 &caCertType) != SECSuccess) { | |
| 876 PORT_Assert(0); | |
| 877 EXIT_IF_NOT_LOGGING(log); | |
| 878 requiredCAKeyUsage = 0; | |
| 879 caCertType = 0; | |
| 880 } | |
| 881 | |
| 882 switch (certUsage) { | |
| 883 case certUsageSSLClient: | |
| 884 case certUsageSSLServer: | |
| 885 case certUsageSSLCA: | |
| 886 case certUsageSSLServerWithStepUp: | |
| 887 case certUsageEmailSigner: | |
| 888 case certUsageEmailRecipient: | |
| 889 case certUsageObjectSigner: | |
| 890 case certUsageVerifyCA: | |
| 891 case certUsageStatusResponder: | |
| 892 if (CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, | |
| 893 &trustType) != SECSuccess) { | |
| 894 PORT_Assert(0); | |
| 895 EXIT_IF_NOT_LOGGING(log); | |
| 896 requiredFlags = 0; | |
| 897 trustType = trustSSL; | |
| 898 } | |
| 899 break; | |
| 900 default: | |
| 901 PORT_Assert(0); | |
| 902 EXIT_IF_NOT_LOGGING(log); | |
| 903 requiredFlags = 0; | |
| 904 trustType = trustSSL; /* This used to be 0, but we need something | |
| 905 * that matches the enumeration type. | |
| 906 */ | |
| 907 caCertType = 0; | |
| 908 } | |
| 909 | |
| 910 /* If the basicConstraint extension is included in an intermmediate CA | |
| 911 * certificate, make sure that the isCA flag is on. If the | |
| 912 * pathLenConstraint component exists, it must be greater than the | |
| 913 * number of CA certificates we have seen so far. If the extension | |
| 914 * is omitted, we will assume that this is a CA certificate with | |
| 915 * an unlimited pathLenConstraint (since it already passes the | |
| 916 * netscape-cert-type extension checking). | |
| 917 */ | |
| 918 | |
| 919 rv = CERT_FindBasicConstraintExten(cert, &basicConstraint); | |
| 920 if (rv != SECSuccess) { | |
| 921 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { | |
| 922 LOG_ERROR_OR_EXIT(log, cert, 0, 0); | |
| 923 } | |
| 924 /* no basic constraints found, we aren't (yet) a CA. */ | |
| 925 isca = PR_FALSE; | |
| 926 } else { | |
| 927 if (basicConstraint.isCA == PR_FALSE) { | |
| 928 PORT_SetError(SEC_ERROR_CA_CERT_INVALID); | |
| 929 LOG_ERROR_OR_EXIT(log, cert, 0, 0); | |
| 930 } | |
| 931 | |
| 932 /* can't check path length if we don't know the previous path */ | |
| 933 isca = PR_TRUE; | |
| 934 } | |
| 935 | |
| 936 if (CERT_GetCertTrust(cert, &certTrust) == SECSuccess) { | |
| 937 /* we have some trust info, but this does NOT imply that this | |
| 938 * cert is actually trusted for any purpose. The cert may be | |
| 939 * explicitly UNtrusted. We won't know until we examine the | |
| 940 * trust bits. | |
| 941 */ | |
| 942 if (certUsage == certUsageStatusResponder) { | |
| 943 /* Check the special case of certUsageStatusResponder */ | |
| 944 issuerCert = CERT_FindCertIssuer(cert, t, certUsage); | |
| 945 if (issuerCert) { | |
| 946 if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx) != | |
| 947 SECSuccess) { | |
| 948 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | |
| 949 CERT_DestroyCertificate(issuerCert); | |
| 950 goto loser; | |
| 951 } | |
| 952 CERT_DestroyCertificate(issuerCert); | |
| 953 } | |
| 954 /* XXX We have NOT determined that this cert is trusted. | |
| 955 * For years, NSS has treated this as trusted, | |
| 956 * but it seems incorrect. | |
| 957 */ | |
| 958 rv = rvFinal; | |
| 959 goto done; | |
| 960 } | |
| 961 | |
| 962 /* | |
| 963 * check the trust params of the issuer | |
| 964 */ | |
| 965 flags = SEC_GET_TRUST_FLAGS(&certTrust, trustType); | |
| 966 if ((flags & requiredFlags) == requiredFlags) { | |
| 967 /* we found a trusted one, so return */ | |
| 968 rv = rvFinal; | |
| 969 goto done; | |
| 970 } | |
| 971 if (flags & CERTDB_VALID_CA) { | |
| 972 validCAOverride = PR_TRUE; | |
| 973 } | |
| 974 /* is it explicitly distrusted? */ | |
| 975 if ((flags & CERTDB_TERMINAL_RECORD) && | |
| 976 ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0)) { | |
| 977 /* untrusted -- the cert is explicitly untrusted, not | |
| 978 * just that it doesn't chain to a trusted cert */ | |
| 979 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); | |
| 980 LOG_ERROR_OR_EXIT(log, cert, 0, flags); | |
| 981 } | |
| 982 } | |
| 983 if (!validCAOverride) { | |
| 984 /* | |
| 985 * Make sure that if this is an intermediate CA in the chain that | |
| 986 * it was given permission by its signer to be a CA. | |
| 987 */ | |
| 988 /* | |
| 989 * if basicConstraints says it is a ca, then we check the | |
| 990 * nsCertType. If the nsCertType has any CA bits set, then | |
| 991 * it must have the right one. | |
| 992 */ | |
| 993 if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) { | |
| 994 isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; | |
| 995 } | |
| 996 | |
| 997 if (!isca) { | |
| 998 PORT_SetError(SEC_ERROR_CA_CERT_INVALID); | |
| 999 LOG_ERROR_OR_EXIT(log, cert, 0, 0); | |
| 1000 } | |
| 1001 | |
| 1002 /* make sure key usage allows cert signing */ | |
| 1003 if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) { | |
| 1004 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); | |
| 1005 LOG_ERROR_OR_EXIT(log, cert, 0, requiredCAKeyUsage); | |
| 1006 } | |
| 1007 } | |
| 1008 /* make sure that the issuer is not self signed. If it is, then | |
| 1009 * stop here to prevent looping. | |
| 1010 */ | |
| 1011 if (cert->isRoot) { | |
| 1012 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); | |
| 1013 LOG_ERROR(log, cert, 0, 0); | |
| 1014 goto loser; | |
| 1015 } | |
| 1016 | |
| 1017 return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, | |
| 1018 wincx, log); | |
| 1019 loser: | |
| 1020 rv = SECFailure; | |
| 1021 done: | |
| 1022 return rv; | |
| 1023 } | |
| 1024 | |
| 1025 #define NEXT_USAGE() \ | |
| 1026 { \ | |
| 1027 i *= 2; \ | |
| 1028 certUsage++; \ | |
| 1029 continue; \ | |
| 1030 } | |
| 1031 | |
| 1032 #define VALID_USAGE() \ | |
| 1033 { \ | |
| 1034 NEXT_USAGE(); \ | |
| 1035 } | |
| 1036 | |
| 1037 #define INVALID_USAGE() \ | |
| 1038 { \ | |
| 1039 if (returnedUsages) { \ | |
| 1040 *returnedUsages &= (~i); \ | |
| 1041 } \ | |
| 1042 if (PR_TRUE == requiredUsage) { \ | |
| 1043 valid = SECFailure; \ | |
| 1044 } \ | |
| 1045 NEXT_USAGE(); \ | |
| 1046 } | |
| 1047 | |
| 1048 /* | |
| 1049 * check the leaf cert against trust and usage. | |
| 1050 * returns success if the cert is not distrusted. If the cert is | |
| 1051 * trusted, then the trusted bool will be true. | |
| 1052 * returns failure if the cert is distrusted. If failure, flags | |
| 1053 * will return the flag bits that indicated distrust. | |
| 1054 */ | |
| 1055 SECStatus | |
| 1056 cert_CheckLeafTrust(CERTCertificate *cert, SECCertUsage certUsage, | |
| 1057 unsigned int *failedFlags, PRBool *trusted) | |
| 1058 { | |
| 1059 unsigned int flags; | |
| 1060 CERTCertTrust trust; | |
| 1061 | |
| 1062 *failedFlags = 0; | |
| 1063 *trusted = PR_FALSE; | |
| 1064 | |
| 1065 /* check trust flags to see if this cert is directly trusted */ | |
| 1066 if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { | |
| 1067 switch (certUsage) { | |
| 1068 case certUsageSSLClient: | |
| 1069 case certUsageSSLServer: | |
| 1070 flags = trust.sslFlags; | |
| 1071 | |
| 1072 /* is the cert directly trusted or not trusted ? */ | |
| 1073 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1074 * authoritative */ | |
| 1075 if (flags & CERTDB_TRUSTED) { /* trust this cert */ | |
| 1076 *trusted = PR_TRUE; | |
| 1077 return SECSuccess; | |
| 1078 } else { /* don't trust this cert */ | |
| 1079 *failedFlags = flags; | |
| 1080 return SECFailure; | |
| 1081 } | |
| 1082 } | |
| 1083 break; | |
| 1084 case certUsageSSLServerWithStepUp: | |
| 1085 /* XXX - step up certs can't be directly trusted, only distrust
*/ | |
| 1086 flags = trust.sslFlags; | |
| 1087 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1088 * authoritative */ | |
| 1089 if ((flags & CERTDB_TRUSTED) == 0) { | |
| 1090 /* don't trust this cert */ | |
| 1091 *failedFlags = flags; | |
| 1092 return SECFailure; | |
| 1093 } | |
| 1094 } | |
| 1095 break; | |
| 1096 case certUsageSSLCA: | |
| 1097 flags = trust.sslFlags; | |
| 1098 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1099 * authoritative */ | |
| 1100 if ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0) { | |
| 1101 /* don't trust this cert */ | |
| 1102 *failedFlags = flags; | |
| 1103 return SECFailure; | |
| 1104 } | |
| 1105 } | |
| 1106 break; | |
| 1107 case certUsageEmailSigner: | |
| 1108 case certUsageEmailRecipient: | |
| 1109 flags = trust.emailFlags; | |
| 1110 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1111 * authoritative */ | |
| 1112 if (flags & CERTDB_TRUSTED) { /* trust this cert */ | |
| 1113 *trusted = PR_TRUE; | |
| 1114 return SECSuccess; | |
| 1115 } else { /* don't trust this cert */ | |
| 1116 *failedFlags = flags; | |
| 1117 return SECFailure; | |
| 1118 } | |
| 1119 } | |
| 1120 | |
| 1121 break; | |
| 1122 case certUsageObjectSigner: | |
| 1123 flags = trust.objectSigningFlags; | |
| 1124 | |
| 1125 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1126 * authoritative */ | |
| 1127 if (flags & CERTDB_TRUSTED) { /* trust this cert */ | |
| 1128 *trusted = PR_TRUE; | |
| 1129 return SECSuccess; | |
| 1130 } else { /* don't trust this cert */ | |
| 1131 *failedFlags = flags; | |
| 1132 return SECFailure; | |
| 1133 } | |
| 1134 } | |
| 1135 break; | |
| 1136 case certUsageVerifyCA: | |
| 1137 case certUsageStatusResponder: | |
| 1138 flags = trust.sslFlags; | |
| 1139 /* is the cert directly trusted or not trusted ? */ | |
| 1140 if ((flags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) == | |
| 1141 (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) { | |
| 1142 *trusted = PR_TRUE; | |
| 1143 return SECSuccess; | |
| 1144 } | |
| 1145 flags = trust.emailFlags; | |
| 1146 /* is the cert directly trusted or not trusted ? */ | |
| 1147 if ((flags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) == | |
| 1148 (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) { | |
| 1149 *trusted = PR_TRUE; | |
| 1150 return SECSuccess; | |
| 1151 } | |
| 1152 flags = trust.objectSigningFlags; | |
| 1153 /* is the cert directly trusted or not trusted ? */ | |
| 1154 if ((flags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) == | |
| 1155 (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) { | |
| 1156 *trusted = PR_TRUE; | |
| 1157 return SECSuccess; | |
| 1158 } | |
| 1159 /* fall through to test distrust */ | |
| 1160 case certUsageAnyCA: | |
| 1161 case certUsageUserCertImport: | |
| 1162 /* do we distrust these certs explicitly */ | |
| 1163 flags = trust.sslFlags; | |
| 1164 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1165 * authoritative */ | |
| 1166 if ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0) { | |
| 1167 *failedFlags = flags; | |
| 1168 return SECFailure; | |
| 1169 } | |
| 1170 } | |
| 1171 flags = trust.emailFlags; | |
| 1172 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1173 * authoritative */ | |
| 1174 if ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0) { | |
| 1175 *failedFlags = flags; | |
| 1176 return SECFailure; | |
| 1177 } | |
| 1178 } | |
| 1179 /* fall through */ | |
| 1180 case certUsageProtectedObjectSigner: | |
| 1181 flags = trust.objectSigningFlags; | |
| 1182 if (flags & CERTDB_TERMINAL_RECORD) { /* the trust record is | |
| 1183 * authoritative */ | |
| 1184 if ((flags & (CERTDB_TRUSTED | CERTDB_TRUSTED_CA)) == 0) { | |
| 1185 *failedFlags = flags; | |
| 1186 return SECFailure; | |
| 1187 } | |
| 1188 } | |
| 1189 break; | |
| 1190 } | |
| 1191 } | |
| 1192 return SECSuccess; | |
| 1193 } | |
| 1194 | |
| 1195 /* | |
| 1196 * verify a certificate by checking if it's valid and that we | |
| 1197 * trust the issuer. | |
| 1198 * | |
| 1199 * certificateUsage contains a bitfield of all cert usages that are | |
| 1200 * required for verification to succeed | |
| 1201 * | |
| 1202 * a bitfield of cert usages is returned in *returnedUsages | |
| 1203 * if requiredUsages is non-zero, the returned bitmap is only | |
| 1204 * for those required usages, otherwise it is for all usages | |
| 1205 * | |
| 1206 */ | |
| 1207 SECStatus | |
| 1208 CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 1209 PRBool checkSig, SECCertificateUsage requiredUsages, PRTi
me t, | |
| 1210 void *wincx, CERTVerifyLog *log, SECCertificateUsage *ret
urnedUsages) | |
| 1211 { | |
| 1212 SECStatus rv; | |
| 1213 SECStatus valid; | |
| 1214 unsigned int requiredKeyUsage; | |
| 1215 unsigned int requiredCertType; | |
| 1216 unsigned int flags; | |
| 1217 unsigned int certType; | |
| 1218 PRBool allowOverride; | |
| 1219 SECCertTimeValidity validity; | |
| 1220 CERTStatusConfig *statusConfig; | |
| 1221 PRInt32 i; | |
| 1222 SECCertUsage certUsage = 0; | |
| 1223 PRBool checkedOCSP = PR_FALSE; | |
| 1224 PRBool checkAllUsages = PR_FALSE; | |
| 1225 PRBool revoked = PR_FALSE; | |
| 1226 PRBool sigerror = PR_FALSE; | |
| 1227 PRBool trusted = PR_FALSE; | |
| 1228 | |
| 1229 if (!requiredUsages) { | |
| 1230 /* there are no required usages, so the user probably wants to | |
| 1231 get status for all usages */ | |
| 1232 checkAllUsages = PR_TRUE; | |
| 1233 } | |
| 1234 | |
| 1235 if (returnedUsages) { | |
| 1236 *returnedUsages = 0; | |
| 1237 } else { | |
| 1238 /* we don't have a place to return status for all usages, | |
| 1239 so we can skip checks for usages that aren't required */ | |
| 1240 checkAllUsages = PR_FALSE; | |
| 1241 } | |
| 1242 valid = SECSuccess; /* start off assuming cert is valid */ | |
| 1243 | |
| 1244 /* make sure that the cert is valid at time t */ | |
| 1245 allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) || | |
| 1246 (requiredUsages & certificateUsageSSLServerWithStep
Up)); | |
| 1247 validity = CERT_CheckCertValidTimes(cert, t, allowOverride); | |
| 1248 if (validity != secCertTimeValid) { | |
| 1249 valid = SECFailure; | |
| 1250 LOG_ERROR_OR_EXIT(log, cert, 0, validity); | |
| 1251 } | |
| 1252 | |
| 1253 /* check key usage and netscape cert type */ | |
| 1254 cert_GetCertType(cert); | |
| 1255 certType = cert->nsCertType; | |
| 1256 | |
| 1257 for (i = 1; i <= certificateUsageHighest && | |
| 1258 (SECSuccess == valid || returnedUsages || log);) { | |
| 1259 PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE; | |
| 1260 if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) { | |
| 1261 NEXT_USAGE(); | |
| 1262 } | |
| 1263 if (returnedUsages) { | |
| 1264 *returnedUsages |= i; /* start off assuming this usage is valid */ | |
| 1265 } | |
| 1266 switch (certUsage) { | |
| 1267 case certUsageSSLClient: | |
| 1268 case certUsageSSLServer: | |
| 1269 case certUsageSSLServerWithStepUp: | |
| 1270 case certUsageSSLCA: | |
| 1271 case certUsageEmailSigner: | |
| 1272 case certUsageEmailRecipient: | |
| 1273 case certUsageObjectSigner: | |
| 1274 case certUsageStatusResponder: | |
| 1275 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, | |
| 1276 &requiredKeyUsage, | |
| 1277 &requiredCertType); | |
| 1278 if (rv != SECSuccess) { | |
| 1279 PORT_Assert(0); | |
| 1280 /* EXIT_IF_NOT_LOGGING(log); XXX ??? */ | |
| 1281 requiredKeyUsage = 0; | |
| 1282 requiredCertType = 0; | |
| 1283 INVALID_USAGE(); | |
| 1284 } | |
| 1285 break; | |
| 1286 | |
| 1287 case certUsageAnyCA: | |
| 1288 case certUsageProtectedObjectSigner: | |
| 1289 case certUsageUserCertImport: | |
| 1290 case certUsageVerifyCA: | |
| 1291 /* these usages cannot be verified */ | |
| 1292 NEXT_USAGE(); | |
| 1293 | |
| 1294 default: | |
| 1295 PORT_Assert(0); | |
| 1296 requiredKeyUsage = 0; | |
| 1297 requiredCertType = 0; | |
| 1298 INVALID_USAGE(); | |
| 1299 } | |
| 1300 if (CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess) { | |
| 1301 if (PR_TRUE == requiredUsage) { | |
| 1302 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); | |
| 1303 } | |
| 1304 LOG_ERROR(log, cert, 0, requiredKeyUsage); | |
| 1305 INVALID_USAGE(); | |
| 1306 } | |
| 1307 if (!(certType & requiredCertType)) { | |
| 1308 if (PR_TRUE == requiredUsage) { | |
| 1309 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); | |
| 1310 } | |
| 1311 LOG_ERROR(log, cert, 0, requiredCertType); | |
| 1312 INVALID_USAGE(); | |
| 1313 } | |
| 1314 | |
| 1315 rv = cert_CheckLeafTrust(cert, certUsage, &flags, &trusted); | |
| 1316 if (rv == SECFailure) { | |
| 1317 if (PR_TRUE == requiredUsage) { | |
| 1318 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); | |
| 1319 } | |
| 1320 LOG_ERROR(log, cert, 0, flags); | |
| 1321 INVALID_USAGE(); | |
| 1322 } else if (trusted) { | |
| 1323 VALID_USAGE(); | |
| 1324 } | |
| 1325 | |
| 1326 if (PR_TRUE == revoked || PR_TRUE == sigerror) { | |
| 1327 INVALID_USAGE(); | |
| 1328 } | |
| 1329 | |
| 1330 rv = cert_VerifyCertChain(handle, cert, | |
| 1331 checkSig, &sigerror, | |
| 1332 certUsage, t, wincx, log, | |
| 1333 &revoked); | |
| 1334 | |
| 1335 if (rv != SECSuccess) { | |
| 1336 /* EXIT_IF_NOT_LOGGING(log); XXX ???? */ | |
| 1337 INVALID_USAGE(); | |
| 1338 } | |
| 1339 | |
| 1340 /* | |
| 1341 * Check OCSP revocation status, but only if the cert we are checking | |
| 1342 * is not a status responder itself. We only do this in the case | |
| 1343 * where we checked the cert chain (above); explicit trust "wins" | |
| 1344 * (avoids status checking, just as it avoids CRL checking) by | |
| 1345 * bypassing this code. | |
| 1346 */ | |
| 1347 | |
| 1348 if (PR_FALSE == checkedOCSP) { | |
| 1349 checkedOCSP = PR_TRUE; /* only check OCSP once */ | |
| 1350 statusConfig = CERT_GetStatusConfig(handle); | |
| 1351 if (requiredUsages != certificateUsageStatusResponder && | |
| 1352 statusConfig != NULL) { | |
| 1353 if (statusConfig->statusChecker != NULL) { | |
| 1354 rv = (*statusConfig->statusChecker)(handle, cert, | |
| 1355 t, wincx); | |
| 1356 if (rv != SECSuccess) { | |
| 1357 LOG_ERROR(log, cert, 0, 0); | |
| 1358 revoked = PR_TRUE; | |
| 1359 INVALID_USAGE(); | |
| 1360 } | |
| 1361 } | |
| 1362 } | |
| 1363 } | |
| 1364 | |
| 1365 NEXT_USAGE(); | |
| 1366 } | |
| 1367 | |
| 1368 loser: | |
| 1369 return (valid); | |
| 1370 } | |
| 1371 | |
| 1372 SECStatus | |
| 1373 CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 1374 PRBool checkSig, SECCertUsage certUsage, PRTime t, | |
| 1375 void *wincx, CERTVerifyLog *log) | |
| 1376 { | |
| 1377 return cert_VerifyCertWithFlags(handle, cert, checkSig, certUsage, t, | |
| 1378 CERT_VERIFYCERT_USE_DEFAULTS, wincx, log); | |
| 1379 } | |
| 1380 | |
| 1381 SECStatus | |
| 1382 cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 1383 PRBool checkSig, SECCertUsage certUsage, PRTime t, | |
| 1384 PRUint32 flags, void *wincx, CERTVerifyLog *log) | |
| 1385 { | |
| 1386 SECStatus rv; | |
| 1387 unsigned int requiredKeyUsage; | |
| 1388 unsigned int requiredCertType; | |
| 1389 unsigned int failedFlags; | |
| 1390 unsigned int certType; | |
| 1391 PRBool trusted; | |
| 1392 PRBool allowOverride; | |
| 1393 SECCertTimeValidity validity; | |
| 1394 CERTStatusConfig *statusConfig; | |
| 1395 | |
| 1396 #ifdef notdef | |
| 1397 /* check if this cert is in the Evil list */ | |
| 1398 rv = CERT_CheckForEvilCert(cert); | |
| 1399 if (rv != SECSuccess) { | |
| 1400 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | |
| 1401 LOG_ERROR_OR_EXIT(log, cert, 0, 0); | |
| 1402 } | |
| 1403 #endif | |
| 1404 | |
| 1405 /* make sure that the cert is valid at time t */ | |
| 1406 allowOverride = (PRBool)((certUsage == certUsageSSLServer) || | |
| 1407 (certUsage == certUsageSSLServerWithStepUp)); | |
| 1408 validity = CERT_CheckCertValidTimes(cert, t, allowOverride); | |
| 1409 if (validity != secCertTimeValid) { | |
| 1410 LOG_ERROR_OR_EXIT(log, cert, 0, validity); | |
| 1411 } | |
| 1412 | |
| 1413 /* check key usage and netscape cert type */ | |
| 1414 cert_GetCertType(cert); | |
| 1415 certType = cert->nsCertType; | |
| 1416 switch (certUsage) { | |
| 1417 case certUsageSSLClient: | |
| 1418 case certUsageSSLServer: | |
| 1419 case certUsageSSLServerWithStepUp: | |
| 1420 case certUsageSSLCA: | |
| 1421 case certUsageEmailSigner: | |
| 1422 case certUsageEmailRecipient: | |
| 1423 case certUsageObjectSigner: | |
| 1424 case certUsageStatusResponder: | |
| 1425 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, | |
| 1426 &requiredKeyUsage, | |
| 1427 &requiredCertType); | |
| 1428 if (rv != SECSuccess) { | |
| 1429 PORT_Assert(0); | |
| 1430 EXIT_IF_NOT_LOGGING(log); | |
| 1431 requiredKeyUsage = 0; | |
| 1432 requiredCertType = 0; | |
| 1433 } | |
| 1434 break; | |
| 1435 case certUsageVerifyCA: | |
| 1436 case certUsageAnyCA: | |
| 1437 requiredKeyUsage = KU_KEY_CERT_SIGN; | |
| 1438 requiredCertType = NS_CERT_TYPE_CA; | |
| 1439 if (!(certType & NS_CERT_TYPE_CA)) { | |
| 1440 certType |= NS_CERT_TYPE_CA; | |
| 1441 } | |
| 1442 break; | |
| 1443 default: | |
| 1444 PORT_Assert(0); | |
| 1445 EXIT_IF_NOT_LOGGING(log); | |
| 1446 requiredKeyUsage = 0; | |
| 1447 requiredCertType = 0; | |
| 1448 } | |
| 1449 if (CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess) { | |
| 1450 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); | |
| 1451 LOG_ERROR_OR_EXIT(log, cert, 0, requiredKeyUsage); | |
| 1452 } | |
| 1453 if (!(certType & requiredCertType)) { | |
| 1454 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); | |
| 1455 LOG_ERROR_OR_EXIT(log, cert, 0, requiredCertType); | |
| 1456 } | |
| 1457 | |
| 1458 rv = cert_CheckLeafTrust(cert, certUsage, &failedFlags, &trusted); | |
| 1459 if (rv == SECFailure) { | |
| 1460 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); | |
| 1461 LOG_ERROR_OR_EXIT(log, cert, 0, failedFlags); | |
| 1462 } else if (trusted) { | |
| 1463 goto done; | |
| 1464 } | |
| 1465 | |
| 1466 rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage, | |
| 1467 t, wincx, log); | |
| 1468 if (rv != SECSuccess) { | |
| 1469 EXIT_IF_NOT_LOGGING(log); | |
| 1470 } | |
| 1471 | |
| 1472 /* | |
| 1473 * Check revocation status, but only if the cert we are checking is not a | |
| 1474 * status responder itself and the caller did not ask us to skip the check. | |
| 1475 * We only do this in the case where we checked the cert chain (above); | |
| 1476 * explicit trust "wins" (avoids status checking, just as it avoids CRL | |
| 1477 * checking, which is all done inside VerifyCertChain) by bypassing this | |
| 1478 * code. | |
| 1479 */ | |
| 1480 if (!(flags & CERT_VERIFYCERT_SKIP_OCSP) && | |
| 1481 certUsage != certUsageStatusResponder) { | |
| 1482 statusConfig = CERT_GetStatusConfig(handle); | |
| 1483 if (statusConfig && statusConfig->statusChecker) { | |
| 1484 rv = (*statusConfig->statusChecker)(handle, cert, | |
| 1485 t, wincx); | |
| 1486 if (rv != SECSuccess) { | |
| 1487 LOG_ERROR_OR_EXIT(log, cert, 0, 0); | |
| 1488 } | |
| 1489 } | |
| 1490 } | |
| 1491 | |
| 1492 done: | |
| 1493 if (log && log->head) { | |
| 1494 return SECFailure; | |
| 1495 } | |
| 1496 return (SECSuccess); | |
| 1497 | |
| 1498 loser: | |
| 1499 rv = SECFailure; | |
| 1500 | |
| 1501 return (rv); | |
| 1502 } | |
| 1503 | |
| 1504 /* | |
| 1505 * verify a certificate by checking if its valid and that we | |
| 1506 * trust the issuer. Verify time against now. | |
| 1507 */ | |
| 1508 SECStatus | |
| 1509 CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 1510 PRBool checkSig, SECCertificateUsage requiredUsages, | |
| 1511 void *wincx, SECCertificateUsage *returnedUsages) | |
| 1512 { | |
| 1513 return (CERT_VerifyCertificate(handle, cert, checkSig, | |
| 1514 requiredUsages, PR_Now(), wincx, NULL, return
edUsages)); | |
| 1515 } | |
| 1516 | |
| 1517 /* obsolete, do not use for new code */ | |
| 1518 SECStatus | |
| 1519 CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert, | |
| 1520 PRBool checkSig, SECCertUsage certUsage, void *wincx) | |
| 1521 { | |
| 1522 return (CERT_VerifyCert(handle, cert, checkSig, | |
| 1523 certUsage, PR_Now(), wincx, NULL)); | |
| 1524 } | |
| 1525 | |
| 1526 /* [ FROM pcertdb.c ] */ | |
| 1527 /* | |
| 1528 * Supported usage values and types: | |
| 1529 * certUsageSSLClient | |
| 1530 * certUsageSSLServer | |
| 1531 * certUsageSSLServerWithStepUp | |
| 1532 * certUsageEmailSigner | |
| 1533 * certUsageEmailRecipient | |
| 1534 * certUsageObjectSigner | |
| 1535 */ | |
| 1536 | |
| 1537 CERTCertificate * | |
| 1538 CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName, | |
| 1539 CERTCertOwner owner, SECCertUsage usage, | |
| 1540 PRBool preferTrusted, PRTime validTime, PRBool validOnly) | |
| 1541 { | |
| 1542 CERTCertList *certList = NULL; | |
| 1543 CERTCertificate *cert = NULL; | |
| 1544 CERTCertTrust certTrust; | |
| 1545 unsigned int requiredTrustFlags; | |
| 1546 SECTrustType requiredTrustType; | |
| 1547 unsigned int flags; | |
| 1548 | |
| 1549 PRBool lookingForCA = PR_FALSE; | |
| 1550 SECStatus rv; | |
| 1551 CERTCertListNode *node; | |
| 1552 CERTCertificate *saveUntrustedCA = NULL; | |
| 1553 | |
| 1554 /* if preferTrusted is set, must be a CA cert */ | |
| 1555 PORT_Assert(!(preferTrusted && (owner != certOwnerCA))); | |
| 1556 | |
| 1557 if (owner == certOwnerCA) { | |
| 1558 lookingForCA = PR_TRUE; | |
| 1559 if (preferTrusted) { | |
| 1560 rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags, | |
| 1561 &requiredTrustType); | |
| 1562 if (rv != SECSuccess) { | |
| 1563 goto loser; | |
| 1564 } | |
| 1565 requiredTrustFlags |= CERTDB_VALID_CA; | |
| 1566 } | |
| 1567 } | |
| 1568 | |
| 1569 certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime, | |
| 1570 validOnly); | |
| 1571 if (certList != NULL) { | |
| 1572 rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA); | |
| 1573 if (rv != SECSuccess) { | |
| 1574 goto loser; | |
| 1575 } | |
| 1576 | |
| 1577 node = CERT_LIST_HEAD(certList); | |
| 1578 | |
| 1579 while (!CERT_LIST_END(node, certList)) { | |
| 1580 cert = node->cert; | |
| 1581 | |
| 1582 /* looking for a trusted CA cert */ | |
| 1583 if ((owner == certOwnerCA) && preferTrusted && | |
| 1584 (requiredTrustType != trustTypeNone)) { | |
| 1585 | |
| 1586 if (CERT_GetCertTrust(cert, &certTrust) != SECSuccess) { | |
| 1587 flags = 0; | |
| 1588 } else { | |
| 1589 flags = SEC_GET_TRUST_FLAGS(&certTrust, requiredTrustType); | |
| 1590 } | |
| 1591 | |
| 1592 if ((flags & requiredTrustFlags) != requiredTrustFlags) { | |
| 1593 /* cert is not trusted */ | |
| 1594 /* if this is the first cert to get this far, then save | |
| 1595 * it, so we can use it if we can't find a trusted one | |
| 1596 */ | |
| 1597 if (saveUntrustedCA == NULL) { | |
| 1598 saveUntrustedCA = cert; | |
| 1599 } | |
| 1600 goto endloop; | |
| 1601 } | |
| 1602 } | |
| 1603 /* if we got this far, then this cert meets all criteria */ | |
| 1604 break; | |
| 1605 | |
| 1606 endloop: | |
| 1607 node = CERT_LIST_NEXT(node); | |
| 1608 cert = NULL; | |
| 1609 } | |
| 1610 | |
| 1611 /* use the saved one if we have it */ | |
| 1612 if (cert == NULL) { | |
| 1613 cert = saveUntrustedCA; | |
| 1614 } | |
| 1615 | |
| 1616 /* if we found one then bump the ref count before freeing the list */ | |
| 1617 if (cert != NULL) { | |
| 1618 /* bump the ref count */ | |
| 1619 cert = CERT_DupCertificate(cert); | |
| 1620 } | |
| 1621 | |
| 1622 CERT_DestroyCertList(certList); | |
| 1623 } | |
| 1624 | |
| 1625 return (cert); | |
| 1626 | |
| 1627 loser: | |
| 1628 if (certList != NULL) { | |
| 1629 CERT_DestroyCertList(certList); | |
| 1630 } | |
| 1631 | |
| 1632 return (NULL); | |
| 1633 } | |
| 1634 | |
| 1635 /* [ From certdb.c ] */ | |
| 1636 /* | |
| 1637 * Filter a list of certificates, removing those certs that do not have | |
| 1638 * one of the named CA certs somewhere in their cert chain. | |
| 1639 * | |
| 1640 * "certList" - the list of certificates to filter | |
| 1641 * "nCANames" - number of CA names | |
| 1642 * "caNames" - array of CA names in string(rfc 1485) form | |
| 1643 * "usage" - what use the certs are for, this is used when | |
| 1644 * selecting CA certs | |
| 1645 */ | |
| 1646 SECStatus | |
| 1647 CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames, | |
| 1648 char **caNames, SECCertUsage usage) | |
| 1649 { | |
| 1650 CERTCertificate *issuerCert = NULL; | |
| 1651 CERTCertificate *subjectCert; | |
| 1652 CERTCertListNode *node, *freenode; | |
| 1653 CERTCertificate *cert; | |
| 1654 int n; | |
| 1655 char **names; | |
| 1656 PRBool found; | |
| 1657 PRTime time; | |
| 1658 | |
| 1659 if (nCANames <= 0) { | |
| 1660 return (SECSuccess); | |
| 1661 } | |
| 1662 | |
| 1663 time = PR_Now(); | |
| 1664 | |
| 1665 node = CERT_LIST_HEAD(certList); | |
| 1666 | |
| 1667 while (!CERT_LIST_END(node, certList)) { | |
| 1668 cert = node->cert; | |
| 1669 | |
| 1670 subjectCert = CERT_DupCertificate(cert); | |
| 1671 | |
| 1672 /* traverse the CA certs for this cert */ | |
| 1673 found = PR_FALSE; | |
| 1674 while (subjectCert != NULL) { | |
| 1675 n = nCANames; | |
| 1676 names = caNames; | |
| 1677 | |
| 1678 if (subjectCert->issuerName != NULL) { | |
| 1679 while (n > 0) { | |
| 1680 if (PORT_Strcmp(*names, subjectCert->issuerName) == 0) { | |
| 1681 found = PR_TRUE; | |
| 1682 break; | |
| 1683 } | |
| 1684 | |
| 1685 n--; | |
| 1686 names++; | |
| 1687 } | |
| 1688 } | |
| 1689 | |
| 1690 if (found) { | |
| 1691 break; | |
| 1692 } | |
| 1693 | |
| 1694 issuerCert = CERT_FindCertIssuer(subjectCert, time, usage); | |
| 1695 if (issuerCert == subjectCert) { | |
| 1696 CERT_DestroyCertificate(issuerCert); | |
| 1697 issuerCert = NULL; | |
| 1698 break; | |
| 1699 } | |
| 1700 CERT_DestroyCertificate(subjectCert); | |
| 1701 subjectCert = issuerCert; | |
| 1702 } | |
| 1703 CERT_DestroyCertificate(subjectCert); | |
| 1704 if (!found) { | |
| 1705 /* CA was not found, so remove this cert from the list */ | |
| 1706 freenode = node; | |
| 1707 node = CERT_LIST_NEXT(node); | |
| 1708 CERT_RemoveCertListNode(freenode); | |
| 1709 } else { | |
| 1710 /* CA was found, so leave it in the list */ | |
| 1711 node = CERT_LIST_NEXT(node); | |
| 1712 } | |
| 1713 } | |
| 1714 | |
| 1715 return (SECSuccess); | |
| 1716 } | |
| 1717 | |
| 1718 /* | |
| 1719 * Given a certificate, return a string containing the nickname, and possibly | |
| 1720 * one of the validity strings, based on the current validity state of the | |
| 1721 * certificate. | |
| 1722 * | |
| 1723 * "arena" - arena to allocate returned string from. If NULL, then heap | |
| 1724 * is used. | |
| 1725 * "cert" - the cert to get nickname from | |
| 1726 * "expiredString" - the string to append to the nickname if the cert is | |
| 1727 * expired. | |
| 1728 * "notYetGoodString" - the string to append to the nickname if the cert is | |
| 1729 * not yet good. | |
| 1730 */ | |
| 1731 char * | |
| 1732 CERT_GetCertNicknameWithValidity(PLArenaPool *arena, CERTCertificate *cert, | |
| 1733 char *expiredString, char *notYetGoodString) | |
| 1734 { | |
| 1735 SECCertTimeValidity validity; | |
| 1736 char *nickname = NULL, *tmpstr = NULL; | |
| 1737 | |
| 1738 validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE); | |
| 1739 | |
| 1740 /* if the cert is good, then just use the nickname directly */ | |
| 1741 if (validity == secCertTimeValid) { | |
| 1742 if (arena == NULL) { | |
| 1743 nickname = PORT_Strdup(cert->nickname); | |
| 1744 } else { | |
| 1745 nickname = PORT_ArenaStrdup(arena, cert->nickname); | |
| 1746 } | |
| 1747 | |
| 1748 if (nickname == NULL) { | |
| 1749 goto loser; | |
| 1750 } | |
| 1751 } else { | |
| 1752 | |
| 1753 /* if the cert is not valid, then tack one of the strings on the | |
| 1754 * end | |
| 1755 */ | |
| 1756 if (validity == secCertTimeExpired) { | |
| 1757 tmpstr = PR_smprintf("%s%s", cert->nickname, | |
| 1758 expiredString); | |
| 1759 } else if (validity == secCertTimeNotValidYet) { | |
| 1760 /* not yet valid */ | |
| 1761 tmpstr = PR_smprintf("%s%s", cert->nickname, | |
| 1762 notYetGoodString); | |
| 1763 } else { | |
| 1764 /* undetermined */ | |
| 1765 tmpstr = PR_smprintf("%s", | |
| 1766 "(NULL) (Validity Unknown)"); | |
| 1767 } | |
| 1768 | |
| 1769 if (tmpstr == NULL) { | |
| 1770 goto loser; | |
| 1771 } | |
| 1772 | |
| 1773 if (arena) { | |
| 1774 /* copy the string into the arena and free the malloc'd one */ | |
| 1775 nickname = PORT_ArenaStrdup(arena, tmpstr); | |
| 1776 PORT_Free(tmpstr); | |
| 1777 } else { | |
| 1778 nickname = tmpstr; | |
| 1779 } | |
| 1780 if (nickname == NULL) { | |
| 1781 goto loser; | |
| 1782 } | |
| 1783 } | |
| 1784 return (nickname); | |
| 1785 | |
| 1786 loser: | |
| 1787 return (NULL); | |
| 1788 } | |
| 1789 | |
| 1790 /* | |
| 1791 * Collect the nicknames from all certs in a CertList. If the cert is not | |
| 1792 * valid, append a string to that nickname. | |
| 1793 * | |
| 1794 * "certList" - the list of certificates | |
| 1795 * "expiredString" - the string to append to the nickname of any expired cert | |
| 1796 * "notYetGoodString" - the string to append to the nickname of any cert | |
| 1797 * that is not yet valid | |
| 1798 */ | |
| 1799 CERTCertNicknames * | |
| 1800 CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString, | |
| 1801 char *notYetGoodString) | |
| 1802 { | |
| 1803 CERTCertNicknames *names; | |
| 1804 PLArenaPool *arena; | |
| 1805 CERTCertListNode *node; | |
| 1806 char **nn; | |
| 1807 | |
| 1808 /* allocate an arena */ | |
| 1809 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 1810 if (arena == NULL) { | |
| 1811 return (NULL); | |
| 1812 } | |
| 1813 | |
| 1814 /* allocate the structure */ | |
| 1815 names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); | |
| 1816 if (names == NULL) { | |
| 1817 goto loser; | |
| 1818 } | |
| 1819 | |
| 1820 /* init the structure */ | |
| 1821 names->arena = arena; | |
| 1822 names->head = NULL; | |
| 1823 names->numnicknames = 0; | |
| 1824 names->nicknames = NULL; | |
| 1825 names->totallen = 0; | |
| 1826 | |
| 1827 /* count the certs in the list */ | |
| 1828 node = CERT_LIST_HEAD(certList); | |
| 1829 while (!CERT_LIST_END(node, certList)) { | |
| 1830 names->numnicknames++; | |
| 1831 node = CERT_LIST_NEXT(node); | |
| 1832 } | |
| 1833 | |
| 1834 /* allocate nicknames array */ | |
| 1835 names->nicknames = PORT_ArenaAlloc(arena, | |
| 1836 sizeof(char *) * names->numnicknames); | |
| 1837 if (names->nicknames == NULL) { | |
| 1838 goto loser; | |
| 1839 } | |
| 1840 | |
| 1841 /* just in case printf can't deal with null strings */ | |
| 1842 if (expiredString == NULL) { | |
| 1843 expiredString = ""; | |
| 1844 } | |
| 1845 | |
| 1846 if (notYetGoodString == NULL) { | |
| 1847 notYetGoodString = ""; | |
| 1848 } | |
| 1849 | |
| 1850 /* traverse the list of certs and collect the nicknames */ | |
| 1851 nn = names->nicknames; | |
| 1852 node = CERT_LIST_HEAD(certList); | |
| 1853 while (!CERT_LIST_END(node, certList)) { | |
| 1854 *nn = CERT_GetCertNicknameWithValidity(arena, node->cert, | |
| 1855 expiredString, | |
| 1856 notYetGoodString); | |
| 1857 if (*nn == NULL) { | |
| 1858 goto loser; | |
| 1859 } | |
| 1860 | |
| 1861 names->totallen += PORT_Strlen(*nn); | |
| 1862 | |
| 1863 nn++; | |
| 1864 node = CERT_LIST_NEXT(node); | |
| 1865 } | |
| 1866 | |
| 1867 return (names); | |
| 1868 | |
| 1869 loser: | |
| 1870 PORT_FreeArena(arena, PR_FALSE); | |
| 1871 return (NULL); | |
| 1872 } | |
| 1873 | |
| 1874 /* | |
| 1875 * Extract the nickname from a nickmake string that may have either | |
| 1876 * expiredString or notYetGoodString appended. | |
| 1877 * | |
| 1878 * Args: | |
| 1879 * "namestring" - the string containing the nickname, and possibly | |
| 1880 * one of the validity label strings | |
| 1881 * "expiredString" - the expired validity label string | |
| 1882 * "notYetGoodString" - the not yet good validity label string | |
| 1883 * | |
| 1884 * Returns the raw nickname | |
| 1885 */ | |
| 1886 char * | |
| 1887 CERT_ExtractNicknameString(char *namestring, char *expiredString, | |
| 1888 char *notYetGoodString) | |
| 1889 { | |
| 1890 int explen, nyglen, namelen; | |
| 1891 int retlen; | |
| 1892 char *retstr; | |
| 1893 | |
| 1894 namelen = PORT_Strlen(namestring); | |
| 1895 explen = PORT_Strlen(expiredString); | |
| 1896 nyglen = PORT_Strlen(notYetGoodString); | |
| 1897 | |
| 1898 if (namelen > explen) { | |
| 1899 if (PORT_Strcmp(expiredString, &namestring[namelen - explen]) == 0) { | |
| 1900 retlen = namelen - explen; | |
| 1901 retstr = (char *)PORT_Alloc(retlen + 1); | |
| 1902 if (retstr == NULL) { | |
| 1903 goto loser; | |
| 1904 } | |
| 1905 | |
| 1906 PORT_Memcpy(retstr, namestring, retlen); | |
| 1907 retstr[retlen] = '\0'; | |
| 1908 goto done; | |
| 1909 } | |
| 1910 } | |
| 1911 | |
| 1912 if (namelen > nyglen) { | |
| 1913 if (PORT_Strcmp(notYetGoodString, &namestring[namelen - nyglen]) == 0) { | |
| 1914 retlen = namelen - nyglen; | |
| 1915 retstr = (char *)PORT_Alloc(retlen + 1); | |
| 1916 if (retstr == NULL) { | |
| 1917 goto loser; | |
| 1918 } | |
| 1919 | |
| 1920 PORT_Memcpy(retstr, namestring, retlen); | |
| 1921 retstr[retlen] = '\0'; | |
| 1922 goto done; | |
| 1923 } | |
| 1924 } | |
| 1925 | |
| 1926 /* if name string is shorter than either invalid string, then it must | |
| 1927 * be a raw nickname | |
| 1928 */ | |
| 1929 retstr = PORT_Strdup(namestring); | |
| 1930 | |
| 1931 done: | |
| 1932 return (retstr); | |
| 1933 | |
| 1934 loser: | |
| 1935 return (NULL); | |
| 1936 } | |
| 1937 | |
| 1938 CERTCertList * | |
| 1939 CERT_GetCertChainFromCert(CERTCertificate *cert, PRTime time, SECCertUsage usage
) | |
| 1940 { | |
| 1941 CERTCertList *chain = NULL; | |
| 1942 int count = 0; | |
| 1943 | |
| 1944 if (NULL == cert) { | |
| 1945 return NULL; | |
| 1946 } | |
| 1947 | |
| 1948 cert = CERT_DupCertificate(cert); | |
| 1949 if (NULL == cert) { | |
| 1950 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 1951 return NULL; | |
| 1952 } | |
| 1953 | |
| 1954 chain = CERT_NewCertList(); | |
| 1955 if (NULL == chain) { | |
| 1956 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 1957 return NULL; | |
| 1958 } | |
| 1959 | |
| 1960 while (cert != NULL && ++count <= CERT_MAX_CERT_CHAIN) { | |
| 1961 if (SECSuccess != CERT_AddCertToListTail(chain, cert)) { | |
| 1962 /* return partial chain */ | |
| 1963 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 1964 return chain; | |
| 1965 } | |
| 1966 | |
| 1967 if (cert->isRoot) { | |
| 1968 /* return complete chain */ | |
| 1969 return chain; | |
| 1970 } | |
| 1971 | |
| 1972 cert = CERT_FindCertIssuer(cert, time, usage); | |
| 1973 } | |
| 1974 | |
| 1975 /* return partial chain */ | |
| 1976 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); | |
| 1977 return chain; | |
| 1978 } | |
| OLD | NEW |