michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "nspr.h" michael@0: #include "secerr.h" michael@0: #include "secport.h" michael@0: #include "seccomon.h" michael@0: #include "secoid.h" michael@0: #include "sslerr.h" michael@0: #include "genname.h" michael@0: #include "keyhi.h" michael@0: #include "cert.h" michael@0: #include "certdb.h" michael@0: #include "certi.h" michael@0: #include "cryptohi.h" michael@0: #include "pkix.h" michael@0: /*#include "pkix_sample_modules.h" */ michael@0: #include "pkix_pl_cert.h" michael@0: michael@0: michael@0: #include "nsspki.h" michael@0: #include "pkitm.h" michael@0: #include "pkim.h" michael@0: #include "pki3hack.h" michael@0: #include "base.h" michael@0: michael@0: /* michael@0: * Check the validity times of a certificate michael@0: */ michael@0: SECStatus michael@0: CERT_CertTimesValid(CERTCertificate *c) michael@0: { michael@0: SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE); michael@0: return (valid == secCertTimeValid) ? SECSuccess : SECFailure; michael@0: } michael@0: michael@0: /* michael@0: * verify the signature of a signed data object with the given DER publickey michael@0: */ michael@0: SECStatus michael@0: CERT_VerifySignedDataWithPublicKey(const CERTSignedData *sd, michael@0: SECKEYPublicKey *pubKey, michael@0: void *wincx) michael@0: { michael@0: SECStatus rv; michael@0: SECItem sig; michael@0: SECOidTag hashAlg = SEC_OID_UNKNOWN; michael@0: michael@0: if ( !pubKey || !sd ) { michael@0: PORT_SetError(PR_INVALID_ARGUMENT_ERROR); michael@0: return SECFailure; michael@0: } michael@0: michael@0: /* check the signature */ michael@0: sig = sd->signature; michael@0: /* convert sig->len from bit counts to byte count. */ michael@0: DER_ConvertBitString(&sig); michael@0: michael@0: rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, michael@0: &sig, &sd->signatureAlgorithm, &hashAlg, wincx); michael@0: if (rv == SECSuccess) { michael@0: /* Are we honoring signatures for this algorithm? */ michael@0: PRUint32 policyFlags = 0; michael@0: rv = NSS_GetAlgorithmPolicy(hashAlg, &policyFlags); michael@0: if (rv == SECSuccess && michael@0: !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) { michael@0: PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); michael@0: rv = SECFailure; michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: * verify the signature of a signed data object with the given DER publickey michael@0: */ michael@0: SECStatus michael@0: CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd, michael@0: CERTSubjectPublicKeyInfo *pubKeyInfo, michael@0: void *wincx) michael@0: { michael@0: SECKEYPublicKey *pubKey; michael@0: SECStatus rv = SECFailure; michael@0: michael@0: /* get cert's public key */ michael@0: pubKey = SECKEY_ExtractPublicKey(pubKeyInfo); michael@0: if (pubKey) { michael@0: rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); michael@0: SECKEY_DestroyPublicKey(pubKey); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: * verify the signature of a signed data object with the given certificate michael@0: */ michael@0: SECStatus michael@0: CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert, michael@0: PRTime t, void *wincx) michael@0: { michael@0: SECKEYPublicKey *pubKey = 0; michael@0: SECStatus rv = SECFailure; michael@0: SECCertTimeValidity validity; michael@0: michael@0: /* check the certificate's validity */ michael@0: validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE); michael@0: if ( validity != secCertTimeValid ) { michael@0: return rv; michael@0: } michael@0: michael@0: /* get cert's public key */ michael@0: pubKey = CERT_ExtractPublicKey(cert); michael@0: if (pubKey) { michael@0: rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); michael@0: SECKEY_DestroyPublicKey(pubKey); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: SECStatus michael@0: SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert, michael@0: CERTCertificate *caCert, PRTime t, void * wincx) michael@0: { michael@0: return CERT_CheckCRL(cert, caCert, NULL, t, wincx); michael@0: } michael@0: michael@0: /* michael@0: * Find the issuer of a cert. Use the authorityKeyID if it exists. michael@0: */ michael@0: CERTCertificate * michael@0: CERT_FindCertIssuer(CERTCertificate *cert, PRTime validTime, SECCertUsage usage) michael@0: { michael@0: NSSCertificate *me; michael@0: NSSTime *nssTime; michael@0: NSSTrustDomain *td; michael@0: NSSCryptoContext *cc; michael@0: NSSCertificate *chain[3]; michael@0: NSSUsage nssUsage; michael@0: PRStatus status; michael@0: michael@0: me = STAN_GetNSSCertificate(cert); michael@0: if (!me) { michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return NULL; michael@0: } michael@0: nssTime = NSSTime_SetPRTime(NULL, validTime); michael@0: nssUsage.anyUsage = PR_FALSE; michael@0: nssUsage.nss3usage = usage; michael@0: nssUsage.nss3lookingForCA = PR_TRUE; michael@0: memset(chain, 0, 3*sizeof(NSSCertificate *)); michael@0: td = STAN_GetDefaultTrustDomain(); michael@0: cc = STAN_GetDefaultCryptoContext(); michael@0: (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL, michael@0: chain, 2, NULL, &status, td, cc); michael@0: nss_ZFreeIf(nssTime); michael@0: if (status == PR_SUCCESS) { michael@0: PORT_Assert(me == chain[0]); michael@0: /* if it's a root, the chain will only have one cert */ michael@0: if (!chain[1]) { michael@0: /* already has a reference from the call to BuildChain */ michael@0: return cert; michael@0: } michael@0: NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ michael@0: return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */ michael@0: } michael@0: if (chain[0]) { michael@0: PORT_Assert(me == chain[0]); michael@0: NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ michael@0: } michael@0: PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); michael@0: return NULL; michael@0: } michael@0: michael@0: /* michael@0: * return required trust flags for various cert usages for CAs michael@0: */ michael@0: SECStatus michael@0: CERT_TrustFlagsForCACertUsage(SECCertUsage usage, michael@0: unsigned int *retFlags, michael@0: SECTrustType *retTrustType) michael@0: { michael@0: unsigned int requiredFlags; michael@0: SECTrustType trustType; michael@0: michael@0: switch ( usage ) { michael@0: case certUsageSSLClient: michael@0: requiredFlags = CERTDB_TRUSTED_CLIENT_CA; michael@0: trustType = trustSSL; michael@0: break; michael@0: case certUsageSSLServer: michael@0: case certUsageSSLCA: michael@0: requiredFlags = CERTDB_TRUSTED_CA; michael@0: trustType = trustSSL; michael@0: break; michael@0: case certUsageSSLServerWithStepUp: michael@0: requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA; michael@0: trustType = trustSSL; michael@0: break; michael@0: case certUsageEmailSigner: michael@0: case certUsageEmailRecipient: michael@0: requiredFlags = CERTDB_TRUSTED_CA; michael@0: trustType = trustEmail; michael@0: break; michael@0: case certUsageObjectSigner: michael@0: requiredFlags = CERTDB_TRUSTED_CA; michael@0: trustType = trustObjectSigning; michael@0: break; michael@0: case certUsageVerifyCA: michael@0: case certUsageAnyCA: michael@0: case certUsageStatusResponder: michael@0: requiredFlags = CERTDB_TRUSTED_CA; michael@0: trustType = trustTypeNone; michael@0: break; michael@0: default: michael@0: PORT_Assert(0); michael@0: goto loser; michael@0: } michael@0: if ( retFlags != NULL ) { michael@0: *retFlags = requiredFlags; michael@0: } michael@0: if ( retTrustType != NULL ) { michael@0: *retTrustType = trustType; michael@0: } michael@0: michael@0: return(SECSuccess); michael@0: loser: michael@0: return(SECFailure); michael@0: } michael@0: michael@0: void michael@0: cert_AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, long error, michael@0: unsigned int depth, void *arg) michael@0: { michael@0: CERTVerifyLogNode *node, *tnode; michael@0: michael@0: PORT_Assert(log != NULL); michael@0: michael@0: node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena, michael@0: sizeof(CERTVerifyLogNode)); michael@0: if ( node != NULL ) { michael@0: node->cert = CERT_DupCertificate(cert); michael@0: node->error = error; michael@0: node->depth = depth; michael@0: node->arg = arg; michael@0: michael@0: if ( log->tail == NULL ) { michael@0: /* empty list */ michael@0: log->head = log->tail = node; michael@0: node->prev = NULL; michael@0: node->next = NULL; michael@0: } else if ( depth >= log->tail->depth ) { michael@0: /* add to tail */ michael@0: node->prev = log->tail; michael@0: log->tail->next = node; michael@0: log->tail = node; michael@0: node->next = NULL; michael@0: } else if ( depth < log->head->depth ) { michael@0: /* add at head */ michael@0: node->prev = NULL; michael@0: node->next = log->head; michael@0: log->head->prev = node; michael@0: log->head = node; michael@0: } else { michael@0: /* add in middle */ michael@0: tnode = log->tail; michael@0: while ( tnode != NULL ) { michael@0: if ( depth >= tnode->depth ) { michael@0: /* insert after tnode */ michael@0: node->prev = tnode; michael@0: node->next = tnode->next; michael@0: tnode->next->prev = node; michael@0: tnode->next = node; michael@0: break; michael@0: } michael@0: michael@0: tnode = tnode->prev; michael@0: } michael@0: } michael@0: michael@0: log->count++; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: #define EXIT_IF_NOT_LOGGING(log) \ michael@0: if ( log == NULL ) { \ michael@0: goto loser; \ michael@0: } michael@0: michael@0: #define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \ michael@0: if ( log != NULL ) { \ michael@0: cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \ michael@0: (void *)(PRWord)arg); \ michael@0: } else { \ michael@0: goto loser; \ michael@0: } michael@0: michael@0: #define LOG_ERROR(log,cert,depth,arg) \ michael@0: if ( log != NULL ) { \ michael@0: cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \ michael@0: (void *)(PRWord)arg); \ michael@0: } michael@0: michael@0: static SECStatus michael@0: cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, PRBool* sigerror, michael@0: SECCertUsage certUsage, PRTime t, void *wincx, michael@0: CERTVerifyLog *log, PRBool* revoked) michael@0: { michael@0: SECTrustType trustType; michael@0: CERTBasicConstraints basicConstraint; michael@0: CERTCertificate *issuerCert = NULL; michael@0: CERTCertificate *subjectCert = NULL; michael@0: CERTCertificate *badCert = NULL; michael@0: PRBool isca; michael@0: SECStatus rv; michael@0: SECStatus rvFinal = SECSuccess; michael@0: int count; michael@0: int currentPathLen = 0; michael@0: int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; michael@0: unsigned int caCertType; michael@0: unsigned int requiredCAKeyUsage; michael@0: unsigned int requiredFlags; michael@0: PLArenaPool *arena = NULL; michael@0: CERTGeneralName *namesList = NULL; michael@0: CERTCertificate **certsList = NULL; michael@0: int certsListLen = 16; michael@0: int namesCount = 0; michael@0: PRBool subjectCertIsSelfIssued; michael@0: CERTCertTrust issuerTrust; michael@0: michael@0: if (revoked) { michael@0: *revoked = PR_FALSE; michael@0: } michael@0: michael@0: if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, michael@0: &requiredCAKeyUsage, michael@0: &caCertType) michael@0: != SECSuccess ) { michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredCAKeyUsage = 0; michael@0: caCertType = 0; michael@0: } michael@0: michael@0: switch ( certUsage ) { michael@0: case certUsageSSLClient: michael@0: case certUsageSSLServer: michael@0: case certUsageSSLCA: michael@0: case certUsageSSLServerWithStepUp: michael@0: case certUsageEmailSigner: michael@0: case certUsageEmailRecipient: michael@0: case certUsageObjectSigner: michael@0: case certUsageVerifyCA: michael@0: case certUsageAnyCA: michael@0: case certUsageStatusResponder: michael@0: if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, michael@0: &trustType) != SECSuccess ) { michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: /* XXX continuing with requiredFlags = 0 seems wrong. It'll michael@0: * cause the following test to be true incorrectly: michael@0: * flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType); michael@0: * if (( flags & requiredFlags ) == requiredFlags) { michael@0: * rv = rvFinal; michael@0: * goto done; michael@0: * } michael@0: * There are three other instances of this problem. michael@0: */ michael@0: requiredFlags = 0; michael@0: trustType = trustSSL; michael@0: } michael@0: break; michael@0: default: michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredFlags = 0; michael@0: trustType = trustSSL;/* This used to be 0, but we need something michael@0: * that matches the enumeration type. michael@0: */ michael@0: caCertType = 0; michael@0: } michael@0: michael@0: subjectCert = CERT_DupCertificate(cert); michael@0: if ( subjectCert == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) { michael@0: goto loser; michael@0: } michael@0: michael@0: certsList = PORT_ZNewArray(CERTCertificate *, certsListLen); michael@0: if (certsList == NULL) michael@0: goto loser; michael@0: michael@0: /* RFC 3280 says that the name constraints will apply to the names michael@0: ** in the leaf (EE) cert, whether it is self issued or not, so michael@0: ** we pretend that it is not. michael@0: */ michael@0: subjectCertIsSelfIssued = PR_FALSE; michael@0: for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) { michael@0: PRBool validCAOverride = PR_FALSE; michael@0: michael@0: /* Construct a list of names for the current and all previous michael@0: * certifcates (except leaf (EE) certs, root CAs, and self-issued michael@0: * intermediate CAs) to be verified against the name constraints michael@0: * extension of the issuer certificate. michael@0: */ michael@0: if (subjectCertIsSelfIssued == PR_FALSE) { michael@0: CERTGeneralName *subjectNameList; michael@0: int subjectNameListLen; michael@0: int i; michael@0: PRBool getSubjectCN = (!count && certUsage == certUsageSSLServer); michael@0: subjectNameList = michael@0: CERT_GetConstrainedCertificateNames(subjectCert, arena, michael@0: getSubjectCN); michael@0: if (!subjectNameList) michael@0: goto loser; michael@0: subjectNameListLen = CERT_GetNamesLength(subjectNameList); michael@0: if (!subjectNameListLen) michael@0: goto loser; michael@0: if (certsListLen <= namesCount + subjectNameListLen) { michael@0: CERTCertificate **tmpCertsList; michael@0: certsListLen = (namesCount + subjectNameListLen) * 2; michael@0: tmpCertsList = michael@0: (CERTCertificate **)PORT_Realloc(certsList, michael@0: certsListLen * sizeof(CERTCertificate *)); michael@0: if (tmpCertsList == NULL) { michael@0: goto loser; michael@0: } michael@0: certsList = tmpCertsList; michael@0: } michael@0: for (i = 0; i < subjectNameListLen; i++) { michael@0: certsList[namesCount + i] = subjectCert; michael@0: } michael@0: namesCount += subjectNameListLen; michael@0: namesList = cert_CombineNamesLists(namesList, subjectNameList); michael@0: } michael@0: michael@0: /* check if the cert has an unsupported critical extension */ michael@0: if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) { michael@0: PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); michael@0: LOG_ERROR_OR_EXIT(log,subjectCert,count,0); michael@0: } michael@0: michael@0: /* find the certificate of the issuer */ michael@0: issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage); michael@0: if ( ! issuerCert ) { michael@0: PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); michael@0: LOG_ERROR(log,subjectCert,count,0); michael@0: goto loser; michael@0: } michael@0: michael@0: /* verify the signature on the cert */ michael@0: if ( checkSig ) { michael@0: rv = CERT_VerifySignedData(&subjectCert->signatureWrap, michael@0: issuerCert, t, wincx); michael@0: michael@0: if ( rv != SECSuccess ) { michael@0: if (sigerror) { michael@0: *sigerror = PR_TRUE; michael@0: } michael@0: if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) { michael@0: PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE); michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); michael@0: } else { michael@0: if (PORT_GetError() != michael@0: SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) { michael@0: PORT_SetError(SEC_ERROR_BAD_SIGNATURE); michael@0: } michael@0: LOG_ERROR_OR_EXIT(log,subjectCert,count,0); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* If the basicConstraint extension is included in an immediate CA michael@0: * certificate, make sure that the isCA flag is on. If the michael@0: * pathLenConstraint component exists, it must be greater than the michael@0: * number of CA certificates we have seen so far. If the extension michael@0: * is omitted, we will assume that this is a CA certificate with michael@0: * an unlimited pathLenConstraint (since it already passes the michael@0: * netscape-cert-type extension checking). michael@0: */ michael@0: michael@0: rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint); michael@0: if ( rv != SECSuccess ) { michael@0: if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); michael@0: } michael@0: pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; michael@0: /* no basic constraints found, we aren't (yet) a CA. */ michael@0: isca = PR_FALSE; michael@0: } else { michael@0: if ( basicConstraint.isCA == PR_FALSE ) { michael@0: PORT_SetError (SEC_ERROR_CA_CERT_INVALID); michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); michael@0: } michael@0: pathLengthLimit = basicConstraint.pathLenConstraint; michael@0: isca = PR_TRUE; michael@0: } michael@0: /* make sure that the path len constraint is properly set.*/ michael@0: if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) { michael@0: PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); michael@0: LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit); michael@0: } michael@0: michael@0: /* make sure that the entire chain is within the name space of the michael@0: * current issuer certificate. michael@0: */ michael@0: rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, michael@0: arena, &badCert); michael@0: if (rv != SECSuccess || badCert != NULL) { michael@0: PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE); michael@0: LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0); michael@0: goto loser; michael@0: } michael@0: michael@0: /* XXX - the error logging may need to go down into CRL stuff at some michael@0: * point michael@0: */ michael@0: /* check revoked list (issuer) */ michael@0: rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx); michael@0: if (rv == SECFailure) { michael@0: if (revoked) { michael@0: *revoked = PR_TRUE; michael@0: } michael@0: LOG_ERROR_OR_EXIT(log,subjectCert,count,0); michael@0: } else if (rv == SECWouldBlock) { michael@0: /* We found something fishy, so we intend to issue an michael@0: * error to the user, but the user may wish to continue michael@0: * processing, in which case we better make sure nothing michael@0: * worse has happened... so keep cranking the loop */ michael@0: rvFinal = SECFailure; michael@0: if (revoked) { michael@0: *revoked = PR_TRUE; michael@0: } michael@0: LOG_ERROR(log,subjectCert,count,0); michael@0: } michael@0: michael@0: if ( CERT_GetCertTrust(issuerCert, &issuerTrust) == SECSuccess) { michael@0: /* we have some trust info, but this does NOT imply that this michael@0: * cert is actually trusted for any purpose. The cert may be michael@0: * explicitly UNtrusted. We won't know until we examine the michael@0: * trust bits. michael@0: */ michael@0: unsigned int flags; michael@0: michael@0: if (certUsage != certUsageAnyCA && michael@0: certUsage != certUsageStatusResponder) { michael@0: michael@0: /* michael@0: * XXX This choice of trustType seems arbitrary. michael@0: */ michael@0: if ( certUsage == certUsageVerifyCA ) { michael@0: if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) { michael@0: trustType = trustEmail; michael@0: } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) { michael@0: trustType = trustSSL; michael@0: } else { michael@0: trustType = trustObjectSigning; michael@0: } michael@0: } michael@0: michael@0: flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); michael@0: if (( flags & requiredFlags ) == requiredFlags) { michael@0: /* we found a trusted one, so return */ michael@0: rv = rvFinal; michael@0: goto done; michael@0: } michael@0: if (flags & CERTDB_VALID_CA) { michael@0: validCAOverride = PR_TRUE; michael@0: } michael@0: /* is it explicitly distrusted? */ michael@0: if ((flags & CERTDB_TERMINAL_RECORD) && michael@0: ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) { michael@0: /* untrusted -- the cert is explicitly untrusted, not michael@0: * just that it doesn't chain to a trusted cert */ michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags); michael@0: } michael@0: } else { michael@0: /* Check if we have any valid trust when cheching for michael@0: * certUsageAnyCA or certUsageStatusResponder. */ michael@0: for (trustType = trustSSL; trustType < trustTypeNone; michael@0: trustType++) { michael@0: flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); michael@0: if ((flags & requiredFlags) == requiredFlags) { michael@0: rv = rvFinal; michael@0: goto done; michael@0: } michael@0: if (flags & CERTDB_VALID_CA) michael@0: validCAOverride = PR_TRUE; michael@0: } michael@0: /* We have 2 separate loops because we want any single trust michael@0: * bit to allow this usage to return trusted. Only if none of michael@0: * the trust bits are on do we check to see if the cert is michael@0: * untrusted */ michael@0: for (trustType = trustSSL; trustType < trustTypeNone; michael@0: trustType++) { michael@0: flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType); michael@0: /* is it explicitly distrusted? */ michael@0: if ((flags & CERTDB_TERMINAL_RECORD) && michael@0: ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) { michael@0: /* untrusted -- the cert is explicitly untrusted, not michael@0: * just that it doesn't chain to a trusted cert */ michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!validCAOverride) { michael@0: /* michael@0: * Make sure that if this is an intermediate CA in the chain that michael@0: * it was given permission by its signer to be a CA. michael@0: */ michael@0: /* michael@0: * if basicConstraints says it is a ca, then we check the michael@0: * nsCertType. If the nsCertType has any CA bits set, then michael@0: * it must have the right one. michael@0: */ michael@0: if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) { michael@0: isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; michael@0: } michael@0: michael@0: if ( !isca ) { michael@0: PORT_SetError(SEC_ERROR_CA_CERT_INVALID); michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); michael@0: } michael@0: michael@0: /* make sure key usage allows cert signing */ michael@0: if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) { michael@0: PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); michael@0: LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage); michael@0: } michael@0: } michael@0: michael@0: /* make sure that the issuer is not self signed. If it is, then michael@0: * stop here to prevent looping. michael@0: */ michael@0: if (issuerCert->isRoot) { michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); michael@0: LOG_ERROR(log, issuerCert, count+1, 0); michael@0: goto loser; michael@0: } michael@0: /* The issuer cert will be the subject cert in the next loop. michael@0: * A cert is self-issued if its subject and issuer are equal and michael@0: * both are of non-zero length. michael@0: */ michael@0: subjectCertIsSelfIssued = (PRBool) michael@0: SECITEM_ItemsAreEqual(&issuerCert->derIssuer, michael@0: &issuerCert->derSubject) && michael@0: issuerCert->derSubject.len > 0; michael@0: if (subjectCertIsSelfIssued == PR_FALSE) { michael@0: /* RFC 3280 says only non-self-issued intermediate CA certs michael@0: * count in path length. michael@0: */ michael@0: ++currentPathLen; michael@0: } michael@0: michael@0: CERT_DestroyCertificate(subjectCert); michael@0: subjectCert = issuerCert; michael@0: issuerCert = NULL; michael@0: } michael@0: michael@0: PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); michael@0: LOG_ERROR(log,subjectCert,count,0); michael@0: loser: michael@0: rv = SECFailure; michael@0: done: michael@0: if (certsList != NULL) { michael@0: PORT_Free(certsList); michael@0: } michael@0: if ( issuerCert ) { michael@0: CERT_DestroyCertificate(issuerCert); michael@0: } michael@0: michael@0: if ( subjectCert ) { michael@0: CERT_DestroyCertificate(subjectCert); michael@0: } michael@0: michael@0: if ( arena != NULL ) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, PRBool* sigerror, michael@0: SECCertUsage certUsage, PRTime t, void *wincx, michael@0: CERTVerifyLog *log, PRBool* revoked) michael@0: { michael@0: if (CERT_GetUsePKIXForValidation()) { michael@0: return cert_VerifyCertChainPkix(cert, checkSig, certUsage, t, michael@0: wincx, log, sigerror, revoked); michael@0: } michael@0: return cert_VerifyCertChainOld(handle, cert, checkSig, sigerror, michael@0: certUsage, t, wincx, log, revoked); michael@0: } michael@0: michael@0: SECStatus michael@0: CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertUsage certUsage, PRTime t, michael@0: void *wincx, CERTVerifyLog *log) michael@0: { michael@0: return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t, michael@0: wincx, log, NULL); michael@0: } michael@0: michael@0: /* michael@0: * verify that a CA can sign a certificate with the requested usage. michael@0: */ michael@0: SECStatus michael@0: CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertUsage certUsage, PRTime t, michael@0: void *wincx, CERTVerifyLog *log) michael@0: { michael@0: SECTrustType trustType; michael@0: CERTBasicConstraints basicConstraint; michael@0: PRBool isca; michael@0: PRBool validCAOverride = PR_FALSE; michael@0: SECStatus rv; michael@0: SECStatus rvFinal = SECSuccess; michael@0: unsigned int flags; michael@0: unsigned int caCertType; michael@0: unsigned int requiredCAKeyUsage; michael@0: unsigned int requiredFlags; michael@0: CERTCertificate *issuerCert; michael@0: CERTCertTrust certTrust; michael@0: michael@0: michael@0: if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, michael@0: &requiredCAKeyUsage, michael@0: &caCertType) != SECSuccess ) { michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredCAKeyUsage = 0; michael@0: caCertType = 0; michael@0: } michael@0: michael@0: switch ( certUsage ) { michael@0: case certUsageSSLClient: michael@0: case certUsageSSLServer: michael@0: case certUsageSSLCA: michael@0: case certUsageSSLServerWithStepUp: michael@0: case certUsageEmailSigner: michael@0: case certUsageEmailRecipient: michael@0: case certUsageObjectSigner: michael@0: case certUsageVerifyCA: michael@0: case certUsageStatusResponder: michael@0: if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, michael@0: &trustType) != SECSuccess ) { michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredFlags = 0; michael@0: trustType = trustSSL; michael@0: } michael@0: break; michael@0: default: michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredFlags = 0; michael@0: trustType = trustSSL;/* This used to be 0, but we need something michael@0: * that matches the enumeration type. michael@0: */ michael@0: caCertType = 0; michael@0: } michael@0: michael@0: /* If the basicConstraint extension is included in an intermmediate CA michael@0: * certificate, make sure that the isCA flag is on. If the michael@0: * pathLenConstraint component exists, it must be greater than the michael@0: * number of CA certificates we have seen so far. If the extension michael@0: * is omitted, we will assume that this is a CA certificate with michael@0: * an unlimited pathLenConstraint (since it already passes the michael@0: * netscape-cert-type extension checking). michael@0: */ michael@0: michael@0: rv = CERT_FindBasicConstraintExten(cert, &basicConstraint); michael@0: if ( rv != SECSuccess ) { michael@0: if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { michael@0: LOG_ERROR_OR_EXIT(log,cert,0,0); michael@0: } michael@0: /* no basic constraints found, we aren't (yet) a CA. */ michael@0: isca = PR_FALSE; michael@0: } else { michael@0: if ( basicConstraint.isCA == PR_FALSE ) { michael@0: PORT_SetError (SEC_ERROR_CA_CERT_INVALID); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,0); michael@0: } michael@0: michael@0: /* can't check path length if we don't know the previous path */ michael@0: isca = PR_TRUE; michael@0: } michael@0: michael@0: if ( CERT_GetCertTrust(cert, &certTrust) == SECSuccess ) { michael@0: /* we have some trust info, but this does NOT imply that this michael@0: * cert is actually trusted for any purpose. The cert may be michael@0: * explicitly UNtrusted. We won't know until we examine the michael@0: * trust bits. michael@0: */ michael@0: if (certUsage == certUsageStatusResponder) { michael@0: /* Check the special case of certUsageStatusResponder */ michael@0: issuerCert = CERT_FindCertIssuer(cert, t, certUsage); michael@0: if (issuerCert) { michael@0: if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx) michael@0: != SECSuccess) { michael@0: PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); michael@0: CERT_DestroyCertificate(issuerCert); michael@0: goto loser; michael@0: } michael@0: CERT_DestroyCertificate(issuerCert); michael@0: } michael@0: /* XXX We have NOT determined that this cert is trusted. michael@0: * For years, NSS has treated this as trusted, michael@0: * but it seems incorrect. michael@0: */ michael@0: rv = rvFinal; michael@0: goto done; michael@0: } michael@0: michael@0: /* michael@0: * check the trust params of the issuer michael@0: */ michael@0: flags = SEC_GET_TRUST_FLAGS(&certTrust, trustType); michael@0: if ( ( flags & requiredFlags ) == requiredFlags) { michael@0: /* we found a trusted one, so return */ michael@0: rv = rvFinal; michael@0: goto done; michael@0: } michael@0: if (flags & CERTDB_VALID_CA) { michael@0: validCAOverride = PR_TRUE; michael@0: } michael@0: /* is it explicitly distrusted? */ michael@0: if ((flags & CERTDB_TERMINAL_RECORD) && michael@0: ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) { michael@0: /* untrusted -- the cert is explicitly untrusted, not michael@0: * just that it doesn't chain to a trusted cert */ michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,flags); michael@0: } michael@0: } michael@0: if (!validCAOverride) { michael@0: /* michael@0: * Make sure that if this is an intermediate CA in the chain that michael@0: * it was given permission by its signer to be a CA. michael@0: */ michael@0: /* michael@0: * if basicConstraints says it is a ca, then we check the michael@0: * nsCertType. If the nsCertType has any CA bits set, then michael@0: * it must have the right one. michael@0: */ michael@0: if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) { michael@0: isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; michael@0: } michael@0: michael@0: if (!isca) { michael@0: PORT_SetError(SEC_ERROR_CA_CERT_INVALID); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,0); michael@0: } michael@0: michael@0: /* make sure key usage allows cert signing */ michael@0: if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) { michael@0: PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage); michael@0: } michael@0: } michael@0: /* make sure that the issuer is not self signed. If it is, then michael@0: * stop here to prevent looping. michael@0: */ michael@0: if (cert->isRoot) { michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); michael@0: LOG_ERROR(log, cert, 0, 0); michael@0: goto loser; michael@0: } michael@0: michael@0: return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, michael@0: wincx, log); michael@0: loser: michael@0: rv = SECFailure; michael@0: done: michael@0: return rv; michael@0: } michael@0: michael@0: #define NEXT_USAGE() { \ michael@0: i*=2; \ michael@0: certUsage++; \ michael@0: continue; \ michael@0: } michael@0: michael@0: #define VALID_USAGE() { \ michael@0: NEXT_USAGE(); \ michael@0: } michael@0: michael@0: #define INVALID_USAGE() { \ michael@0: if (returnedUsages) { \ michael@0: *returnedUsages &= (~i); \ michael@0: } \ michael@0: if (PR_TRUE == requiredUsage) { \ michael@0: valid = SECFailure; \ michael@0: } \ michael@0: NEXT_USAGE(); \ michael@0: } michael@0: michael@0: /* michael@0: * check the leaf cert against trust and usage. michael@0: * returns success if the cert is not distrusted. If the cert is michael@0: * trusted, then the trusted bool will be true. michael@0: * returns failure if the cert is distrusted. If failure, flags michael@0: * will return the flag bits that indicated distrust. michael@0: */ michael@0: SECStatus michael@0: cert_CheckLeafTrust(CERTCertificate *cert, SECCertUsage certUsage, michael@0: unsigned int *failedFlags, PRBool *trusted) michael@0: { michael@0: unsigned int flags; michael@0: CERTCertTrust trust; michael@0: michael@0: *failedFlags = 0; michael@0: *trusted = PR_FALSE; michael@0: michael@0: /* check trust flags to see if this cert is directly trusted */ michael@0: if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) { michael@0: switch ( certUsage ) { michael@0: case certUsageSSLClient: michael@0: case certUsageSSLServer: michael@0: flags = trust.sslFlags; michael@0: michael@0: /* is the cert directly trusted or not trusted ? */ michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ michael@0: *trusted = PR_TRUE; michael@0: return SECSuccess; michael@0: } else { /* don't trust this cert */ michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: break; michael@0: case certUsageSSLServerWithStepUp: michael@0: /* XXX - step up certs can't be directly trusted, only distrust */ michael@0: flags = trust.sslFlags; michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if (( flags & CERTDB_TRUSTED ) == 0) { michael@0: /* don't trust this cert */ michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: break; michael@0: case certUsageSSLCA: michael@0: flags = trust.sslFlags; michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if (( flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA) ) == 0) { michael@0: /* don't trust this cert */ michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: break; michael@0: case certUsageEmailSigner: michael@0: case certUsageEmailRecipient: michael@0: flags = trust.emailFlags; michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ michael@0: *trusted = PR_TRUE; michael@0: return SECSuccess; michael@0: } michael@0: else { /* don't trust this cert */ michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: michael@0: break; michael@0: case certUsageObjectSigner: michael@0: flags = trust.objectSigningFlags; michael@0: michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ michael@0: *trusted = PR_TRUE; michael@0: return SECSuccess; michael@0: } else { /* don't trust this cert */ michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: break; michael@0: case certUsageVerifyCA: michael@0: case certUsageStatusResponder: michael@0: flags = trust.sslFlags; michael@0: /* is the cert directly trusted or not trusted ? */ michael@0: if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == michael@0: ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { michael@0: *trusted = PR_TRUE; michael@0: return SECSuccess; michael@0: } michael@0: flags = trust.emailFlags; michael@0: /* is the cert directly trusted or not trusted ? */ michael@0: if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == michael@0: ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { michael@0: *trusted = PR_TRUE; michael@0: return SECSuccess; michael@0: } michael@0: flags = trust.objectSigningFlags; michael@0: /* is the cert directly trusted or not trusted ? */ michael@0: if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == michael@0: ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { michael@0: *trusted = PR_TRUE; michael@0: return SECSuccess; michael@0: } michael@0: /* fall through to test distrust */ michael@0: case certUsageAnyCA: michael@0: case certUsageUserCertImport: michael@0: /* do we distrust these certs explicitly */ michael@0: flags = trust.sslFlags; michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) { michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: flags = trust.emailFlags; michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) { michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: /* fall through */ michael@0: case certUsageProtectedObjectSigner: michael@0: flags = trust.objectSigningFlags; michael@0: if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is michael@0: * authoritative */ michael@0: if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) { michael@0: *failedFlags = flags; michael@0: return SECFailure; michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: /* michael@0: * verify a certificate by checking if it's valid and that we michael@0: * trust the issuer. michael@0: * michael@0: * certificateUsage contains a bitfield of all cert usages that are michael@0: * required for verification to succeed michael@0: * michael@0: * a bitfield of cert usages is returned in *returnedUsages michael@0: * if requiredUsages is non-zero, the returned bitmap is only michael@0: * for those required usages, otherwise it is for all usages michael@0: * michael@0: */ michael@0: SECStatus michael@0: CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertificateUsage requiredUsages, PRTime t, michael@0: void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages) michael@0: { michael@0: SECStatus rv; michael@0: SECStatus valid; michael@0: unsigned int requiredKeyUsage; michael@0: unsigned int requiredCertType; michael@0: unsigned int flags; michael@0: unsigned int certType; michael@0: PRBool allowOverride; michael@0: SECCertTimeValidity validity; michael@0: CERTStatusConfig *statusConfig; michael@0: PRInt32 i; michael@0: SECCertUsage certUsage = 0; michael@0: PRBool checkedOCSP = PR_FALSE; michael@0: PRBool checkAllUsages = PR_FALSE; michael@0: PRBool revoked = PR_FALSE; michael@0: PRBool sigerror = PR_FALSE; michael@0: PRBool trusted = PR_FALSE; michael@0: michael@0: if (!requiredUsages) { michael@0: /* there are no required usages, so the user probably wants to michael@0: get status for all usages */ michael@0: checkAllUsages = PR_TRUE; michael@0: } michael@0: michael@0: if (returnedUsages) { michael@0: *returnedUsages = 0; michael@0: } else { michael@0: /* we don't have a place to return status for all usages, michael@0: so we can skip checks for usages that aren't required */ michael@0: checkAllUsages = PR_FALSE; michael@0: } michael@0: valid = SECSuccess ; /* start off assuming cert is valid */ michael@0: michael@0: /* make sure that the cert is valid at time t */ michael@0: allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) || michael@0: (requiredUsages & certificateUsageSSLServerWithStepUp)); michael@0: validity = CERT_CheckCertValidTimes(cert, t, allowOverride); michael@0: if ( validity != secCertTimeValid ) { michael@0: valid = SECFailure; michael@0: LOG_ERROR_OR_EXIT(log,cert,0,validity); michael@0: } michael@0: michael@0: /* check key usage and netscape cert type */ michael@0: cert_GetCertType(cert); michael@0: certType = cert->nsCertType; michael@0: michael@0: for (i=1; i<=certificateUsageHighest && michael@0: (SECSuccess == valid || returnedUsages || log) ; ) { michael@0: PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE; michael@0: if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) { michael@0: NEXT_USAGE(); michael@0: } michael@0: if (returnedUsages) { michael@0: *returnedUsages |= i; /* start off assuming this usage is valid */ michael@0: } michael@0: switch ( certUsage ) { michael@0: case certUsageSSLClient: michael@0: case certUsageSSLServer: michael@0: case certUsageSSLServerWithStepUp: michael@0: case certUsageSSLCA: michael@0: case certUsageEmailSigner: michael@0: case certUsageEmailRecipient: michael@0: case certUsageObjectSigner: michael@0: case certUsageStatusResponder: michael@0: rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, michael@0: &requiredKeyUsage, michael@0: &requiredCertType); michael@0: if ( rv != SECSuccess ) { michael@0: PORT_Assert(0); michael@0: /* EXIT_IF_NOT_LOGGING(log); XXX ??? */ michael@0: requiredKeyUsage = 0; michael@0: requiredCertType = 0; michael@0: INVALID_USAGE(); michael@0: } michael@0: break; michael@0: michael@0: case certUsageAnyCA: michael@0: case certUsageProtectedObjectSigner: michael@0: case certUsageUserCertImport: michael@0: case certUsageVerifyCA: michael@0: /* these usages cannot be verified */ michael@0: NEXT_USAGE(); michael@0: michael@0: default: michael@0: PORT_Assert(0); michael@0: requiredKeyUsage = 0; michael@0: requiredCertType = 0; michael@0: INVALID_USAGE(); michael@0: } michael@0: if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { michael@0: if (PR_TRUE == requiredUsage) { michael@0: PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); michael@0: } michael@0: LOG_ERROR(log,cert,0,requiredKeyUsage); michael@0: INVALID_USAGE(); michael@0: } michael@0: if ( !( certType & requiredCertType ) ) { michael@0: if (PR_TRUE == requiredUsage) { michael@0: PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); michael@0: } michael@0: LOG_ERROR(log,cert,0,requiredCertType); michael@0: INVALID_USAGE(); michael@0: } michael@0: michael@0: rv = cert_CheckLeafTrust(cert, certUsage, &flags, &trusted); michael@0: if (rv == SECFailure) { michael@0: if (PR_TRUE == requiredUsage) { michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); michael@0: } michael@0: LOG_ERROR(log, cert, 0, flags); michael@0: INVALID_USAGE(); michael@0: } else if (trusted) { michael@0: VALID_USAGE(); michael@0: } michael@0: michael@0: if (PR_TRUE == revoked || PR_TRUE == sigerror) { michael@0: INVALID_USAGE(); michael@0: } michael@0: michael@0: rv = cert_VerifyCertChain(handle, cert, michael@0: checkSig, &sigerror, michael@0: certUsage, t, wincx, log, michael@0: &revoked); michael@0: michael@0: if (rv != SECSuccess) { michael@0: /* EXIT_IF_NOT_LOGGING(log); XXX ???? */ michael@0: INVALID_USAGE(); michael@0: } michael@0: michael@0: /* michael@0: * Check OCSP revocation status, but only if the cert we are checking michael@0: * is not a status responder itself. We only do this in the case michael@0: * where we checked the cert chain (above); explicit trust "wins" michael@0: * (avoids status checking, just as it avoids CRL checking) by michael@0: * bypassing this code. michael@0: */ michael@0: michael@0: if (PR_FALSE == checkedOCSP) { michael@0: checkedOCSP = PR_TRUE; /* only check OCSP once */ michael@0: statusConfig = CERT_GetStatusConfig(handle); michael@0: if (requiredUsages != certificateUsageStatusResponder && michael@0: statusConfig != NULL) { michael@0: if (statusConfig->statusChecker != NULL) { michael@0: rv = (* statusConfig->statusChecker)(handle, cert, michael@0: t, wincx); michael@0: if (rv != SECSuccess) { michael@0: LOG_ERROR(log,cert,0,0); michael@0: revoked = PR_TRUE; michael@0: INVALID_USAGE(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: NEXT_USAGE(); michael@0: } michael@0: michael@0: loser: michael@0: return(valid); michael@0: } michael@0: michael@0: SECStatus michael@0: CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertUsage certUsage, PRTime t, michael@0: void *wincx, CERTVerifyLog *log) michael@0: { michael@0: return cert_VerifyCertWithFlags(handle, cert, checkSig, certUsage, t, michael@0: CERT_VERIFYCERT_USE_DEFAULTS, wincx, log); michael@0: } michael@0: michael@0: SECStatus michael@0: cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertUsage certUsage, PRTime t, michael@0: PRUint32 flags, void *wincx, CERTVerifyLog *log) michael@0: { michael@0: SECStatus rv; michael@0: unsigned int requiredKeyUsage; michael@0: unsigned int requiredCertType; michael@0: unsigned int failedFlags; michael@0: unsigned int certType; michael@0: PRBool trusted; michael@0: PRBool allowOverride; michael@0: SECCertTimeValidity validity; michael@0: CERTStatusConfig *statusConfig; michael@0: michael@0: #ifdef notdef michael@0: /* check if this cert is in the Evil list */ michael@0: rv = CERT_CheckForEvilCert(cert); michael@0: if ( rv != SECSuccess ) { michael@0: PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,0); michael@0: } michael@0: #endif michael@0: michael@0: /* make sure that the cert is valid at time t */ michael@0: allowOverride = (PRBool)((certUsage == certUsageSSLServer) || michael@0: (certUsage == certUsageSSLServerWithStepUp)); michael@0: validity = CERT_CheckCertValidTimes(cert, t, allowOverride); michael@0: if ( validity != secCertTimeValid ) { michael@0: LOG_ERROR_OR_EXIT(log,cert,0,validity); michael@0: } michael@0: michael@0: /* check key usage and netscape cert type */ michael@0: cert_GetCertType(cert); michael@0: certType = cert->nsCertType; michael@0: switch ( certUsage ) { michael@0: case certUsageSSLClient: michael@0: case certUsageSSLServer: michael@0: case certUsageSSLServerWithStepUp: michael@0: case certUsageSSLCA: michael@0: case certUsageEmailSigner: michael@0: case certUsageEmailRecipient: michael@0: case certUsageObjectSigner: michael@0: case certUsageStatusResponder: michael@0: rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, michael@0: &requiredKeyUsage, michael@0: &requiredCertType); michael@0: if ( rv != SECSuccess ) { michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredKeyUsage = 0; michael@0: requiredCertType = 0; michael@0: } michael@0: break; michael@0: case certUsageVerifyCA: michael@0: case certUsageAnyCA: michael@0: requiredKeyUsage = KU_KEY_CERT_SIGN; michael@0: requiredCertType = NS_CERT_TYPE_CA; michael@0: if ( ! ( certType & NS_CERT_TYPE_CA ) ) { michael@0: certType |= NS_CERT_TYPE_CA; michael@0: } michael@0: break; michael@0: default: michael@0: PORT_Assert(0); michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: requiredKeyUsage = 0; michael@0: requiredCertType = 0; michael@0: } michael@0: if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { michael@0: PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage); michael@0: } michael@0: if ( !( certType & requiredCertType ) ) { michael@0: PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); michael@0: LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType); michael@0: } michael@0: michael@0: rv = cert_CheckLeafTrust(cert, certUsage, &failedFlags, &trusted); michael@0: if (rv == SECFailure) { michael@0: PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); michael@0: LOG_ERROR_OR_EXIT(log, cert, 0, failedFlags); michael@0: } else if (trusted) { michael@0: goto done; michael@0: } michael@0: michael@0: michael@0: rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage, michael@0: t, wincx, log); michael@0: if (rv != SECSuccess) { michael@0: EXIT_IF_NOT_LOGGING(log); michael@0: } michael@0: michael@0: /* michael@0: * Check revocation status, but only if the cert we are checking is not a michael@0: * status responder itself and the caller did not ask us to skip the check. michael@0: * We only do this in the case where we checked the cert chain (above); michael@0: * explicit trust "wins" (avoids status checking, just as it avoids CRL michael@0: * checking, which is all done inside VerifyCertChain) by bypassing this michael@0: * code. michael@0: */ michael@0: if (!(flags & CERT_VERIFYCERT_SKIP_OCSP) && michael@0: certUsage != certUsageStatusResponder) { michael@0: statusConfig = CERT_GetStatusConfig(handle); michael@0: if (statusConfig && statusConfig->statusChecker) { michael@0: rv = (* statusConfig->statusChecker)(handle, cert, michael@0: t, wincx); michael@0: if (rv != SECSuccess) { michael@0: LOG_ERROR_OR_EXIT(log,cert,0,0); michael@0: } michael@0: } michael@0: } michael@0: michael@0: done: michael@0: if (log && log->head) { michael@0: return SECFailure; michael@0: } michael@0: return(SECSuccess); michael@0: michael@0: loser: michael@0: rv = SECFailure; michael@0: michael@0: return(rv); michael@0: } michael@0: michael@0: /* michael@0: * verify a certificate by checking if its valid and that we michael@0: * trust the issuer. Verify time against now. michael@0: */ michael@0: SECStatus michael@0: CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertificateUsage requiredUsages, michael@0: void *wincx, SECCertificateUsage* returnedUsages) michael@0: { michael@0: return(CERT_VerifyCertificate(handle, cert, checkSig, michael@0: requiredUsages, PR_Now(), wincx, NULL, returnedUsages)); michael@0: } michael@0: michael@0: /* obsolete, do not use for new code */ michael@0: SECStatus michael@0: CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert, michael@0: PRBool checkSig, SECCertUsage certUsage, void *wincx) michael@0: { michael@0: return(CERT_VerifyCert(handle, cert, checkSig, michael@0: certUsage, PR_Now(), wincx, NULL)); michael@0: } michael@0: michael@0: michael@0: /* [ FROM pcertdb.c ] */ michael@0: /* michael@0: * Supported usage values and types: michael@0: * certUsageSSLClient michael@0: * certUsageSSLServer michael@0: * certUsageSSLServerWithStepUp michael@0: * certUsageEmailSigner michael@0: * certUsageEmailRecipient michael@0: * certUsageObjectSigner michael@0: */ michael@0: michael@0: CERTCertificate * michael@0: CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName, michael@0: CERTCertOwner owner, SECCertUsage usage, michael@0: PRBool preferTrusted, PRTime validTime, PRBool validOnly) michael@0: { michael@0: CERTCertList *certList = NULL; michael@0: CERTCertificate *cert = NULL; michael@0: CERTCertTrust certTrust; michael@0: unsigned int requiredTrustFlags; michael@0: SECTrustType requiredTrustType; michael@0: unsigned int flags; michael@0: michael@0: PRBool lookingForCA = PR_FALSE; michael@0: SECStatus rv; michael@0: CERTCertListNode *node; michael@0: CERTCertificate *saveUntrustedCA = NULL; michael@0: michael@0: /* if preferTrusted is set, must be a CA cert */ michael@0: PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) ); michael@0: michael@0: if ( owner == certOwnerCA ) { michael@0: lookingForCA = PR_TRUE; michael@0: if ( preferTrusted ) { michael@0: rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags, michael@0: &requiredTrustType); michael@0: if ( rv != SECSuccess ) { michael@0: goto loser; michael@0: } michael@0: requiredTrustFlags |= CERTDB_VALID_CA; michael@0: } michael@0: } michael@0: michael@0: certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime, michael@0: validOnly); michael@0: if ( certList != NULL ) { michael@0: rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA); michael@0: if ( rv != SECSuccess ) { michael@0: goto loser; michael@0: } michael@0: michael@0: node = CERT_LIST_HEAD(certList); michael@0: michael@0: while ( !CERT_LIST_END(node, certList) ) { michael@0: cert = node->cert; michael@0: michael@0: /* looking for a trusted CA cert */ michael@0: if ( ( owner == certOwnerCA ) && preferTrusted && michael@0: ( requiredTrustType != trustTypeNone ) ) { michael@0: michael@0: if ( CERT_GetCertTrust(cert, &certTrust) != SECSuccess ) { michael@0: flags = 0; michael@0: } else { michael@0: flags = SEC_GET_TRUST_FLAGS(&certTrust, requiredTrustType); michael@0: } michael@0: michael@0: if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) { michael@0: /* cert is not trusted */ michael@0: /* if this is the first cert to get this far, then save michael@0: * it, so we can use it if we can't find a trusted one michael@0: */ michael@0: if ( saveUntrustedCA == NULL ) { michael@0: saveUntrustedCA = cert; michael@0: } michael@0: goto endloop; michael@0: } michael@0: } michael@0: /* if we got this far, then this cert meets all criteria */ michael@0: break; michael@0: michael@0: endloop: michael@0: node = CERT_LIST_NEXT(node); michael@0: cert = NULL; michael@0: } michael@0: michael@0: /* use the saved one if we have it */ michael@0: if ( cert == NULL ) { michael@0: cert = saveUntrustedCA; michael@0: } michael@0: michael@0: /* if we found one then bump the ref count before freeing the list */ michael@0: if ( cert != NULL ) { michael@0: /* bump the ref count */ michael@0: cert = CERT_DupCertificate(cert); michael@0: } michael@0: michael@0: CERT_DestroyCertList(certList); michael@0: } michael@0: michael@0: return(cert); michael@0: michael@0: loser: michael@0: if ( certList != NULL ) { michael@0: CERT_DestroyCertList(certList); michael@0: } michael@0: michael@0: return(NULL); michael@0: } michael@0: michael@0: michael@0: /* [ From certdb.c ] */ michael@0: /* michael@0: * Filter a list of certificates, removing those certs that do not have michael@0: * one of the named CA certs somewhere in their cert chain. michael@0: * michael@0: * "certList" - the list of certificates to filter michael@0: * "nCANames" - number of CA names michael@0: * "caNames" - array of CA names in string(rfc 1485) form michael@0: * "usage" - what use the certs are for, this is used when michael@0: * selecting CA certs michael@0: */ michael@0: SECStatus michael@0: CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames, michael@0: char **caNames, SECCertUsage usage) michael@0: { michael@0: CERTCertificate *issuerCert = NULL; michael@0: CERTCertificate *subjectCert; michael@0: CERTCertListNode *node, *freenode; michael@0: CERTCertificate *cert; michael@0: int n; michael@0: char **names; michael@0: PRBool found; michael@0: PRTime time; michael@0: michael@0: if ( nCANames <= 0 ) { michael@0: return(SECSuccess); michael@0: } michael@0: michael@0: time = PR_Now(); michael@0: michael@0: node = CERT_LIST_HEAD(certList); michael@0: michael@0: while ( ! CERT_LIST_END(node, certList) ) { michael@0: cert = node->cert; michael@0: michael@0: subjectCert = CERT_DupCertificate(cert); michael@0: michael@0: /* traverse the CA certs for this cert */ michael@0: found = PR_FALSE; michael@0: while ( subjectCert != NULL ) { michael@0: n = nCANames; michael@0: names = caNames; michael@0: michael@0: if (subjectCert->issuerName != NULL) { michael@0: while ( n > 0 ) { michael@0: if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) { michael@0: found = PR_TRUE; michael@0: break; michael@0: } michael@0: michael@0: n--; michael@0: names++; michael@0: } michael@0: } michael@0: michael@0: if ( found ) { michael@0: break; michael@0: } michael@0: michael@0: issuerCert = CERT_FindCertIssuer(subjectCert, time, usage); michael@0: if ( issuerCert == subjectCert ) { michael@0: CERT_DestroyCertificate(issuerCert); michael@0: issuerCert = NULL; michael@0: break; michael@0: } michael@0: CERT_DestroyCertificate(subjectCert); michael@0: subjectCert = issuerCert; michael@0: michael@0: } michael@0: CERT_DestroyCertificate(subjectCert); michael@0: if ( !found ) { michael@0: /* CA was not found, so remove this cert from the list */ michael@0: freenode = node; michael@0: node = CERT_LIST_NEXT(node); michael@0: CERT_RemoveCertListNode(freenode); michael@0: } else { michael@0: /* CA was found, so leave it in the list */ michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: } michael@0: michael@0: return(SECSuccess); michael@0: } michael@0: michael@0: /* michael@0: * Given a certificate, return a string containing the nickname, and possibly michael@0: * one of the validity strings, based on the current validity state of the michael@0: * certificate. michael@0: * michael@0: * "arena" - arena to allocate returned string from. If NULL, then heap michael@0: * is used. michael@0: * "cert" - the cert to get nickname from michael@0: * "expiredString" - the string to append to the nickname if the cert is michael@0: * expired. michael@0: * "notYetGoodString" - the string to append to the nickname if the cert is michael@0: * not yet good. michael@0: */ michael@0: char * michael@0: CERT_GetCertNicknameWithValidity(PLArenaPool *arena, CERTCertificate *cert, michael@0: char *expiredString, char *notYetGoodString) michael@0: { michael@0: SECCertTimeValidity validity; michael@0: char *nickname = NULL, *tmpstr = NULL; michael@0: michael@0: validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE); michael@0: michael@0: /* if the cert is good, then just use the nickname directly */ michael@0: if ( validity == secCertTimeValid ) { michael@0: if ( arena == NULL ) { michael@0: nickname = PORT_Strdup(cert->nickname); michael@0: } else { michael@0: nickname = PORT_ArenaStrdup(arena, cert->nickname); michael@0: } michael@0: michael@0: if ( nickname == NULL ) { michael@0: goto loser; michael@0: } michael@0: } else { michael@0: michael@0: /* if the cert is not valid, then tack one of the strings on the michael@0: * end michael@0: */ michael@0: if ( validity == secCertTimeExpired ) { michael@0: tmpstr = PR_smprintf("%s%s", cert->nickname, michael@0: expiredString); michael@0: } else if ( validity == secCertTimeNotValidYet ) { michael@0: /* not yet valid */ michael@0: tmpstr = PR_smprintf("%s%s", cert->nickname, michael@0: notYetGoodString); michael@0: } else { michael@0: /* undetermined */ michael@0: tmpstr = PR_smprintf("%s", michael@0: "(NULL) (Validity Unknown)"); michael@0: } michael@0: michael@0: if ( tmpstr == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: if ( arena ) { michael@0: /* copy the string into the arena and free the malloc'd one */ michael@0: nickname = PORT_ArenaStrdup(arena, tmpstr); michael@0: PORT_Free(tmpstr); michael@0: } else { michael@0: nickname = tmpstr; michael@0: } michael@0: if ( nickname == NULL ) { michael@0: goto loser; michael@0: } michael@0: } michael@0: return(nickname); michael@0: michael@0: loser: michael@0: return(NULL); michael@0: } michael@0: michael@0: /* michael@0: * Collect the nicknames from all certs in a CertList. If the cert is not michael@0: * valid, append a string to that nickname. michael@0: * michael@0: * "certList" - the list of certificates michael@0: * "expiredString" - the string to append to the nickname of any expired cert michael@0: * "notYetGoodString" - the string to append to the nickname of any cert michael@0: * that is not yet valid michael@0: */ michael@0: CERTCertNicknames * michael@0: CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString, michael@0: char *notYetGoodString) michael@0: { michael@0: CERTCertNicknames *names; michael@0: PLArenaPool *arena; michael@0: CERTCertListNode *node; michael@0: char **nn; michael@0: michael@0: /* allocate an arena */ michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( arena == NULL ) { michael@0: return(NULL); michael@0: } michael@0: michael@0: /* allocate the structure */ michael@0: names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); michael@0: if ( names == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* init the structure */ michael@0: names->arena = arena; michael@0: names->head = NULL; michael@0: names->numnicknames = 0; michael@0: names->nicknames = NULL; michael@0: names->totallen = 0; michael@0: michael@0: /* count the certs in the list */ michael@0: node = CERT_LIST_HEAD(certList); michael@0: while ( ! CERT_LIST_END(node, certList) ) { michael@0: names->numnicknames++; michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: michael@0: /* allocate nicknames array */ michael@0: names->nicknames = PORT_ArenaAlloc(arena, michael@0: sizeof(char *) * names->numnicknames); michael@0: if ( names->nicknames == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: /* just in case printf can't deal with null strings */ michael@0: if (expiredString == NULL ) { michael@0: expiredString = ""; michael@0: } michael@0: michael@0: if ( notYetGoodString == NULL ) { michael@0: notYetGoodString = ""; michael@0: } michael@0: michael@0: /* traverse the list of certs and collect the nicknames */ michael@0: nn = names->nicknames; michael@0: node = CERT_LIST_HEAD(certList); michael@0: while ( ! CERT_LIST_END(node, certList) ) { michael@0: *nn = CERT_GetCertNicknameWithValidity(arena, node->cert, michael@0: expiredString, michael@0: notYetGoodString); michael@0: if ( *nn == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: names->totallen += PORT_Strlen(*nn); michael@0: michael@0: nn++; michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: michael@0: return(names); michael@0: michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return(NULL); michael@0: } michael@0: michael@0: /* michael@0: * Extract the nickname from a nickmake string that may have either michael@0: * expiredString or notYetGoodString appended. michael@0: * michael@0: * Args: michael@0: * "namestring" - the string containing the nickname, and possibly michael@0: * one of the validity label strings michael@0: * "expiredString" - the expired validity label string michael@0: * "notYetGoodString" - the not yet good validity label string michael@0: * michael@0: * Returns the raw nickname michael@0: */ michael@0: char * michael@0: CERT_ExtractNicknameString(char *namestring, char *expiredString, michael@0: char *notYetGoodString) michael@0: { michael@0: int explen, nyglen, namelen; michael@0: int retlen; michael@0: char *retstr; michael@0: michael@0: namelen = PORT_Strlen(namestring); michael@0: explen = PORT_Strlen(expiredString); michael@0: nyglen = PORT_Strlen(notYetGoodString); michael@0: michael@0: if ( namelen > explen ) { michael@0: if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) { michael@0: retlen = namelen - explen; michael@0: retstr = (char *)PORT_Alloc(retlen+1); michael@0: if ( retstr == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: PORT_Memcpy(retstr, namestring, retlen); michael@0: retstr[retlen] = '\0'; michael@0: goto done; michael@0: } michael@0: } michael@0: michael@0: if ( namelen > nyglen ) { michael@0: if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) { michael@0: retlen = namelen - nyglen; michael@0: retstr = (char *)PORT_Alloc(retlen+1); michael@0: if ( retstr == NULL ) { michael@0: goto loser; michael@0: } michael@0: michael@0: PORT_Memcpy(retstr, namestring, retlen); michael@0: retstr[retlen] = '\0'; michael@0: goto done; michael@0: } michael@0: } michael@0: michael@0: /* if name string is shorter than either invalid string, then it must michael@0: * be a raw nickname michael@0: */ michael@0: retstr = PORT_Strdup(namestring); michael@0: michael@0: done: michael@0: return(retstr); michael@0: michael@0: loser: michael@0: return(NULL); michael@0: } michael@0: michael@0: CERTCertList * michael@0: CERT_GetCertChainFromCert(CERTCertificate *cert, PRTime time, SECCertUsage usage) michael@0: { michael@0: CERTCertList *chain = NULL; michael@0: int count = 0; michael@0: michael@0: if (NULL == cert) { michael@0: return NULL; michael@0: } michael@0: michael@0: cert = CERT_DupCertificate(cert); michael@0: if (NULL == cert) { michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return NULL; michael@0: } michael@0: michael@0: chain = CERT_NewCertList(); michael@0: if (NULL == chain) { michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return NULL; michael@0: } michael@0: michael@0: while (cert != NULL && ++count <= CERT_MAX_CERT_CHAIN) { michael@0: if (SECSuccess != CERT_AddCertToListTail(chain, cert)) { michael@0: /* return partial chain */ michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: return chain; michael@0: } michael@0: michael@0: if (cert->isRoot) { michael@0: /* return complete chain */ michael@0: return chain; michael@0: } michael@0: michael@0: cert = CERT_FindCertIssuer(cert, time, usage); michael@0: } michael@0: michael@0: /* return partial chain */ michael@0: PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); michael@0: return chain; michael@0: }