1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/certhigh/certvfy.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1844 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include "nspr.h" 1.8 +#include "secerr.h" 1.9 +#include "secport.h" 1.10 +#include "seccomon.h" 1.11 +#include "secoid.h" 1.12 +#include "sslerr.h" 1.13 +#include "genname.h" 1.14 +#include "keyhi.h" 1.15 +#include "cert.h" 1.16 +#include "certdb.h" 1.17 +#include "certi.h" 1.18 +#include "cryptohi.h" 1.19 +#include "pkix.h" 1.20 +/*#include "pkix_sample_modules.h" */ 1.21 +#include "pkix_pl_cert.h" 1.22 + 1.23 + 1.24 +#include "nsspki.h" 1.25 +#include "pkitm.h" 1.26 +#include "pkim.h" 1.27 +#include "pki3hack.h" 1.28 +#include "base.h" 1.29 + 1.30 +/* 1.31 + * Check the validity times of a certificate 1.32 + */ 1.33 +SECStatus 1.34 +CERT_CertTimesValid(CERTCertificate *c) 1.35 +{ 1.36 + SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE); 1.37 + return (valid == secCertTimeValid) ? SECSuccess : SECFailure; 1.38 +} 1.39 + 1.40 +/* 1.41 + * verify the signature of a signed data object with the given DER publickey 1.42 + */ 1.43 +SECStatus 1.44 +CERT_VerifySignedDataWithPublicKey(const CERTSignedData *sd, 1.45 + SECKEYPublicKey *pubKey, 1.46 + void *wincx) 1.47 +{ 1.48 + SECStatus rv; 1.49 + SECItem sig; 1.50 + SECOidTag hashAlg = SEC_OID_UNKNOWN; 1.51 + 1.52 + if ( !pubKey || !sd ) { 1.53 + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); 1.54 + return SECFailure; 1.55 + } 1.56 + 1.57 + /* check the signature */ 1.58 + sig = sd->signature; 1.59 + /* convert sig->len from bit counts to byte count. */ 1.60 + DER_ConvertBitString(&sig); 1.61 + 1.62 + rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, 1.63 + &sig, &sd->signatureAlgorithm, &hashAlg, wincx); 1.64 + if (rv == SECSuccess) { 1.65 + /* Are we honoring signatures for this algorithm? */ 1.66 + PRUint32 policyFlags = 0; 1.67 + rv = NSS_GetAlgorithmPolicy(hashAlg, &policyFlags); 1.68 + if (rv == SECSuccess && 1.69 + !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) { 1.70 + PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); 1.71 + rv = SECFailure; 1.72 + } 1.73 + } 1.74 + return rv; 1.75 +} 1.76 + 1.77 +/* 1.78 + * verify the signature of a signed data object with the given DER publickey 1.79 + */ 1.80 +SECStatus 1.81 +CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd, 1.82 + CERTSubjectPublicKeyInfo *pubKeyInfo, 1.83 + void *wincx) 1.84 +{ 1.85 + SECKEYPublicKey *pubKey; 1.86 + SECStatus rv = SECFailure; 1.87 + 1.88 + /* get cert's public key */ 1.89 + pubKey = SECKEY_ExtractPublicKey(pubKeyInfo); 1.90 + if (pubKey) { 1.91 + rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); 1.92 + SECKEY_DestroyPublicKey(pubKey); 1.93 + } 1.94 + return rv; 1.95 +} 1.96 + 1.97 +/* 1.98 + * verify the signature of a signed data object with the given certificate 1.99 + */ 1.100 +SECStatus 1.101 +CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert, 1.102 + PRTime t, void *wincx) 1.103 +{ 1.104 + SECKEYPublicKey *pubKey = 0; 1.105 + SECStatus rv = SECFailure; 1.106 + SECCertTimeValidity validity; 1.107 + 1.108 + /* check the certificate's validity */ 1.109 + validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE); 1.110 + if ( validity != secCertTimeValid ) { 1.111 + return rv; 1.112 + } 1.113 + 1.114 + /* get cert's public key */ 1.115 + pubKey = CERT_ExtractPublicKey(cert); 1.116 + if (pubKey) { 1.117 + rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); 1.118 + SECKEY_DestroyPublicKey(pubKey); 1.119 + } 1.120 + return rv; 1.121 +} 1.122 + 1.123 + 1.124 +SECStatus 1.125 +SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert, 1.126 + CERTCertificate *caCert, PRTime t, void * wincx) 1.127 +{ 1.128 + return CERT_CheckCRL(cert, caCert, NULL, t, wincx); 1.129 +} 1.130 + 1.131 +/* 1.132 + * Find the issuer of a cert. Use the authorityKeyID if it exists. 1.133 + */ 1.134 +CERTCertificate * 1.135 +CERT_FindCertIssuer(CERTCertificate *cert, PRTime validTime, SECCertUsage usage) 1.136 +{ 1.137 + NSSCertificate *me; 1.138 + NSSTime *nssTime; 1.139 + NSSTrustDomain *td; 1.140 + NSSCryptoContext *cc; 1.141 + NSSCertificate *chain[3]; 1.142 + NSSUsage nssUsage; 1.143 + PRStatus status; 1.144 + 1.145 + me = STAN_GetNSSCertificate(cert); 1.146 + if (!me) { 1.147 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.148 + return NULL; 1.149 + } 1.150 + nssTime = NSSTime_SetPRTime(NULL, validTime); 1.151 + nssUsage.anyUsage = PR_FALSE; 1.152 + nssUsage.nss3usage = usage; 1.153 + nssUsage.nss3lookingForCA = PR_TRUE; 1.154 + memset(chain, 0, 3*sizeof(NSSCertificate *)); 1.155 + td = STAN_GetDefaultTrustDomain(); 1.156 + cc = STAN_GetDefaultCryptoContext(); 1.157 + (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL, 1.158 + chain, 2, NULL, &status, td, cc); 1.159 + nss_ZFreeIf(nssTime); 1.160 + if (status == PR_SUCCESS) { 1.161 + PORT_Assert(me == chain[0]); 1.162 + /* if it's a root, the chain will only have one cert */ 1.163 + if (!chain[1]) { 1.164 + /* already has a reference from the call to BuildChain */ 1.165 + return cert; 1.166 + } 1.167 + NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ 1.168 + return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */ 1.169 + } 1.170 + if (chain[0]) { 1.171 + PORT_Assert(me == chain[0]); 1.172 + NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ 1.173 + } 1.174 + PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); 1.175 + return NULL; 1.176 +} 1.177 + 1.178 +/* 1.179 + * return required trust flags for various cert usages for CAs 1.180 + */ 1.181 +SECStatus 1.182 +CERT_TrustFlagsForCACertUsage(SECCertUsage usage, 1.183 + unsigned int *retFlags, 1.184 + SECTrustType *retTrustType) 1.185 +{ 1.186 + unsigned int requiredFlags; 1.187 + SECTrustType trustType; 1.188 + 1.189 + switch ( usage ) { 1.190 + case certUsageSSLClient: 1.191 + requiredFlags = CERTDB_TRUSTED_CLIENT_CA; 1.192 + trustType = trustSSL; 1.193 + break; 1.194 + case certUsageSSLServer: 1.195 + case certUsageSSLCA: 1.196 + requiredFlags = CERTDB_TRUSTED_CA; 1.197 + trustType = trustSSL; 1.198 + break; 1.199 + case certUsageSSLServerWithStepUp: 1.200 + requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA; 1.201 + trustType = trustSSL; 1.202 + break; 1.203 + case certUsageEmailSigner: 1.204 + case certUsageEmailRecipient: 1.205 + requiredFlags = CERTDB_TRUSTED_CA; 1.206 + trustType = trustEmail; 1.207 + break; 1.208 + case certUsageObjectSigner: 1.209 + requiredFlags = CERTDB_TRUSTED_CA; 1.210 + trustType = trustObjectSigning; 1.211 + break; 1.212 + case certUsageVerifyCA: 1.213 + case certUsageAnyCA: 1.214 + case certUsageStatusResponder: 1.215 + requiredFlags = CERTDB_TRUSTED_CA; 1.216 + trustType = trustTypeNone; 1.217 + break; 1.218 + default: 1.219 + PORT_Assert(0); 1.220 + goto loser; 1.221 + } 1.222 + if ( retFlags != NULL ) { 1.223 + *retFlags = requiredFlags; 1.224 + } 1.225 + if ( retTrustType != NULL ) { 1.226 + *retTrustType = trustType; 1.227 + } 1.228 + 1.229 + return(SECSuccess); 1.230 +loser: 1.231 + return(SECFailure); 1.232 +} 1.233 + 1.234 +void 1.235 +cert_AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, long error, 1.236 + unsigned int depth, void *arg) 1.237 +{ 1.238 + CERTVerifyLogNode *node, *tnode; 1.239 + 1.240 + PORT_Assert(log != NULL); 1.241 + 1.242 + node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena, 1.243 + sizeof(CERTVerifyLogNode)); 1.244 + if ( node != NULL ) { 1.245 + node->cert = CERT_DupCertificate(cert); 1.246 + node->error = error; 1.247 + node->depth = depth; 1.248 + node->arg = arg; 1.249 + 1.250 + if ( log->tail == NULL ) { 1.251 + /* empty list */ 1.252 + log->head = log->tail = node; 1.253 + node->prev = NULL; 1.254 + node->next = NULL; 1.255 + } else if ( depth >= log->tail->depth ) { 1.256 + /* add to tail */ 1.257 + node->prev = log->tail; 1.258 + log->tail->next = node; 1.259 + log->tail = node; 1.260 + node->next = NULL; 1.261 + } else if ( depth < log->head->depth ) { 1.262 + /* add at head */ 1.263 + node->prev = NULL; 1.264 + node->next = log->head; 1.265 + log->head->prev = node; 1.266 + log->head = node; 1.267 + } else { 1.268 + /* add in middle */ 1.269 + tnode = log->tail; 1.270 + while ( tnode != NULL ) { 1.271 + if ( depth >= tnode->depth ) { 1.272 + /* insert after tnode */ 1.273 + node->prev = tnode; 1.274 + node->next = tnode->next; 1.275 + tnode->next->prev = node; 1.276 + tnode->next = node; 1.277 + break; 1.278 + } 1.279 + 1.280 + tnode = tnode->prev; 1.281 + } 1.282 + } 1.283 + 1.284 + log->count++; 1.285 + } 1.286 + return; 1.287 +} 1.288 + 1.289 +#define EXIT_IF_NOT_LOGGING(log) \ 1.290 + if ( log == NULL ) { \ 1.291 + goto loser; \ 1.292 + } 1.293 + 1.294 +#define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \ 1.295 + if ( log != NULL ) { \ 1.296 + cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \ 1.297 + (void *)(PRWord)arg); \ 1.298 + } else { \ 1.299 + goto loser; \ 1.300 + } 1.301 + 1.302 +#define LOG_ERROR(log,cert,depth,arg) \ 1.303 + if ( log != NULL ) { \ 1.304 + cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \ 1.305 + (void *)(PRWord)arg); \ 1.306 + } 1.307 + 1.308 +static SECStatus 1.309 +cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert, 1.310 + PRBool checkSig, PRBool* sigerror, 1.311 + SECCertUsage certUsage, PRTime t, void *wincx, 1.312 + CERTVerifyLog *log, PRBool* revoked) 1.313 +{ 1.314 + SECTrustType trustType; 1.315 + CERTBasicConstraints basicConstraint; 1.316 + CERTCertificate *issuerCert = NULL; 1.317 + CERTCertificate *subjectCert = NULL; 1.318 + CERTCertificate *badCert = NULL; 1.319 + PRBool isca; 1.320 + SECStatus rv; 1.321 + SECStatus rvFinal = SECSuccess; 1.322 + int count; 1.323 + int currentPathLen = 0; 1.324 + int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; 1.325 + unsigned int caCertType; 1.326 + unsigned int requiredCAKeyUsage; 1.327 + unsigned int requiredFlags; 1.328 + PLArenaPool *arena = NULL; 1.329 + CERTGeneralName *namesList = NULL; 1.330 + CERTCertificate **certsList = NULL; 1.331 + int certsListLen = 16; 1.332 + int namesCount = 0; 1.333 + PRBool subjectCertIsSelfIssued; 1.334 + CERTCertTrust issuerTrust; 1.335 + 1.336 + if (revoked) { 1.337 + *revoked = PR_FALSE; 1.338 + } 1.339 + 1.340 + if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, 1.341 + &requiredCAKeyUsage, 1.342 + &caCertType) 1.343 + != SECSuccess ) { 1.344 + PORT_Assert(0); 1.345 + EXIT_IF_NOT_LOGGING(log); 1.346 + requiredCAKeyUsage = 0; 1.347 + caCertType = 0; 1.348 + } 1.349 + 1.350 + switch ( certUsage ) { 1.351 + case certUsageSSLClient: 1.352 + case certUsageSSLServer: 1.353 + case certUsageSSLCA: 1.354 + case certUsageSSLServerWithStepUp: 1.355 + case certUsageEmailSigner: 1.356 + case certUsageEmailRecipient: 1.357 + case certUsageObjectSigner: 1.358 + case certUsageVerifyCA: 1.359 + case certUsageAnyCA: 1.360 + case certUsageStatusResponder: 1.361 + if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, 1.362 + &trustType) != SECSuccess ) { 1.363 + PORT_Assert(0); 1.364 + EXIT_IF_NOT_LOGGING(log); 1.365 + /* XXX continuing with requiredFlags = 0 seems wrong. It'll 1.366 + * cause the following test to be true incorrectly: 1.367 + * flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType); 1.368 + * if (( flags & requiredFlags ) == requiredFlags) { 1.369 + * rv = rvFinal; 1.370 + * goto done; 1.371 + * } 1.372 + * There are three other instances of this problem. 1.373 + */ 1.374 + requiredFlags = 0; 1.375 + trustType = trustSSL; 1.376 + } 1.377 + break; 1.378 + default: 1.379 + PORT_Assert(0); 1.380 + EXIT_IF_NOT_LOGGING(log); 1.381 + requiredFlags = 0; 1.382 + trustType = trustSSL;/* This used to be 0, but we need something 1.383 + * that matches the enumeration type. 1.384 + */ 1.385 + caCertType = 0; 1.386 + } 1.387 + 1.388 + subjectCert = CERT_DupCertificate(cert); 1.389 + if ( subjectCert == NULL ) { 1.390 + goto loser; 1.391 + } 1.392 + 1.393 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.394 + if (arena == NULL) { 1.395 + goto loser; 1.396 + } 1.397 + 1.398 + certsList = PORT_ZNewArray(CERTCertificate *, certsListLen); 1.399 + if (certsList == NULL) 1.400 + goto loser; 1.401 + 1.402 + /* RFC 3280 says that the name constraints will apply to the names 1.403 + ** in the leaf (EE) cert, whether it is self issued or not, so 1.404 + ** we pretend that it is not. 1.405 + */ 1.406 + subjectCertIsSelfIssued = PR_FALSE; 1.407 + for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) { 1.408 + PRBool validCAOverride = PR_FALSE; 1.409 + 1.410 + /* Construct a list of names for the current and all previous 1.411 + * certifcates (except leaf (EE) certs, root CAs, and self-issued 1.412 + * intermediate CAs) to be verified against the name constraints 1.413 + * extension of the issuer certificate. 1.414 + */ 1.415 + if (subjectCertIsSelfIssued == PR_FALSE) { 1.416 + CERTGeneralName *subjectNameList; 1.417 + int subjectNameListLen; 1.418 + int i; 1.419 + PRBool getSubjectCN = (!count && certUsage == certUsageSSLServer); 1.420 + subjectNameList = 1.421 + CERT_GetConstrainedCertificateNames(subjectCert, arena, 1.422 + getSubjectCN); 1.423 + if (!subjectNameList) 1.424 + goto loser; 1.425 + subjectNameListLen = CERT_GetNamesLength(subjectNameList); 1.426 + if (!subjectNameListLen) 1.427 + goto loser; 1.428 + if (certsListLen <= namesCount + subjectNameListLen) { 1.429 + CERTCertificate **tmpCertsList; 1.430 + certsListLen = (namesCount + subjectNameListLen) * 2; 1.431 + tmpCertsList = 1.432 + (CERTCertificate **)PORT_Realloc(certsList, 1.433 + certsListLen * sizeof(CERTCertificate *)); 1.434 + if (tmpCertsList == NULL) { 1.435 + goto loser; 1.436 + } 1.437 + certsList = tmpCertsList; 1.438 + } 1.439 + for (i = 0; i < subjectNameListLen; i++) { 1.440 + certsList[namesCount + i] = subjectCert; 1.441 + } 1.442 + namesCount += subjectNameListLen; 1.443 + namesList = cert_CombineNamesLists(namesList, subjectNameList); 1.444 + } 1.445 + 1.446 + /* check if the cert has an unsupported critical extension */ 1.447 + if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) { 1.448 + PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); 1.449 + LOG_ERROR_OR_EXIT(log,subjectCert,count,0); 1.450 + } 1.451 + 1.452 + /* find the certificate of the issuer */ 1.453 + issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage); 1.454 + if ( ! issuerCert ) { 1.455 + PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); 1.456 + LOG_ERROR(log,subjectCert,count,0); 1.457 + goto loser; 1.458 + } 1.459 + 1.460 + /* verify the signature on the cert */ 1.461 + if ( checkSig ) { 1.462 + rv = CERT_VerifySignedData(&subjectCert->signatureWrap, 1.463 + issuerCert, t, wincx); 1.464 + 1.465 + if ( rv != SECSuccess ) { 1.466 + if (sigerror) { 1.467 + *sigerror = PR_TRUE; 1.468 + } 1.469 + if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) { 1.470 + PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE); 1.471 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); 1.472 + } else { 1.473 + if (PORT_GetError() != 1.474 + SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) { 1.475 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.476 + } 1.477 + LOG_ERROR_OR_EXIT(log,subjectCert,count,0); 1.478 + } 1.479 + } 1.480 + } 1.481 + 1.482 + /* If the basicConstraint extension is included in an immediate CA 1.483 + * certificate, make sure that the isCA flag is on. If the 1.484 + * pathLenConstraint component exists, it must be greater than the 1.485 + * number of CA certificates we have seen so far. If the extension 1.486 + * is omitted, we will assume that this is a CA certificate with 1.487 + * an unlimited pathLenConstraint (since it already passes the 1.488 + * netscape-cert-type extension checking). 1.489 + */ 1.490 + 1.491 + rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint); 1.492 + if ( rv != SECSuccess ) { 1.493 + if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { 1.494 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); 1.495 + } 1.496 + pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; 1.497 + /* no basic constraints found, we aren't (yet) a CA. */ 1.498 + isca = PR_FALSE; 1.499 + } else { 1.500 + if ( basicConstraint.isCA == PR_FALSE ) { 1.501 + PORT_SetError (SEC_ERROR_CA_CERT_INVALID); 1.502 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); 1.503 + } 1.504 + pathLengthLimit = basicConstraint.pathLenConstraint; 1.505 + isca = PR_TRUE; 1.506 + } 1.507 + /* make sure that the path len constraint is properly set.*/ 1.508 + if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) { 1.509 + PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); 1.510 + LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit); 1.511 + } 1.512 + 1.513 + /* make sure that the entire chain is within the name space of the 1.514 + * current issuer certificate. 1.515 + */ 1.516 + rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, 1.517 + arena, &badCert); 1.518 + if (rv != SECSuccess || badCert != NULL) { 1.519 + PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE); 1.520 + LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0); 1.521 + goto loser; 1.522 + } 1.523 + 1.524 + /* XXX - the error logging may need to go down into CRL stuff at some 1.525 + * point 1.526 + */ 1.527 + /* check revoked list (issuer) */ 1.528 + rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx); 1.529 + if (rv == SECFailure) { 1.530 + if (revoked) { 1.531 + *revoked = PR_TRUE; 1.532 + } 1.533 + LOG_ERROR_OR_EXIT(log,subjectCert,count,0); 1.534 + } else if (rv == SECWouldBlock) { 1.535 + /* We found something fishy, so we intend to issue an 1.536 + * error to the user, but the user may wish to continue 1.537 + * processing, in which case we better make sure nothing 1.538 + * worse has happened... so keep cranking the loop */ 1.539 + rvFinal = SECFailure; 1.540 + if (revoked) { 1.541 + *revoked = PR_TRUE; 1.542 + } 1.543 + LOG_ERROR(log,subjectCert,count,0); 1.544 + } 1.545 + 1.546 + if ( CERT_GetCertTrust(issuerCert, &issuerTrust) == SECSuccess) { 1.547 + /* we have some trust info, but this does NOT imply that this 1.548 + * cert is actually trusted for any purpose. The cert may be 1.549 + * explicitly UNtrusted. We won't know until we examine the 1.550 + * trust bits. 1.551 + */ 1.552 + unsigned int flags; 1.553 + 1.554 + if (certUsage != certUsageAnyCA && 1.555 + certUsage != certUsageStatusResponder) { 1.556 + 1.557 + /* 1.558 + * XXX This choice of trustType seems arbitrary. 1.559 + */ 1.560 + if ( certUsage == certUsageVerifyCA ) { 1.561 + if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) { 1.562 + trustType = trustEmail; 1.563 + } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) { 1.564 + trustType = trustSSL; 1.565 + } else { 1.566 + trustType = trustObjectSigning; 1.567 + } 1.568 + } 1.569 + 1.570 + flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); 1.571 + if (( flags & requiredFlags ) == requiredFlags) { 1.572 + /* we found a trusted one, so return */ 1.573 + rv = rvFinal; 1.574 + goto done; 1.575 + } 1.576 + if (flags & CERTDB_VALID_CA) { 1.577 + validCAOverride = PR_TRUE; 1.578 + } 1.579 + /* is it explicitly distrusted? */ 1.580 + if ((flags & CERTDB_TERMINAL_RECORD) && 1.581 + ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) { 1.582 + /* untrusted -- the cert is explicitly untrusted, not 1.583 + * just that it doesn't chain to a trusted cert */ 1.584 + PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); 1.585 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags); 1.586 + } 1.587 + } else { 1.588 + /* Check if we have any valid trust when cheching for 1.589 + * certUsageAnyCA or certUsageStatusResponder. */ 1.590 + for (trustType = trustSSL; trustType < trustTypeNone; 1.591 + trustType++) { 1.592 + flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); 1.593 + if ((flags & requiredFlags) == requiredFlags) { 1.594 + rv = rvFinal; 1.595 + goto done; 1.596 + } 1.597 + if (flags & CERTDB_VALID_CA) 1.598 + validCAOverride = PR_TRUE; 1.599 + } 1.600 + /* We have 2 separate loops because we want any single trust 1.601 + * bit to allow this usage to return trusted. Only if none of 1.602 + * the trust bits are on do we check to see if the cert is 1.603 + * untrusted */ 1.604 + for (trustType = trustSSL; trustType < trustTypeNone; 1.605 + trustType++) { 1.606 + flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); 1.607 + /* is it explicitly distrusted? */ 1.608 + if ((flags & CERTDB_TERMINAL_RECORD) && 1.609 + ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) { 1.610 + /* untrusted -- the cert is explicitly untrusted, not 1.611 + * just that it doesn't chain to a trusted cert */ 1.612 + PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); 1.613 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags); 1.614 + } 1.615 + } 1.616 + } 1.617 + } 1.618 + 1.619 + if (!validCAOverride) { 1.620 + /* 1.621 + * Make sure that if this is an intermediate CA in the chain that 1.622 + * it was given permission by its signer to be a CA. 1.623 + */ 1.624 + /* 1.625 + * if basicConstraints says it is a ca, then we check the 1.626 + * nsCertType. If the nsCertType has any CA bits set, then 1.627 + * it must have the right one. 1.628 + */ 1.629 + if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) { 1.630 + isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; 1.631 + } 1.632 + 1.633 + if ( !isca ) { 1.634 + PORT_SetError(SEC_ERROR_CA_CERT_INVALID); 1.635 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); 1.636 + } 1.637 + 1.638 + /* make sure key usage allows cert signing */ 1.639 + if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) { 1.640 + PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); 1.641 + LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage); 1.642 + } 1.643 + } 1.644 + 1.645 + /* make sure that the issuer is not self signed. If it is, then 1.646 + * stop here to prevent looping. 1.647 + */ 1.648 + if (issuerCert->isRoot) { 1.649 + PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); 1.650 + LOG_ERROR(log, issuerCert, count+1, 0); 1.651 + goto loser; 1.652 + } 1.653 + /* The issuer cert will be the subject cert in the next loop. 1.654 + * A cert is self-issued if its subject and issuer are equal and 1.655 + * both are of non-zero length. 1.656 + */ 1.657 + subjectCertIsSelfIssued = (PRBool) 1.658 + SECITEM_ItemsAreEqual(&issuerCert->derIssuer, 1.659 + &issuerCert->derSubject) && 1.660 + issuerCert->derSubject.len > 0; 1.661 + if (subjectCertIsSelfIssued == PR_FALSE) { 1.662 + /* RFC 3280 says only non-self-issued intermediate CA certs 1.663 + * count in path length. 1.664 + */ 1.665 + ++currentPathLen; 1.666 + } 1.667 + 1.668 + CERT_DestroyCertificate(subjectCert); 1.669 + subjectCert = issuerCert; 1.670 + issuerCert = NULL; 1.671 + } 1.672 + 1.673 + PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); 1.674 + LOG_ERROR(log,subjectCert,count,0); 1.675 +loser: 1.676 + rv = SECFailure; 1.677 +done: 1.678 + if (certsList != NULL) { 1.679 + PORT_Free(certsList); 1.680 + } 1.681 + if ( issuerCert ) { 1.682 + CERT_DestroyCertificate(issuerCert); 1.683 + } 1.684 + 1.685 + if ( subjectCert ) { 1.686 + CERT_DestroyCertificate(subjectCert); 1.687 + } 1.688 + 1.689 + if ( arena != NULL ) { 1.690 + PORT_FreeArena(arena, PR_FALSE); 1.691 + } 1.692 + return rv; 1.693 +} 1.694 + 1.695 +SECStatus 1.696 +cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, 1.697 + PRBool checkSig, PRBool* sigerror, 1.698 + SECCertUsage certUsage, PRTime t, void *wincx, 1.699 + CERTVerifyLog *log, PRBool* revoked) 1.700 +{ 1.701 + if (CERT_GetUsePKIXForValidation()) { 1.702 + return cert_VerifyCertChainPkix(cert, checkSig, certUsage, t, 1.703 + wincx, log, sigerror, revoked); 1.704 + } 1.705 + return cert_VerifyCertChainOld(handle, cert, checkSig, sigerror, 1.706 + certUsage, t, wincx, log, revoked); 1.707 +} 1.708 + 1.709 +SECStatus 1.710 +CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, 1.711 + PRBool checkSig, SECCertUsage certUsage, PRTime t, 1.712 + void *wincx, CERTVerifyLog *log) 1.713 +{ 1.714 + return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t, 1.715 + wincx, log, NULL); 1.716 +} 1.717 + 1.718 +/* 1.719 + * verify that a CA can sign a certificate with the requested usage. 1.720 + */ 1.721 +SECStatus 1.722 +CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert, 1.723 + PRBool checkSig, SECCertUsage certUsage, PRTime t, 1.724 + void *wincx, CERTVerifyLog *log) 1.725 +{ 1.726 + SECTrustType trustType; 1.727 + CERTBasicConstraints basicConstraint; 1.728 + PRBool isca; 1.729 + PRBool validCAOverride = PR_FALSE; 1.730 + SECStatus rv; 1.731 + SECStatus rvFinal = SECSuccess; 1.732 + unsigned int flags; 1.733 + unsigned int caCertType; 1.734 + unsigned int requiredCAKeyUsage; 1.735 + unsigned int requiredFlags; 1.736 + CERTCertificate *issuerCert; 1.737 + CERTCertTrust certTrust; 1.738 + 1.739 + 1.740 + if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, 1.741 + &requiredCAKeyUsage, 1.742 + &caCertType) != SECSuccess ) { 1.743 + PORT_Assert(0); 1.744 + EXIT_IF_NOT_LOGGING(log); 1.745 + requiredCAKeyUsage = 0; 1.746 + caCertType = 0; 1.747 + } 1.748 + 1.749 + switch ( certUsage ) { 1.750 + case certUsageSSLClient: 1.751 + case certUsageSSLServer: 1.752 + case certUsageSSLCA: 1.753 + case certUsageSSLServerWithStepUp: 1.754 + case certUsageEmailSigner: 1.755 + case certUsageEmailRecipient: 1.756 + case certUsageObjectSigner: 1.757 + case certUsageVerifyCA: 1.758 + case certUsageStatusResponder: 1.759 + if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, 1.760 + &trustType) != SECSuccess ) { 1.761 + PORT_Assert(0); 1.762 + EXIT_IF_NOT_LOGGING(log); 1.763 + requiredFlags = 0; 1.764 + trustType = trustSSL; 1.765 + } 1.766 + break; 1.767 + default: 1.768 + PORT_Assert(0); 1.769 + EXIT_IF_NOT_LOGGING(log); 1.770 + requiredFlags = 0; 1.771 + trustType = trustSSL;/* This used to be 0, but we need something 1.772 + * that matches the enumeration type. 1.773 + */ 1.774 + caCertType = 0; 1.775 + } 1.776 + 1.777 + /* If the basicConstraint extension is included in an intermmediate CA 1.778 + * certificate, make sure that the isCA flag is on. If the 1.779 + * pathLenConstraint component exists, it must be greater than the 1.780 + * number of CA certificates we have seen so far. If the extension 1.781 + * is omitted, we will assume that this is a CA certificate with 1.782 + * an unlimited pathLenConstraint (since it already passes the 1.783 + * netscape-cert-type extension checking). 1.784 + */ 1.785 + 1.786 + rv = CERT_FindBasicConstraintExten(cert, &basicConstraint); 1.787 + if ( rv != SECSuccess ) { 1.788 + if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { 1.789 + LOG_ERROR_OR_EXIT(log,cert,0,0); 1.790 + } 1.791 + /* no basic constraints found, we aren't (yet) a CA. */ 1.792 + isca = PR_FALSE; 1.793 + } else { 1.794 + if ( basicConstraint.isCA == PR_FALSE ) { 1.795 + PORT_SetError (SEC_ERROR_CA_CERT_INVALID); 1.796 + LOG_ERROR_OR_EXIT(log,cert,0,0); 1.797 + } 1.798 + 1.799 + /* can't check path length if we don't know the previous path */ 1.800 + isca = PR_TRUE; 1.801 + } 1.802 + 1.803 + if ( CERT_GetCertTrust(cert, &certTrust) == SECSuccess ) { 1.804 + /* we have some trust info, but this does NOT imply that this 1.805 + * cert is actually trusted for any purpose. The cert may be 1.806 + * explicitly UNtrusted. We won't know until we examine the 1.807 + * trust bits. 1.808 + */ 1.809 + if (certUsage == certUsageStatusResponder) { 1.810 + /* Check the special case of certUsageStatusResponder */ 1.811 + issuerCert = CERT_FindCertIssuer(cert, t, certUsage); 1.812 + if (issuerCert) { 1.813 + if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx) 1.814 + != SECSuccess) { 1.815 + PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); 1.816 + CERT_DestroyCertificate(issuerCert); 1.817 + goto loser; 1.818 + } 1.819 + CERT_DestroyCertificate(issuerCert); 1.820 + } 1.821 + /* XXX We have NOT determined that this cert is trusted. 1.822 + * For years, NSS has treated this as trusted, 1.823 + * but it seems incorrect. 1.824 + */ 1.825 + rv = rvFinal; 1.826 + goto done; 1.827 + } 1.828 + 1.829 + /* 1.830 + * check the trust params of the issuer 1.831 + */ 1.832 + flags = SEC_GET_TRUST_FLAGS(&certTrust, trustType); 1.833 + if ( ( flags & requiredFlags ) == requiredFlags) { 1.834 + /* we found a trusted one, so return */ 1.835 + rv = rvFinal; 1.836 + goto done; 1.837 + } 1.838 + if (flags & CERTDB_VALID_CA) { 1.839 + validCAOverride = PR_TRUE; 1.840 + } 1.841 + /* is it explicitly distrusted? */ 1.842 + if ((flags & CERTDB_TERMINAL_RECORD) && 1.843 + ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) { 1.844 + /* untrusted -- the cert is explicitly untrusted, not 1.845 + * just that it doesn't chain to a trusted cert */ 1.846 + PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); 1.847 + LOG_ERROR_OR_EXIT(log,cert,0,flags); 1.848 + } 1.849 + } 1.850 + if (!validCAOverride) { 1.851 + /* 1.852 + * Make sure that if this is an intermediate CA in the chain that 1.853 + * it was given permission by its signer to be a CA. 1.854 + */ 1.855 + /* 1.856 + * if basicConstraints says it is a ca, then we check the 1.857 + * nsCertType. If the nsCertType has any CA bits set, then 1.858 + * it must have the right one. 1.859 + */ 1.860 + if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) { 1.861 + isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; 1.862 + } 1.863 + 1.864 + if (!isca) { 1.865 + PORT_SetError(SEC_ERROR_CA_CERT_INVALID); 1.866 + LOG_ERROR_OR_EXIT(log,cert,0,0); 1.867 + } 1.868 + 1.869 + /* make sure key usage allows cert signing */ 1.870 + if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) { 1.871 + PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); 1.872 + LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage); 1.873 + } 1.874 + } 1.875 + /* make sure that the issuer is not self signed. If it is, then 1.876 + * stop here to prevent looping. 1.877 + */ 1.878 + if (cert->isRoot) { 1.879 + PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); 1.880 + LOG_ERROR(log, cert, 0, 0); 1.881 + goto loser; 1.882 + } 1.883 + 1.884 + return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, 1.885 + wincx, log); 1.886 +loser: 1.887 + rv = SECFailure; 1.888 +done: 1.889 + return rv; 1.890 +} 1.891 + 1.892 +#define NEXT_USAGE() { \ 1.893 + i*=2; \ 1.894 + certUsage++; \ 1.895 + continue; \ 1.896 +} 1.897 + 1.898 +#define VALID_USAGE() { \ 1.899 + NEXT_USAGE(); \ 1.900 +} 1.901 + 1.902 +#define INVALID_USAGE() { \ 1.903 + if (returnedUsages) { \ 1.904 + *returnedUsages &= (~i); \ 1.905 + } \ 1.906 + if (PR_TRUE == requiredUsage) { \ 1.907 + valid = SECFailure; \ 1.908 + } \ 1.909 + NEXT_USAGE(); \ 1.910 +} 1.911 + 1.912 +/* 1.913 + * check the leaf cert against trust and usage. 1.914 + * returns success if the cert is not distrusted. If the cert is 1.915 + * trusted, then the trusted bool will be true. 1.916 + * returns failure if the cert is distrusted. If failure, flags 1.917 + * will return the flag bits that indicated distrust. 1.918 + */ 1.919 +SECStatus 1.920 +cert_CheckLeafTrust(CERTCertificate *cert, SECCertUsage certUsage, 1.921 + unsigned int *failedFlags, PRBool *trusted) 1.922 +{ 1.923 + unsigned int flags; 1.924 + CERTCertTrust trust; 1.925 + 1.926 + *failedFlags = 0; 1.927 + *trusted = PR_FALSE; 1.928 + 1.929 + /* check trust flags to see if this cert is directly trusted */ 1.930 + if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) { 1.931 + switch ( certUsage ) { 1.932 + case certUsageSSLClient: 1.933 + case certUsageSSLServer: 1.934 + flags = trust.sslFlags; 1.935 + 1.936 + /* is the cert directly trusted or not trusted ? */ 1.937 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.938 + * authoritative */ 1.939 + if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ 1.940 + *trusted = PR_TRUE; 1.941 + return SECSuccess; 1.942 + } else { /* don't trust this cert */ 1.943 + *failedFlags = flags; 1.944 + return SECFailure; 1.945 + } 1.946 + } 1.947 + break; 1.948 + case certUsageSSLServerWithStepUp: 1.949 + /* XXX - step up certs can't be directly trusted, only distrust */ 1.950 + flags = trust.sslFlags; 1.951 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.952 + * authoritative */ 1.953 + if (( flags & CERTDB_TRUSTED ) == 0) { 1.954 + /* don't trust this cert */ 1.955 + *failedFlags = flags; 1.956 + return SECFailure; 1.957 + } 1.958 + } 1.959 + break; 1.960 + case certUsageSSLCA: 1.961 + flags = trust.sslFlags; 1.962 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.963 + * authoritative */ 1.964 + if (( flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA) ) == 0) { 1.965 + /* don't trust this cert */ 1.966 + *failedFlags = flags; 1.967 + return SECFailure; 1.968 + } 1.969 + } 1.970 + break; 1.971 + case certUsageEmailSigner: 1.972 + case certUsageEmailRecipient: 1.973 + flags = trust.emailFlags; 1.974 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.975 + * authoritative */ 1.976 + if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ 1.977 + *trusted = PR_TRUE; 1.978 + return SECSuccess; 1.979 + } 1.980 + else { /* don't trust this cert */ 1.981 + *failedFlags = flags; 1.982 + return SECFailure; 1.983 + } 1.984 + } 1.985 + 1.986 + break; 1.987 + case certUsageObjectSigner: 1.988 + flags = trust.objectSigningFlags; 1.989 + 1.990 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.991 + * authoritative */ 1.992 + if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ 1.993 + *trusted = PR_TRUE; 1.994 + return SECSuccess; 1.995 + } else { /* don't trust this cert */ 1.996 + *failedFlags = flags; 1.997 + return SECFailure; 1.998 + } 1.999 + } 1.1000 + break; 1.1001 + case certUsageVerifyCA: 1.1002 + case certUsageStatusResponder: 1.1003 + flags = trust.sslFlags; 1.1004 + /* is the cert directly trusted or not trusted ? */ 1.1005 + if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == 1.1006 + ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { 1.1007 + *trusted = PR_TRUE; 1.1008 + return SECSuccess; 1.1009 + } 1.1010 + flags = trust.emailFlags; 1.1011 + /* is the cert directly trusted or not trusted ? */ 1.1012 + if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == 1.1013 + ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { 1.1014 + *trusted = PR_TRUE; 1.1015 + return SECSuccess; 1.1016 + } 1.1017 + flags = trust.objectSigningFlags; 1.1018 + /* is the cert directly trusted or not trusted ? */ 1.1019 + if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == 1.1020 + ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { 1.1021 + *trusted = PR_TRUE; 1.1022 + return SECSuccess; 1.1023 + } 1.1024 + /* fall through to test distrust */ 1.1025 + case certUsageAnyCA: 1.1026 + case certUsageUserCertImport: 1.1027 + /* do we distrust these certs explicitly */ 1.1028 + flags = trust.sslFlags; 1.1029 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.1030 + * authoritative */ 1.1031 + if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) { 1.1032 + *failedFlags = flags; 1.1033 + return SECFailure; 1.1034 + } 1.1035 + } 1.1036 + flags = trust.emailFlags; 1.1037 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.1038 + * authoritative */ 1.1039 + if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) { 1.1040 + *failedFlags = flags; 1.1041 + return SECFailure; 1.1042 + } 1.1043 + } 1.1044 + /* fall through */ 1.1045 + case certUsageProtectedObjectSigner: 1.1046 + flags = trust.objectSigningFlags; 1.1047 + if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is 1.1048 + * authoritative */ 1.1049 + if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) { 1.1050 + *failedFlags = flags; 1.1051 + return SECFailure; 1.1052 + } 1.1053 + } 1.1054 + break; 1.1055 + } 1.1056 + } 1.1057 + return SECSuccess; 1.1058 +} 1.1059 + 1.1060 +/* 1.1061 + * verify a certificate by checking if it's valid and that we 1.1062 + * trust the issuer. 1.1063 + * 1.1064 + * certificateUsage contains a bitfield of all cert usages that are 1.1065 + * required for verification to succeed 1.1066 + * 1.1067 + * a bitfield of cert usages is returned in *returnedUsages 1.1068 + * if requiredUsages is non-zero, the returned bitmap is only 1.1069 + * for those required usages, otherwise it is for all usages 1.1070 + * 1.1071 + */ 1.1072 +SECStatus 1.1073 +CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, 1.1074 + PRBool checkSig, SECCertificateUsage requiredUsages, PRTime t, 1.1075 + void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages) 1.1076 +{ 1.1077 + SECStatus rv; 1.1078 + SECStatus valid; 1.1079 + unsigned int requiredKeyUsage; 1.1080 + unsigned int requiredCertType; 1.1081 + unsigned int flags; 1.1082 + unsigned int certType; 1.1083 + PRBool allowOverride; 1.1084 + SECCertTimeValidity validity; 1.1085 + CERTStatusConfig *statusConfig; 1.1086 + PRInt32 i; 1.1087 + SECCertUsage certUsage = 0; 1.1088 + PRBool checkedOCSP = PR_FALSE; 1.1089 + PRBool checkAllUsages = PR_FALSE; 1.1090 + PRBool revoked = PR_FALSE; 1.1091 + PRBool sigerror = PR_FALSE; 1.1092 + PRBool trusted = PR_FALSE; 1.1093 + 1.1094 + if (!requiredUsages) { 1.1095 + /* there are no required usages, so the user probably wants to 1.1096 + get status for all usages */ 1.1097 + checkAllUsages = PR_TRUE; 1.1098 + } 1.1099 + 1.1100 + if (returnedUsages) { 1.1101 + *returnedUsages = 0; 1.1102 + } else { 1.1103 + /* we don't have a place to return status for all usages, 1.1104 + so we can skip checks for usages that aren't required */ 1.1105 + checkAllUsages = PR_FALSE; 1.1106 + } 1.1107 + valid = SECSuccess ; /* start off assuming cert is valid */ 1.1108 + 1.1109 + /* make sure that the cert is valid at time t */ 1.1110 + allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) || 1.1111 + (requiredUsages & certificateUsageSSLServerWithStepUp)); 1.1112 + validity = CERT_CheckCertValidTimes(cert, t, allowOverride); 1.1113 + if ( validity != secCertTimeValid ) { 1.1114 + valid = SECFailure; 1.1115 + LOG_ERROR_OR_EXIT(log,cert,0,validity); 1.1116 + } 1.1117 + 1.1118 + /* check key usage and netscape cert type */ 1.1119 + cert_GetCertType(cert); 1.1120 + certType = cert->nsCertType; 1.1121 + 1.1122 + for (i=1; i<=certificateUsageHighest && 1.1123 + (SECSuccess == valid || returnedUsages || log) ; ) { 1.1124 + PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE; 1.1125 + if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) { 1.1126 + NEXT_USAGE(); 1.1127 + } 1.1128 + if (returnedUsages) { 1.1129 + *returnedUsages |= i; /* start off assuming this usage is valid */ 1.1130 + } 1.1131 + switch ( certUsage ) { 1.1132 + case certUsageSSLClient: 1.1133 + case certUsageSSLServer: 1.1134 + case certUsageSSLServerWithStepUp: 1.1135 + case certUsageSSLCA: 1.1136 + case certUsageEmailSigner: 1.1137 + case certUsageEmailRecipient: 1.1138 + case certUsageObjectSigner: 1.1139 + case certUsageStatusResponder: 1.1140 + rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, 1.1141 + &requiredKeyUsage, 1.1142 + &requiredCertType); 1.1143 + if ( rv != SECSuccess ) { 1.1144 + PORT_Assert(0); 1.1145 + /* EXIT_IF_NOT_LOGGING(log); XXX ??? */ 1.1146 + requiredKeyUsage = 0; 1.1147 + requiredCertType = 0; 1.1148 + INVALID_USAGE(); 1.1149 + } 1.1150 + break; 1.1151 + 1.1152 + case certUsageAnyCA: 1.1153 + case certUsageProtectedObjectSigner: 1.1154 + case certUsageUserCertImport: 1.1155 + case certUsageVerifyCA: 1.1156 + /* these usages cannot be verified */ 1.1157 + NEXT_USAGE(); 1.1158 + 1.1159 + default: 1.1160 + PORT_Assert(0); 1.1161 + requiredKeyUsage = 0; 1.1162 + requiredCertType = 0; 1.1163 + INVALID_USAGE(); 1.1164 + } 1.1165 + if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { 1.1166 + if (PR_TRUE == requiredUsage) { 1.1167 + PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); 1.1168 + } 1.1169 + LOG_ERROR(log,cert,0,requiredKeyUsage); 1.1170 + INVALID_USAGE(); 1.1171 + } 1.1172 + if ( !( certType & requiredCertType ) ) { 1.1173 + if (PR_TRUE == requiredUsage) { 1.1174 + PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); 1.1175 + } 1.1176 + LOG_ERROR(log,cert,0,requiredCertType); 1.1177 + INVALID_USAGE(); 1.1178 + } 1.1179 + 1.1180 + rv = cert_CheckLeafTrust(cert, certUsage, &flags, &trusted); 1.1181 + if (rv == SECFailure) { 1.1182 + if (PR_TRUE == requiredUsage) { 1.1183 + PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); 1.1184 + } 1.1185 + LOG_ERROR(log, cert, 0, flags); 1.1186 + INVALID_USAGE(); 1.1187 + } else if (trusted) { 1.1188 + VALID_USAGE(); 1.1189 + } 1.1190 + 1.1191 + if (PR_TRUE == revoked || PR_TRUE == sigerror) { 1.1192 + INVALID_USAGE(); 1.1193 + } 1.1194 + 1.1195 + rv = cert_VerifyCertChain(handle, cert, 1.1196 + checkSig, &sigerror, 1.1197 + certUsage, t, wincx, log, 1.1198 + &revoked); 1.1199 + 1.1200 + if (rv != SECSuccess) { 1.1201 + /* EXIT_IF_NOT_LOGGING(log); XXX ???? */ 1.1202 + INVALID_USAGE(); 1.1203 + } 1.1204 + 1.1205 + /* 1.1206 + * Check OCSP revocation status, but only if the cert we are checking 1.1207 + * is not a status responder itself. We only do this in the case 1.1208 + * where we checked the cert chain (above); explicit trust "wins" 1.1209 + * (avoids status checking, just as it avoids CRL checking) by 1.1210 + * bypassing this code. 1.1211 + */ 1.1212 + 1.1213 + if (PR_FALSE == checkedOCSP) { 1.1214 + checkedOCSP = PR_TRUE; /* only check OCSP once */ 1.1215 + statusConfig = CERT_GetStatusConfig(handle); 1.1216 + if (requiredUsages != certificateUsageStatusResponder && 1.1217 + statusConfig != NULL) { 1.1218 + if (statusConfig->statusChecker != NULL) { 1.1219 + rv = (* statusConfig->statusChecker)(handle, cert, 1.1220 + t, wincx); 1.1221 + if (rv != SECSuccess) { 1.1222 + LOG_ERROR(log,cert,0,0); 1.1223 + revoked = PR_TRUE; 1.1224 + INVALID_USAGE(); 1.1225 + } 1.1226 + } 1.1227 + } 1.1228 + } 1.1229 + 1.1230 + NEXT_USAGE(); 1.1231 + } 1.1232 + 1.1233 +loser: 1.1234 + return(valid); 1.1235 +} 1.1236 + 1.1237 +SECStatus 1.1238 +CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert, 1.1239 + PRBool checkSig, SECCertUsage certUsage, PRTime t, 1.1240 + void *wincx, CERTVerifyLog *log) 1.1241 +{ 1.1242 + return cert_VerifyCertWithFlags(handle, cert, checkSig, certUsage, t, 1.1243 + CERT_VERIFYCERT_USE_DEFAULTS, wincx, log); 1.1244 +} 1.1245 + 1.1246 +SECStatus 1.1247 +cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert, 1.1248 + PRBool checkSig, SECCertUsage certUsage, PRTime t, 1.1249 + PRUint32 flags, void *wincx, CERTVerifyLog *log) 1.1250 +{ 1.1251 + SECStatus rv; 1.1252 + unsigned int requiredKeyUsage; 1.1253 + unsigned int requiredCertType; 1.1254 + unsigned int failedFlags; 1.1255 + unsigned int certType; 1.1256 + PRBool trusted; 1.1257 + PRBool allowOverride; 1.1258 + SECCertTimeValidity validity; 1.1259 + CERTStatusConfig *statusConfig; 1.1260 + 1.1261 +#ifdef notdef 1.1262 + /* check if this cert is in the Evil list */ 1.1263 + rv = CERT_CheckForEvilCert(cert); 1.1264 + if ( rv != SECSuccess ) { 1.1265 + PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); 1.1266 + LOG_ERROR_OR_EXIT(log,cert,0,0); 1.1267 + } 1.1268 +#endif 1.1269 + 1.1270 + /* make sure that the cert is valid at time t */ 1.1271 + allowOverride = (PRBool)((certUsage == certUsageSSLServer) || 1.1272 + (certUsage == certUsageSSLServerWithStepUp)); 1.1273 + validity = CERT_CheckCertValidTimes(cert, t, allowOverride); 1.1274 + if ( validity != secCertTimeValid ) { 1.1275 + LOG_ERROR_OR_EXIT(log,cert,0,validity); 1.1276 + } 1.1277 + 1.1278 + /* check key usage and netscape cert type */ 1.1279 + cert_GetCertType(cert); 1.1280 + certType = cert->nsCertType; 1.1281 + switch ( certUsage ) { 1.1282 + case certUsageSSLClient: 1.1283 + case certUsageSSLServer: 1.1284 + case certUsageSSLServerWithStepUp: 1.1285 + case certUsageSSLCA: 1.1286 + case certUsageEmailSigner: 1.1287 + case certUsageEmailRecipient: 1.1288 + case certUsageObjectSigner: 1.1289 + case certUsageStatusResponder: 1.1290 + rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, 1.1291 + &requiredKeyUsage, 1.1292 + &requiredCertType); 1.1293 + if ( rv != SECSuccess ) { 1.1294 + PORT_Assert(0); 1.1295 + EXIT_IF_NOT_LOGGING(log); 1.1296 + requiredKeyUsage = 0; 1.1297 + requiredCertType = 0; 1.1298 + } 1.1299 + break; 1.1300 + case certUsageVerifyCA: 1.1301 + case certUsageAnyCA: 1.1302 + requiredKeyUsage = KU_KEY_CERT_SIGN; 1.1303 + requiredCertType = NS_CERT_TYPE_CA; 1.1304 + if ( ! ( certType & NS_CERT_TYPE_CA ) ) { 1.1305 + certType |= NS_CERT_TYPE_CA; 1.1306 + } 1.1307 + break; 1.1308 + default: 1.1309 + PORT_Assert(0); 1.1310 + EXIT_IF_NOT_LOGGING(log); 1.1311 + requiredKeyUsage = 0; 1.1312 + requiredCertType = 0; 1.1313 + } 1.1314 + if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { 1.1315 + PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); 1.1316 + LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage); 1.1317 + } 1.1318 + if ( !( certType & requiredCertType ) ) { 1.1319 + PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); 1.1320 + LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType); 1.1321 + } 1.1322 + 1.1323 + rv = cert_CheckLeafTrust(cert, certUsage, &failedFlags, &trusted); 1.1324 + if (rv == SECFailure) { 1.1325 + PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); 1.1326 + LOG_ERROR_OR_EXIT(log, cert, 0, failedFlags); 1.1327 + } else if (trusted) { 1.1328 + goto done; 1.1329 + } 1.1330 + 1.1331 + 1.1332 + rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage, 1.1333 + t, wincx, log); 1.1334 + if (rv != SECSuccess) { 1.1335 + EXIT_IF_NOT_LOGGING(log); 1.1336 + } 1.1337 + 1.1338 + /* 1.1339 + * Check revocation status, but only if the cert we are checking is not a 1.1340 + * status responder itself and the caller did not ask us to skip the check. 1.1341 + * We only do this in the case where we checked the cert chain (above); 1.1342 + * explicit trust "wins" (avoids status checking, just as it avoids CRL 1.1343 + * checking, which is all done inside VerifyCertChain) by bypassing this 1.1344 + * code. 1.1345 + */ 1.1346 + if (!(flags & CERT_VERIFYCERT_SKIP_OCSP) && 1.1347 + certUsage != certUsageStatusResponder) { 1.1348 + statusConfig = CERT_GetStatusConfig(handle); 1.1349 + if (statusConfig && statusConfig->statusChecker) { 1.1350 + rv = (* statusConfig->statusChecker)(handle, cert, 1.1351 + t, wincx); 1.1352 + if (rv != SECSuccess) { 1.1353 + LOG_ERROR_OR_EXIT(log,cert,0,0); 1.1354 + } 1.1355 + } 1.1356 + } 1.1357 + 1.1358 +done: 1.1359 + if (log && log->head) { 1.1360 + return SECFailure; 1.1361 + } 1.1362 + return(SECSuccess); 1.1363 + 1.1364 +loser: 1.1365 + rv = SECFailure; 1.1366 + 1.1367 + return(rv); 1.1368 +} 1.1369 + 1.1370 +/* 1.1371 + * verify a certificate by checking if its valid and that we 1.1372 + * trust the issuer. Verify time against now. 1.1373 + */ 1.1374 +SECStatus 1.1375 +CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert, 1.1376 + PRBool checkSig, SECCertificateUsage requiredUsages, 1.1377 + void *wincx, SECCertificateUsage* returnedUsages) 1.1378 +{ 1.1379 + return(CERT_VerifyCertificate(handle, cert, checkSig, 1.1380 + requiredUsages, PR_Now(), wincx, NULL, returnedUsages)); 1.1381 +} 1.1382 + 1.1383 +/* obsolete, do not use for new code */ 1.1384 +SECStatus 1.1385 +CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert, 1.1386 + PRBool checkSig, SECCertUsage certUsage, void *wincx) 1.1387 +{ 1.1388 + return(CERT_VerifyCert(handle, cert, checkSig, 1.1389 + certUsage, PR_Now(), wincx, NULL)); 1.1390 +} 1.1391 + 1.1392 + 1.1393 +/* [ FROM pcertdb.c ] */ 1.1394 +/* 1.1395 + * Supported usage values and types: 1.1396 + * certUsageSSLClient 1.1397 + * certUsageSSLServer 1.1398 + * certUsageSSLServerWithStepUp 1.1399 + * certUsageEmailSigner 1.1400 + * certUsageEmailRecipient 1.1401 + * certUsageObjectSigner 1.1402 + */ 1.1403 + 1.1404 +CERTCertificate * 1.1405 +CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName, 1.1406 + CERTCertOwner owner, SECCertUsage usage, 1.1407 + PRBool preferTrusted, PRTime validTime, PRBool validOnly) 1.1408 +{ 1.1409 + CERTCertList *certList = NULL; 1.1410 + CERTCertificate *cert = NULL; 1.1411 + CERTCertTrust certTrust; 1.1412 + unsigned int requiredTrustFlags; 1.1413 + SECTrustType requiredTrustType; 1.1414 + unsigned int flags; 1.1415 + 1.1416 + PRBool lookingForCA = PR_FALSE; 1.1417 + SECStatus rv; 1.1418 + CERTCertListNode *node; 1.1419 + CERTCertificate *saveUntrustedCA = NULL; 1.1420 + 1.1421 + /* if preferTrusted is set, must be a CA cert */ 1.1422 + PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) ); 1.1423 + 1.1424 + if ( owner == certOwnerCA ) { 1.1425 + lookingForCA = PR_TRUE; 1.1426 + if ( preferTrusted ) { 1.1427 + rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags, 1.1428 + &requiredTrustType); 1.1429 + if ( rv != SECSuccess ) { 1.1430 + goto loser; 1.1431 + } 1.1432 + requiredTrustFlags |= CERTDB_VALID_CA; 1.1433 + } 1.1434 + } 1.1435 + 1.1436 + certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime, 1.1437 + validOnly); 1.1438 + if ( certList != NULL ) { 1.1439 + rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA); 1.1440 + if ( rv != SECSuccess ) { 1.1441 + goto loser; 1.1442 + } 1.1443 + 1.1444 + node = CERT_LIST_HEAD(certList); 1.1445 + 1.1446 + while ( !CERT_LIST_END(node, certList) ) { 1.1447 + cert = node->cert; 1.1448 + 1.1449 + /* looking for a trusted CA cert */ 1.1450 + if ( ( owner == certOwnerCA ) && preferTrusted && 1.1451 + ( requiredTrustType != trustTypeNone ) ) { 1.1452 + 1.1453 + if ( CERT_GetCertTrust(cert, &certTrust) != SECSuccess ) { 1.1454 + flags = 0; 1.1455 + } else { 1.1456 + flags = SEC_GET_TRUST_FLAGS(&certTrust, requiredTrustType); 1.1457 + } 1.1458 + 1.1459 + if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) { 1.1460 + /* cert is not trusted */ 1.1461 + /* if this is the first cert to get this far, then save 1.1462 + * it, so we can use it if we can't find a trusted one 1.1463 + */ 1.1464 + if ( saveUntrustedCA == NULL ) { 1.1465 + saveUntrustedCA = cert; 1.1466 + } 1.1467 + goto endloop; 1.1468 + } 1.1469 + } 1.1470 + /* if we got this far, then this cert meets all criteria */ 1.1471 + break; 1.1472 + 1.1473 +endloop: 1.1474 + node = CERT_LIST_NEXT(node); 1.1475 + cert = NULL; 1.1476 + } 1.1477 + 1.1478 + /* use the saved one if we have it */ 1.1479 + if ( cert == NULL ) { 1.1480 + cert = saveUntrustedCA; 1.1481 + } 1.1482 + 1.1483 + /* if we found one then bump the ref count before freeing the list */ 1.1484 + if ( cert != NULL ) { 1.1485 + /* bump the ref count */ 1.1486 + cert = CERT_DupCertificate(cert); 1.1487 + } 1.1488 + 1.1489 + CERT_DestroyCertList(certList); 1.1490 + } 1.1491 + 1.1492 + return(cert); 1.1493 + 1.1494 +loser: 1.1495 + if ( certList != NULL ) { 1.1496 + CERT_DestroyCertList(certList); 1.1497 + } 1.1498 + 1.1499 + return(NULL); 1.1500 +} 1.1501 + 1.1502 + 1.1503 +/* [ From certdb.c ] */ 1.1504 +/* 1.1505 + * Filter a list of certificates, removing those certs that do not have 1.1506 + * one of the named CA certs somewhere in their cert chain. 1.1507 + * 1.1508 + * "certList" - the list of certificates to filter 1.1509 + * "nCANames" - number of CA names 1.1510 + * "caNames" - array of CA names in string(rfc 1485) form 1.1511 + * "usage" - what use the certs are for, this is used when 1.1512 + * selecting CA certs 1.1513 + */ 1.1514 +SECStatus 1.1515 +CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames, 1.1516 + char **caNames, SECCertUsage usage) 1.1517 +{ 1.1518 + CERTCertificate *issuerCert = NULL; 1.1519 + CERTCertificate *subjectCert; 1.1520 + CERTCertListNode *node, *freenode; 1.1521 + CERTCertificate *cert; 1.1522 + int n; 1.1523 + char **names; 1.1524 + PRBool found; 1.1525 + PRTime time; 1.1526 + 1.1527 + if ( nCANames <= 0 ) { 1.1528 + return(SECSuccess); 1.1529 + } 1.1530 + 1.1531 + time = PR_Now(); 1.1532 + 1.1533 + node = CERT_LIST_HEAD(certList); 1.1534 + 1.1535 + while ( ! CERT_LIST_END(node, certList) ) { 1.1536 + cert = node->cert; 1.1537 + 1.1538 + subjectCert = CERT_DupCertificate(cert); 1.1539 + 1.1540 + /* traverse the CA certs for this cert */ 1.1541 + found = PR_FALSE; 1.1542 + while ( subjectCert != NULL ) { 1.1543 + n = nCANames; 1.1544 + names = caNames; 1.1545 + 1.1546 + if (subjectCert->issuerName != NULL) { 1.1547 + while ( n > 0 ) { 1.1548 + if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) { 1.1549 + found = PR_TRUE; 1.1550 + break; 1.1551 + } 1.1552 + 1.1553 + n--; 1.1554 + names++; 1.1555 + } 1.1556 + } 1.1557 + 1.1558 + if ( found ) { 1.1559 + break; 1.1560 + } 1.1561 + 1.1562 + issuerCert = CERT_FindCertIssuer(subjectCert, time, usage); 1.1563 + if ( issuerCert == subjectCert ) { 1.1564 + CERT_DestroyCertificate(issuerCert); 1.1565 + issuerCert = NULL; 1.1566 + break; 1.1567 + } 1.1568 + CERT_DestroyCertificate(subjectCert); 1.1569 + subjectCert = issuerCert; 1.1570 + 1.1571 + } 1.1572 + CERT_DestroyCertificate(subjectCert); 1.1573 + if ( !found ) { 1.1574 + /* CA was not found, so remove this cert from the list */ 1.1575 + freenode = node; 1.1576 + node = CERT_LIST_NEXT(node); 1.1577 + CERT_RemoveCertListNode(freenode); 1.1578 + } else { 1.1579 + /* CA was found, so leave it in the list */ 1.1580 + node = CERT_LIST_NEXT(node); 1.1581 + } 1.1582 + } 1.1583 + 1.1584 + return(SECSuccess); 1.1585 +} 1.1586 + 1.1587 +/* 1.1588 + * Given a certificate, return a string containing the nickname, and possibly 1.1589 + * one of the validity strings, based on the current validity state of the 1.1590 + * certificate. 1.1591 + * 1.1592 + * "arena" - arena to allocate returned string from. If NULL, then heap 1.1593 + * is used. 1.1594 + * "cert" - the cert to get nickname from 1.1595 + * "expiredString" - the string to append to the nickname if the cert is 1.1596 + * expired. 1.1597 + * "notYetGoodString" - the string to append to the nickname if the cert is 1.1598 + * not yet good. 1.1599 + */ 1.1600 +char * 1.1601 +CERT_GetCertNicknameWithValidity(PLArenaPool *arena, CERTCertificate *cert, 1.1602 + char *expiredString, char *notYetGoodString) 1.1603 +{ 1.1604 + SECCertTimeValidity validity; 1.1605 + char *nickname = NULL, *tmpstr = NULL; 1.1606 + 1.1607 + validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE); 1.1608 + 1.1609 + /* if the cert is good, then just use the nickname directly */ 1.1610 + if ( validity == secCertTimeValid ) { 1.1611 + if ( arena == NULL ) { 1.1612 + nickname = PORT_Strdup(cert->nickname); 1.1613 + } else { 1.1614 + nickname = PORT_ArenaStrdup(arena, cert->nickname); 1.1615 + } 1.1616 + 1.1617 + if ( nickname == NULL ) { 1.1618 + goto loser; 1.1619 + } 1.1620 + } else { 1.1621 + 1.1622 + /* if the cert is not valid, then tack one of the strings on the 1.1623 + * end 1.1624 + */ 1.1625 + if ( validity == secCertTimeExpired ) { 1.1626 + tmpstr = PR_smprintf("%s%s", cert->nickname, 1.1627 + expiredString); 1.1628 + } else if ( validity == secCertTimeNotValidYet ) { 1.1629 + /* not yet valid */ 1.1630 + tmpstr = PR_smprintf("%s%s", cert->nickname, 1.1631 + notYetGoodString); 1.1632 + } else { 1.1633 + /* undetermined */ 1.1634 + tmpstr = PR_smprintf("%s", 1.1635 + "(NULL) (Validity Unknown)"); 1.1636 + } 1.1637 + 1.1638 + if ( tmpstr == NULL ) { 1.1639 + goto loser; 1.1640 + } 1.1641 + 1.1642 + if ( arena ) { 1.1643 + /* copy the string into the arena and free the malloc'd one */ 1.1644 + nickname = PORT_ArenaStrdup(arena, tmpstr); 1.1645 + PORT_Free(tmpstr); 1.1646 + } else { 1.1647 + nickname = tmpstr; 1.1648 + } 1.1649 + if ( nickname == NULL ) { 1.1650 + goto loser; 1.1651 + } 1.1652 + } 1.1653 + return(nickname); 1.1654 + 1.1655 +loser: 1.1656 + return(NULL); 1.1657 +} 1.1658 + 1.1659 +/* 1.1660 + * Collect the nicknames from all certs in a CertList. If the cert is not 1.1661 + * valid, append a string to that nickname. 1.1662 + * 1.1663 + * "certList" - the list of certificates 1.1664 + * "expiredString" - the string to append to the nickname of any expired cert 1.1665 + * "notYetGoodString" - the string to append to the nickname of any cert 1.1666 + * that is not yet valid 1.1667 + */ 1.1668 +CERTCertNicknames * 1.1669 +CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString, 1.1670 + char *notYetGoodString) 1.1671 +{ 1.1672 + CERTCertNicknames *names; 1.1673 + PLArenaPool *arena; 1.1674 + CERTCertListNode *node; 1.1675 + char **nn; 1.1676 + 1.1677 + /* allocate an arena */ 1.1678 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1679 + if ( arena == NULL ) { 1.1680 + return(NULL); 1.1681 + } 1.1682 + 1.1683 + /* allocate the structure */ 1.1684 + names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); 1.1685 + if ( names == NULL ) { 1.1686 + goto loser; 1.1687 + } 1.1688 + 1.1689 + /* init the structure */ 1.1690 + names->arena = arena; 1.1691 + names->head = NULL; 1.1692 + names->numnicknames = 0; 1.1693 + names->nicknames = NULL; 1.1694 + names->totallen = 0; 1.1695 + 1.1696 + /* count the certs in the list */ 1.1697 + node = CERT_LIST_HEAD(certList); 1.1698 + while ( ! CERT_LIST_END(node, certList) ) { 1.1699 + names->numnicknames++; 1.1700 + node = CERT_LIST_NEXT(node); 1.1701 + } 1.1702 + 1.1703 + /* allocate nicknames array */ 1.1704 + names->nicknames = PORT_ArenaAlloc(arena, 1.1705 + sizeof(char *) * names->numnicknames); 1.1706 + if ( names->nicknames == NULL ) { 1.1707 + goto loser; 1.1708 + } 1.1709 + 1.1710 + /* just in case printf can't deal with null strings */ 1.1711 + if (expiredString == NULL ) { 1.1712 + expiredString = ""; 1.1713 + } 1.1714 + 1.1715 + if ( notYetGoodString == NULL ) { 1.1716 + notYetGoodString = ""; 1.1717 + } 1.1718 + 1.1719 + /* traverse the list of certs and collect the nicknames */ 1.1720 + nn = names->nicknames; 1.1721 + node = CERT_LIST_HEAD(certList); 1.1722 + while ( ! CERT_LIST_END(node, certList) ) { 1.1723 + *nn = CERT_GetCertNicknameWithValidity(arena, node->cert, 1.1724 + expiredString, 1.1725 + notYetGoodString); 1.1726 + if ( *nn == NULL ) { 1.1727 + goto loser; 1.1728 + } 1.1729 + 1.1730 + names->totallen += PORT_Strlen(*nn); 1.1731 + 1.1732 + nn++; 1.1733 + node = CERT_LIST_NEXT(node); 1.1734 + } 1.1735 + 1.1736 + return(names); 1.1737 + 1.1738 +loser: 1.1739 + PORT_FreeArena(arena, PR_FALSE); 1.1740 + return(NULL); 1.1741 +} 1.1742 + 1.1743 +/* 1.1744 + * Extract the nickname from a nickmake string that may have either 1.1745 + * expiredString or notYetGoodString appended. 1.1746 + * 1.1747 + * Args: 1.1748 + * "namestring" - the string containing the nickname, and possibly 1.1749 + * one of the validity label strings 1.1750 + * "expiredString" - the expired validity label string 1.1751 + * "notYetGoodString" - the not yet good validity label string 1.1752 + * 1.1753 + * Returns the raw nickname 1.1754 + */ 1.1755 +char * 1.1756 +CERT_ExtractNicknameString(char *namestring, char *expiredString, 1.1757 + char *notYetGoodString) 1.1758 +{ 1.1759 + int explen, nyglen, namelen; 1.1760 + int retlen; 1.1761 + char *retstr; 1.1762 + 1.1763 + namelen = PORT_Strlen(namestring); 1.1764 + explen = PORT_Strlen(expiredString); 1.1765 + nyglen = PORT_Strlen(notYetGoodString); 1.1766 + 1.1767 + if ( namelen > explen ) { 1.1768 + if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) { 1.1769 + retlen = namelen - explen; 1.1770 + retstr = (char *)PORT_Alloc(retlen+1); 1.1771 + if ( retstr == NULL ) { 1.1772 + goto loser; 1.1773 + } 1.1774 + 1.1775 + PORT_Memcpy(retstr, namestring, retlen); 1.1776 + retstr[retlen] = '\0'; 1.1777 + goto done; 1.1778 + } 1.1779 + } 1.1780 + 1.1781 + if ( namelen > nyglen ) { 1.1782 + if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) { 1.1783 + retlen = namelen - nyglen; 1.1784 + retstr = (char *)PORT_Alloc(retlen+1); 1.1785 + if ( retstr == NULL ) { 1.1786 + goto loser; 1.1787 + } 1.1788 + 1.1789 + PORT_Memcpy(retstr, namestring, retlen); 1.1790 + retstr[retlen] = '\0'; 1.1791 + goto done; 1.1792 + } 1.1793 + } 1.1794 + 1.1795 + /* if name string is shorter than either invalid string, then it must 1.1796 + * be a raw nickname 1.1797 + */ 1.1798 + retstr = PORT_Strdup(namestring); 1.1799 + 1.1800 +done: 1.1801 + return(retstr); 1.1802 + 1.1803 +loser: 1.1804 + return(NULL); 1.1805 +} 1.1806 + 1.1807 +CERTCertList * 1.1808 +CERT_GetCertChainFromCert(CERTCertificate *cert, PRTime time, SECCertUsage usage) 1.1809 +{ 1.1810 + CERTCertList *chain = NULL; 1.1811 + int count = 0; 1.1812 + 1.1813 + if (NULL == cert) { 1.1814 + return NULL; 1.1815 + } 1.1816 + 1.1817 + cert = CERT_DupCertificate(cert); 1.1818 + if (NULL == cert) { 1.1819 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1820 + return NULL; 1.1821 + } 1.1822 + 1.1823 + chain = CERT_NewCertList(); 1.1824 + if (NULL == chain) { 1.1825 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1826 + return NULL; 1.1827 + } 1.1828 + 1.1829 + while (cert != NULL && ++count <= CERT_MAX_CERT_CHAIN) { 1.1830 + if (SECSuccess != CERT_AddCertToListTail(chain, cert)) { 1.1831 + /* return partial chain */ 1.1832 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1833 + return chain; 1.1834 + } 1.1835 + 1.1836 + if (cert->isRoot) { 1.1837 + /* return complete chain */ 1.1838 + return chain; 1.1839 + } 1.1840 + 1.1841 + cert = CERT_FindCertIssuer(cert, time, usage); 1.1842 + } 1.1843 + 1.1844 + /* return partial chain */ 1.1845 + PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); 1.1846 + return chain; 1.1847 +}