Bug 683883 - Improve DigitNotarGate handling in PSM; r=rrelyea

This commit is contained in:
Kai Engert 2011-09-02 13:58:32 -04:00
parent 71d64d5d55
commit 472f2f1189

View File

@ -1038,9 +1038,43 @@ static struct nsSerialBinaryBlacklistEntry myUTNBlacklistEntries[] = {
{ 0, 0 } // end marker
};
// Bug 682927: Do not trust any DigiNotar-issued certificates.
// We do this check after normal certificate validation because we do not
// want to override a "revoked" OCSP response.
// Call this if we have already decided that a cert should be treated as INVALID,
// in order to check if we to worsen the error to REVOKED.
PRErrorCode
PSM_SSL_DigiNotarTreatAsRevoked(CERTCertificate * serverCert,
CERTCertList * serverCertChain)
{
// If any involved cert was issued by DigiNotar,
// and serverCert was issued after 01-JUL-2011,
// then worsen the error to revoked.
PRTime cutoff = 0;
PRStatus status = PR_ParseTimeString("01-JUL-2011 00:00", PR_TRUE, &cutoff);
if (status != PR_SUCCESS) {
NS_ASSERTION(status == PR_SUCCESS, "PR_ParseTimeString failed");
// be safe, assume it's afterwards, keep going
} else {
PRTime notBefore = 0, notAfter = 0;
if (CERT_GetCertTimes(serverCert, &notBefore, &notAfter) == SECSuccess &&
notBefore < cutoff) {
// no worsening for certs issued before the cutoff date
return 0;
}
}
for (CERTCertListNode *node = CERT_LIST_HEAD(serverCertChain);
!CERT_LIST_END(node, serverCertChain);
node = CERT_LIST_NEXT(node)) {
if (node->cert->issuerName &&
strstr(node->cert->issuerName, "CN=DigiNotar")) {
return SEC_ERROR_REVOKED_CERTIFICATE;
}
}
return 0;
}
// Call this only if a cert has been reported by NSS as VALID
PRErrorCode
PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert,
CERTCertList * serverCertChain)
@ -1053,28 +1087,30 @@ PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert,
if (!node->cert->issuerName)
continue;
// If it's one of the "Staat der Nederlanden Root"s, then don't blacklist.
// Compare names, and ensure it's a self-signed root.
if ((!strcmp(node->cert->issuerName,
"CN=Staat der Nederlanden Root CA,O=Staat der Nederlanden,C=NL") ||
!strcmp(node->cert->issuerName,
"CN=Staat der Nederlanden Root CA - G2,O=Staat der Nederlanden,C=NL")) &&
SECITEM_ItemsAreEqual(&node->cert->derIssuer,&node->cert->derSubject)
) {
// keep as valid
return 0;
}
if (strstr(node->cert->issuerName, "CN=DigiNotar")) {
isDigiNotarIssuedCert = PR_TRUE;
// Do not let the user override the error if the cert was
// chained from the "DigiNotar Root CA" cert and the cert was issued
// within the time window in which we think the mis-issuance(s) occurred.
if (strstr(node->cert->issuerName, "CN=DigiNotar Root CA")) {
PRTime cutoff = 0, notBefore = 0, notAfter = 0;
PRStatus status = PR_ParseTimeString("01-JUL-2011 00:00", PR_TRUE, &cutoff);
NS_ASSERTION(status == PR_SUCCESS, "PR_ParseTimeString failed");
if (status != PR_SUCCESS ||
CERT_GetCertTimes(serverCert, &notBefore, &notAfter) != SECSuccess ||
notBefore >= cutoff) {
return SEC_ERROR_REVOKED_CERTIFICATE;
}
}
}
}
if (isDigiNotarIssuedCert)
return SEC_ERROR_UNTRUSTED_ISSUER; // user can override this
else
return 0; // No DigiNotor cert => carry on as normal
if (isDigiNotarIssuedCert) {
// let's see if we want to worsen the error code to revoked.
PRErrorCode revoked_code = PSM_SSL_DigiNotarTreatAsRevoked(serverCert, serverCertChain);
return (revoked_code != 0) ? revoked_code : SEC_ERROR_UNTRUSTED_ISSUER;
}
return 0;
}
@ -1140,19 +1176,28 @@ SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
}
CERTCertList *certList = nsnull;
if (rv == SECSuccess) {
certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA);
if (!certList) {
rv = SECFailure;
} else {
PRErrorCode blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(serverCert,
certList);
if (blacklistErrorCode != 0) {
infoObject->SetCertIssuerBlacklisted();
PORT_SetError(blacklistErrorCode);
rv = SECFailure;
certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA);
if (!certList) {
rv = SECFailure;
} else {
PRErrorCode blacklistErrorCode;
if (rv == SECSuccess) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(serverCert, certList);
} else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
PRErrorCode savedErrorCode = PORT_GetError();
// Check if we want to worsen the error code to "revoked".
blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(serverCert, certList);
if (blacklistErrorCode == 0) {
// we don't worsen the code, let's keep the original error code from NSS
PORT_SetError(savedErrorCode);
}
}
if (blacklistErrorCode != 0) {
infoObject->SetCertIssuerBlacklisted();
PORT_SetError(blacklistErrorCode);
rv = SECFailure;
}
}
if (rv == SECSuccess) {