SECStatus AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId& policy, const SECItem& candidateCertDER, /*out*/ TrustLevel* trustLevel) { MOZ_ASSERT(policy.IsAnyPolicy()); MOZ_ASSERT(trustLevel); MOZ_ASSERT(mTrustedRoot); if (!trustLevel || !policy.IsAnyPolicy()) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } if (!mTrustedRoot) { PR_SetError(PR_INVALID_STATE_ERROR, 0); return SECFailure; } // Handle active distrust of the certificate. // XXX: This would be cleaner and more efficient if we could get the trust // information without constructing a CERTCertificate here, but NSS doesn't // expose it in any other easy-to-use fashion. ScopedCERTCertificate candidateCert( CERT_NewTempCertificate(CERT_GetDefaultCertDB(), const_cast<SECItem*>(&candidateCertDER), nullptr, false, true)); if (!candidateCert) { return SECFailure; } CERTCertTrust trust; if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) { PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning); // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit, // because we can have active distrust for either type of cert. Note that // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the // relevant trust bit isn't set then that means the cert must be considered // distrusted. PRUint32 relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA ? CERTDB_TRUSTED_CA : CERTDB_TRUSTED; if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD))) == CERTDB_TERMINAL_RECORD) { *trustLevel = TrustLevel::ActivelyDistrusted; return SECSuccess; } } // mTrustedRoot is the only trust anchor for this validation. if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) { *trustLevel = TrustLevel::TrustAnchor; return SECSuccess; } *trustLevel = TrustLevel::InheritsTrust; return SECSuccess; }
static CERTCertificate * stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate) { nssDecodedCert *dc = NULL; CERTCertificate *cc = NULL; CERTCertTrust certTrust; nssPKIObject_Lock(&c->object); dc = c->decoding; if (!dc) { dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding); if (!dc) { goto loser; } cc = (CERTCertificate *)dc->data; PORT_Assert(cc); /* software error */ if (!cc) { nssDecodedPKIXCertificate_Destroy(dc); nss_SetError(NSS_ERROR_INTERNAL_ERROR); goto loser; } PORT_Assert(!c->decoding); if (!c->decoding) { c->decoding = dc; } else { /* this should never happen. Fail. */ nssDecodedPKIXCertificate_Destroy(dc); nss_SetError(NSS_ERROR_INTERNAL_ERROR); goto loser; } } cc = (CERTCertificate *)dc->data; PORT_Assert(cc); if (!cc) { nss_SetError(NSS_ERROR_INTERNAL_ERROR); goto loser; } if (!cc->nssCertificate || forceUpdate) { fill_CERTCertificateFields(c, cc, forceUpdate); } else if (CERT_GetCertTrust(cc, &certTrust) != SECSuccess && !c->object.cryptoContext) { /* if it's a perm cert, it might have been stored before the * trust, so look for the trust again. But a temp cert can be * ignored. */ CERTCertTrust* trust = NULL; trust = nssTrust_GetCERTCertTrustForCert(c, cc); CERT_LockCertTrust(cc); cc->trust = trust; CERT_UnlockCertTrust(cc); } loser: nssPKIObject_Unlock(&c->object); return cc; }
static void addToCertListIfTrusted(CERTCertList* certList, CERTCertificate* cert) { CERTCertTrust nssTrust; if (CERT_GetCertTrust(cert, &nssTrust) != SECSuccess) { return; } unsigned int flags = SEC_GET_TRUST_FLAGS(&nssTrust, trustSSL); if (flags & CERTDB_TRUSTED_CA) { CERT_AddCertToListTail(certList, CERT_DupCertificate(cert)); } }
NS_IMETHODIMP nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert, PRUint32 certType, PRUint32 trustType, PRBool *_isTrusted) { NS_ENSURE_ARG_POINTER(_isTrusted); *_isTrusted = PR_FALSE; nsNSSShutDownPreventionLock locker; SECStatus srv; nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert); CERTCertificate *nsscert = pipCert->GetCert(); CERTCertTrust nsstrust; srv = CERT_GetCertTrust(nsscert, &nsstrust); if (srv != SECSuccess) return NS_ERROR_FAILURE; nsNSSCertTrust trust(&nsstrust); CERT_DestroyCertificate(nsscert); if (certType == nsIX509Cert::CA_CERT) { if (trustType & nsIX509CertDB::TRUSTED_SSL) { *_isTrusted = trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE); } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { *_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE); } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { *_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE); } else { return NS_ERROR_FAILURE; } } else if (certType == nsIX509Cert::SERVER_CERT) { if (trustType & nsIX509CertDB::TRUSTED_SSL) { *_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE); } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE); } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE); } else { return NS_ERROR_FAILURE; } } else if (certType == nsIX509Cert::EMAIL_CERT) { if (trustType & nsIX509CertDB::TRUSTED_SSL) { *_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE); } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE); } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE); } else { return NS_ERROR_FAILURE; } } /* user: ignore */ return NS_OK; }
SECStatus NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA, const CERTCertificate* candidateCert, /*out*/ TrustLevel* trustLevel) { PORT_Assert(candidateCert); PORT_Assert(trustLevel); if (!candidateCert || !trustLevel) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } // XXX: CERT_GetCertTrust seems to be abusing SECStatus as a boolean, where // SECSuccess means that there is a trust record and SECFailure means there // is not a trust record. I looked at NSS's internal uses of // CERT_GetCertTrust, and all that code uses the result as a boolean meaning // "We have a trust record." CERTCertTrust trust; if (CERT_GetCertTrust(candidateCert, &trust) == SECSuccess) { PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, mCertDBTrustType); // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit, // because we can have active distrust for either type of cert. Note that // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the // relevant trust bit isn't set then that means the cert must be considered // distrusted. PRUint32 relevantTrustBit = endEntityOrCA == MustBeCA ? CERTDB_TRUSTED_CA : CERTDB_TRUSTED; if (((flags & (relevantTrustBit|CERTDB_TERMINAL_RECORD))) == CERTDB_TERMINAL_RECORD) { *trustLevel = ActivelyDistrusted; return SECSuccess; } // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Gecko hasn't // needed to consider end-entity certs to be their own trust anchors since // Gecko implemented nsICertOverrideService. if (flags & CERTDB_TRUSTED_CA) { *trustLevel = TrustAnchor; return SECSuccess; } } *trustLevel = InheritsTrust; return SECSuccess; }
static SECStatus CollectDistNames( CERTCertificate *cert, SECItem *k, void *data) { CERTDistNames *names; PRBool saveit = PR_FALSE; CERTCertTrust trust; dnameNode *node; int len; names = (CERTDistNames *)data; if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) { /* only collect names of CAs trusted for issuing SSL clients */ if ( trust.sslFlags & CERTDB_TRUSTED_CLIENT_CA ) { saveit = PR_TRUE; } } if ( saveit ) { /* allocate the node */ node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode)); if ( node == NULL ) { return(SECFailure); } /* copy the name */ node->name.len = len = cert->derSubject.len; node->name.type = siBuffer; node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len); if ( node->name.data == NULL ) { return(SECFailure); } PORT_Memcpy(node->name.data, cert->derSubject.data, len); /* link it into the list */ node->next = (dnameNode *)names->head; names->head = (void *)node; /* bump the count */ names->nnames++; } return(SECSuccess); }
static PRBool nss3certificate_isTrustedForUsage(nssDecodedCert *dc, const NSSUsage *usage) { CERTCertificate *cc; PRBool ca; SECStatus secrv; unsigned int requiredFlags; unsigned int trustFlags; SECTrustType trustType; CERTCertTrust trust; /* This is for NSS 3.3 functions that do not specify a usage */ if (usage->anyUsage) { return PR_FALSE; /* XXX is this right? */ } cc = (CERTCertificate *)dc->data; ca = usage->nss3lookingForCA; if (!ca) { PRBool trusted; unsigned int failedFlags; secrv = cert_CheckLeafTrust(cc, usage->nss3usage, &failedFlags, &trusted); return secrv == SECSuccess && trusted; } secrv = CERT_TrustFlagsForCACertUsage(usage->nss3usage, &requiredFlags, &trustType); if (secrv != SECSuccess) { return PR_FALSE; } secrv = CERT_GetCertTrust(cc, &trust); if (secrv != SECSuccess) { return PR_FALSE; } if (trustType == trustTypeNone) { /* normally trustTypeNone usages accept any of the given trust bits * being on as acceptable. */ trustFlags = trust.sslFlags | trust.emailFlags | trust.objectSigningFlags; } else { trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType); } return (trustFlags & requiredFlags) == requiredFlags; }
// Based on nsNSSCertificateDB::SetCertTrust. bool SetCertTrust(const net::X509Certificate* cert, net::CertType type, net::NSSCertDatabase::TrustBits trustBits) { const unsigned kSSLTrustBits = net::NSSCertDatabase::TRUSTED_SSL | net::NSSCertDatabase::DISTRUSTED_SSL; const unsigned kEmailTrustBits = net::NSSCertDatabase::TRUSTED_EMAIL | net::NSSCertDatabase::DISTRUSTED_EMAIL; const unsigned kObjSignTrustBits = net::NSSCertDatabase::TRUSTED_OBJ_SIGN | net::NSSCertDatabase::DISTRUSTED_OBJ_SIGN; if ((trustBits & kSSLTrustBits) == kSSLTrustBits || (trustBits & kEmailTrustBits) == kEmailTrustBits || (trustBits & kObjSignTrustBits) == kObjSignTrustBits) { LOG(ERROR) << "SetCertTrust called with conflicting trust bits " << trustBits; NOTREACHED(); return false; } SECStatus srv; CERTCertificate *nsscert = cert->os_cert_handle(); if (type == net::CA_CERT) { // Note that we start with CERTDB_VALID_CA for default trust and explicit // trust, but explicitly distrusted usages will be set to // CERTDB_TERMINAL_RECORD only. CERTCertTrust trust = {CERTDB_VALID_CA, CERTDB_VALID_CA, CERTDB_VALID_CA}; if (trustBits & net::NSSCertDatabase::DISTRUSTED_SSL) trust.sslFlags = CERTDB_TERMINAL_RECORD; else if (trustBits & net::NSSCertDatabase::TRUSTED_SSL) trust.sslFlags |= CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA; if (trustBits & net::NSSCertDatabase::DISTRUSTED_EMAIL) trust.emailFlags = CERTDB_TERMINAL_RECORD; else if (trustBits & net::NSSCertDatabase::TRUSTED_EMAIL) trust.emailFlags |= CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA; if (trustBits & net::NSSCertDatabase::DISTRUSTED_OBJ_SIGN) trust.objectSigningFlags = CERTDB_TERMINAL_RECORD; else if (trustBits & net::NSSCertDatabase::TRUSTED_OBJ_SIGN) trust.objectSigningFlags |= CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA; srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert, &trust); } else if (type == net::SERVER_CERT) { CERTCertTrust trust = {0}; // We only modify the sslFlags, so copy the other flags. CERT_GetCertTrust(nsscert, &trust); trust.sslFlags = 0; if (trustBits & net::NSSCertDatabase::DISTRUSTED_SSL) trust.sslFlags |= CERTDB_TERMINAL_RECORD; else if (trustBits & net::NSSCertDatabase::TRUSTED_SSL) trust.sslFlags |= CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD; srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert, &trust); } else { // ignore user and email/unknown certs return true; } if (srv != SECSuccess) LOG(ERROR) << "SetCertTrust failed with error " << PORT_GetError(); return srv == SECSuccess; }
SECStatus AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA, SECOidTag policy, const CERTCertificate* candidateCert, /*out*/ TrustLevel* trustLevel) { MOZ_ASSERT(policy == SEC_OID_X509_ANY_POLICY); MOZ_ASSERT(candidateCert); MOZ_ASSERT(trustLevel); MOZ_ASSERT(mTrustedRoot); if (!candidateCert || !trustLevel || policy != SEC_OID_X509_ANY_POLICY) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } if (!mTrustedRoot) { PR_SetError(PR_INVALID_STATE_ERROR, 0); return SECFailure; } // Handle active distrust of the certificate. CERTCertTrust trust; if (CERT_GetCertTrust(candidateCert, &trust) == SECSuccess) { PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning); // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit, // because we can have active distrust for either type of cert. Note that // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the // relevant trust bit isn't set then that means the cert must be considered // distrusted. PRUint32 relevantTrustBit = endEntityOrCA == MustBeCA ? CERTDB_TRUSTED_CA : CERTDB_TRUSTED; if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD))) == CERTDB_TERMINAL_RECORD) { *trustLevel = ActivelyDistrusted; return SECSuccess; } #ifdef MOZ_B2G_CERTDATA // XXX(Bug 972201): We have to allow the old way of supporting additional // roots until we fix bug 889744. Remove this along with the rest of the // MOZ_B2G_CERTDATA stuff. // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Gecko hasn't // needed to consider end-entity certs to be their own trust anchors since // Gecko implemented nsICertOverrideService. if (flags & CERTDB_TRUSTED_CA) { *trustLevel = TrustAnchor; return SECSuccess; } #endif } // mTrustedRoot is the only trust anchor for this validation. if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert)) { *trustLevel = TrustAnchor; return SECSuccess; } *trustLevel = InheritsTrust; return SECSuccess; }