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