Bug 399696, allow temporary certificate exceptions r=rrelyeea, a=vladimir

This commit is contained in:
kaie@kuix.de 2007-11-19 07:32:43 -08:00
Родитель 785d1dced2
Коммит 36bcdfca47
12 изменённых файлов: 98 добавлений и 131 удалений

Просмотреть файл

@ -399,3 +399,5 @@ UserCertIgnoredNoPrivateKey=This personal certificate can't be installed because
UserCertImported=Your personal certificate has been installed. You should keep a backup copy of this certificate.
CertOrgUnknown=(Unknown)
CertNotStored=(Not Stored)
CertExceptionPermanent=Permanent
CertExceptionTemporary=Temporary

Просмотреть файл

@ -95,6 +95,7 @@
<!ENTITY certmgr.certname "Certificate Name">
<!ENTITY certmgr.certserver "Server">
<!ENTITY certmgr.typesofoverrides "Exceptions">
<!ENTITY certmgr.override_lifetime "Lifetime">
<!ENTITY certmgr.tokenname "Security Device">
<!ENTITY certmgr.purpose "Purposes">
<!ENTITY certmgr.issued "Issued On">
@ -142,3 +143,5 @@
<!ENTITY exceptionMgr.certstatus.caption "Certificate Status">
<!ENTITY exceptionMgr.certstatus.viewCert "View…">
<!ENTITY exceptionMgr.certstatus.accesskey "V">
<!ENTITY exceptionMgr.permanent.label "Permanently store this exception">
<!ENTITY exceptionMgr.permanent.accesskey "P">

Просмотреть файл

@ -59,6 +59,9 @@
<treecol id="sitecol" label="&certmgr.certserver;"
persist="hidden width ordinal" flex="1"/>
<splitter class="tree-splitter"/>
<treecol id="lifetimecol" label="&certmgr.override_lifetime;"
persist="hidden width ordinal" flex="1"/>
<splitter class="tree-splitter"/>
<!-- this is too geeky, leave out for now
<treecol id="overridetypecol" label="&certmgr.typesofoverrides;"
persist="hidden width ordinal" flex="1"/>

Просмотреть файл

@ -189,6 +189,7 @@ function getURI() {
function resetDialog() {
document.getElementById("viewCertButton").disabled = true;
document.getElementById("permanent").disabled = true;
gDialog.getButton("extra1").disabled = true;
setText("headerDescription", "");
setText("statusDescription", "");
@ -263,12 +264,14 @@ function updateCertStatus() {
// In these cases, we do want to enable the "Add Exception" button
gDialog.getButton("extra1").disabled = false;
document.getElementById("permanent").disabled = false;
setText("headerDescription", gPKIBundle.GetStringFromName("addExceptionInvalidHeader"));
}
else {
shortDesc = "addExceptionValidShort";
longDesc = "addExceptionValidLong";
gDialog.getButton("extra1").disabled = true;
document.getElementById("permanent").disabled = true;
}
document.getElementById("viewCertButton").disabled = false;
@ -278,12 +281,14 @@ function updateCertStatus() {
longDesc = "addExceptionCheckingLong";
document.getElementById("viewCertButton").disabled = true;
gDialog.getButton("extra1").disabled = true;
document.getElementById("permanent").disabled = true;
}
else {
shortDesc = "addExceptionNoCertShort";
longDesc = "addExceptionNoCertLong";
document.getElementById("viewCertButton").disabled = true;
gDialog.getButton("extra1").disabled = true;
document.getElementById("permanent").disabled = true;
}
setText("statusDescription", gPKIBundle.GetStringFromName(shortDesc));
@ -328,10 +333,13 @@ function addException() {
if(gSSLStatus.isNotValidAtThisTime)
flags |= overrideService.ERROR_TIME;
var permanentCheckbox = document.getElementById("permanent");
overrideService.rememberValidityOverride(
getURI().hostPort,
gCert,
flags);
flags,
!permanentCheckbox.checked);
window.arguments[0].exceptionAdded = true;
gDialog.acceptDialog();

Просмотреть файл

@ -108,5 +108,8 @@
style="font-weight: bold; padding-bottom: 1em;"/>
<description id="status3LongDescription" style="white-space: -moz-pre-wrap;"/>
<spacer flex="1"/>
<checkbox id="permanent" checked="true" disabled="true"
label="&exceptionMgr.permanent.label;"
accesskey="&exceptionMgr.permanent.accesskey;"/>
</groupbox>
</dialog>

Просмотреть файл

@ -51,7 +51,7 @@ interface nsIX509Cert;
* {host:port, cert-fingerprint, allowed-overrides}
* that the user wants to accept without further warnings.
*/
[scriptable, uuid(7e646227-485d-49c6-8e37-e2c62cb204e1)]
[scriptable, uuid(13ca097a-935c-4a62-9c91-7a9d803ae701)]
interface nsICertOverrideService : nsISupports {
/**
@ -82,7 +82,8 @@ interface nsICertOverrideService : nsISupports {
*/
void rememberValidityOverride(in AString aHostNameWithPort,
in nsIX509Cert aCert,
in PRUint32 aOverrideBits);
in PRUint32 aOverrideBits,
in boolean aTemporary);
/**
* The given cert should always be accepted for the given hostname:port,
@ -99,7 +100,8 @@ interface nsICertOverrideService : nsISupports {
*/
boolean hasMatchingOverride(in AString aHostNameWithPort,
in nsIX509Cert aCert,
out PRUint32 aOverrideBits);
out PRUint32 aOverrideBits,
out boolean aIsTemporary);
/**
* Retrieve the stored override for the given hostname:port.
@ -115,17 +117,18 @@ interface nsICertOverrideService : nsISupports {
boolean getValidityOverride(in AString aHostNameWithPort,
out ACString aHashAlg,
out ACString aFingerprint,
out PRUint32 aOverrideBits);
out PRUint32 aOverrideBits,
out boolean aIsTemporary);
/**
* Remove a stored override for the given hostname:port.
* Remove a override for the given hostname:port.
*
* @param aHostNameWithPort The host:port whose entry should be cleared.
*/
void clearValidityOverride(in AString aHostNameWithPort);
/**
* Obtain the full list of hostname:port for which overrides are stored.
* Obtain the full list of hostname:port for which overrides are known.
*
* @param aCount The number of host:port entries returned
* @param aHostsWithPortsArray The array of host:port entries returned
@ -140,5 +143,7 @@ interface nsICertOverrideService : nsISupports {
* @return how many override entries are currently on file
* for the given certificate
*/
PRUint32 isCertUsedForOverrides(in nsIX509Cert aCert);
PRUint32 isCertUsedForOverrides(in nsIX509Cert aCert,
in boolean aCheckTemporaries,
in boolean aCheckPermanents);
};

Просмотреть файл

@ -56,10 +56,7 @@ interface nsISSLStatus : nsISupports {
* "unstrusted because missing or untrusted issuer"
* and
* "untrusted because self signed"
* compare for equality of
* nsIX509Cert::subjectName
* and
* nsIX509Cert::issuerName
* query nsIX509Cert3::isSelfSigned
*/
readonly attribute boolean isUntrusted;
};

Просмотреть файл

@ -268,7 +268,9 @@ nsCertOverrideService::Read()
nsCertOverride::OverrideBits bits;
nsCertOverride::convertStringToBits(bits_string, bits);
AddEntryToList(host, algo_string, fingerprint, bits, db_key);
AddEntryToList(host,
PR_FALSE, // not temporary
algo_string, fingerprint, bits, db_key);
}
return NS_OK;
@ -287,6 +289,8 @@ WriteEntryCallback(nsCertOverrideEntry *aEntry,
if (rawStreamPtr && aEntry)
{
const nsCertOverride &settings = aEntry->mSettings;
if (settings.mIsTemporary)
return PL_DHASH_NEXT;
nsCAutoString bits_string;
nsCertOverride::convertBitsToString(settings.mOverrideBits,
@ -401,107 +405,6 @@ GetCertFingerprintByOidTag(nsIX509Cert *aCert,
return GetCertFingerprintByOidTag(nsscert, aOidTag, fp);
}
#include <string.h>
#include "secitem.h"
#include "secport.h"
#include "secerr.h"
// FIXME: This is a temporary copy of NSS function SEC_StringToOID,
// already available on NSS trunk, but not yet delivered to
// the client application. Remove this function and the include
// statements after a new tag landed with bug 397296.
static SECStatus
_psm_copy_SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
{
PRUint32 decimal_numbers = 0;
PRUint32 result_bytes = 0;
SECStatus rv;
PRUint8 result[1024];
static const PRUint32 max_decimal = (0xffffffff / 10);
static const char OIDstring[] = {"OID."};
if (!from || !to) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (!len) {
len = PL_strlen(from);
}
if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
from += 4; /* skip leading "OID." if present */
len -= 4;
}
if (!len) {
bad_data:
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
do {
PRUint32 decimal = 0;
while (len > 0 && isdigit(*from)) {
PRUint32 addend = (*from++ - '0');
--len;
if (decimal > max_decimal) /* overflow */
goto bad_data;
decimal = (decimal * 10) + addend;
if (decimal < addend) /* overflow */
goto bad_data;
}
if (len != 0 && *from != '.') {
goto bad_data;
}
if (decimal_numbers == 0) {
if (decimal > 2)
goto bad_data;
result[0] = decimal * 40;
result_bytes = 1;
} else if (decimal_numbers == 1) {
if (decimal > 40)
goto bad_data;
result[0] += decimal;
} else {
/* encode the decimal number, */
PRUint8 * rp;
PRUint32 num_bytes = 0;
PRUint32 tmp = decimal;
while (tmp) {
num_bytes++;
tmp >>= 7;
}
if (!num_bytes )
++num_bytes; /* use one byte for a zero value */
if (num_bytes + result_bytes > sizeof result)
goto bad_data;
tmp = num_bytes;
rp = result + result_bytes - 1;
rp[tmp] = (PRUint8)(decimal & 0x7f);
decimal >>= 7;
while (--tmp > 0) {
rp[tmp] = (PRUint8)(decimal | 0x80);
decimal >>= 7;
}
result_bytes += num_bytes;
}
++decimal_numbers;
if (len > 0) { /* skip trailing '.' */
++from;
--len;
}
} while (len > 0);
/* now result contains result_bytes of data */
if (to->data && to->len >= result_bytes) {
PORT_Memcpy(to->data, result, to->len = result_bytes);
rv = SECSuccess;
} else {
SECItem result_item = {siBuffer, NULL, 0 };
result_item.data = result;
result_item.len = result_bytes;
rv = SECITEM_CopyItem(pool, to, &result_item);
}
return rv;
}
static nsresult
GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
const nsCString &dottedOid,
@ -510,7 +413,7 @@ GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
SECItem oid;
oid.data = nsnull;
oid.len = 0;
SECStatus srv = _psm_copy_SEC_StringToOID(nsnull, &oid,
SECStatus srv = SEC_StringToOID(nsnull, &oid,
dottedOid.get(), dottedOid.Length());
if (srv != SECSuccess)
return NS_ERROR_FAILURE;
@ -544,7 +447,8 @@ GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
NS_IMETHODIMP
nsCertOverrideService::RememberValidityOverride(const nsAString & aHostNameWithPort,
nsIX509Cert *aCert,
PRUint32 aOverrideBits)
PRUint32 aOverrideBits,
PRBool aTemporary)
{
NS_ENSURE_ARG_POINTER(aCert);
if (aHostNameWithPort.IsEmpty())
@ -607,7 +511,9 @@ nsCertOverrideService::RememberValidityOverride(const nsAString & aHostNameWithP
{
nsAutoMonitor lock(monitor);
AddEntryToList(myHostPort, mDottedOidForStoringNewHashes, fpStr,
AddEntryToList(myHostPort,
aTemporary,
mDottedOidForStoringNewHashes, fpStr,
(nsCertOverride::OverrideBits)aOverrideBits,
nsDependentCString(dbkey));
Write();
@ -621,6 +527,7 @@ NS_IMETHODIMP
nsCertOverrideService::HasMatchingOverride(const nsAString & aHostNameWithPort,
nsIX509Cert *aCert,
PRUint32 *aOverrideBits,
PRBool *aIsTemporary,
PRBool *_retval)
{
if (aHostNameWithPort.IsEmpty())
@ -628,6 +535,7 @@ nsCertOverrideService::HasMatchingOverride(const nsAString & aHostNameWithPort,
NS_ENSURE_ARG_POINTER(aCert);
NS_ENSURE_ARG_POINTER(aOverrideBits);
NS_ENSURE_ARG_POINTER(aIsTemporary);
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
*aOverrideBits = nsCertOverride::ob_None;
@ -646,6 +554,7 @@ nsCertOverrideService::HasMatchingOverride(const nsAString & aHostNameWithPort,
}
*aOverrideBits = settings.mOverrideBits;
*aIsTemporary = settings.mIsTemporary;
nsCAutoString fpStr;
nsresult rv;
@ -668,9 +577,11 @@ nsCertOverrideService::GetValidityOverride(const nsAString & aHostNameWithPort,
nsACString & aHashAlg,
nsACString & aFingerprint,
PRUint32 *aOverrideBits,
PRBool *aIsTemporary,
PRBool *_found)
{
NS_ENSURE_ARG_POINTER(_found);
NS_ENSURE_ARG_POINTER(aIsTemporary);
NS_ENSURE_ARG_POINTER(aOverrideBits);
*_found = PR_FALSE;
*aOverrideBits = nsCertOverride::ob_None;
@ -690,6 +601,7 @@ nsCertOverrideService::GetValidityOverride(const nsAString & aHostNameWithPort,
if (*_found) {
*aOverrideBits = settings.mOverrideBits;
*aIsTemporary = settings.mIsTemporary;
aFingerprint = settings.mFingerprint;
aHashAlg = settings.mFingerprintAlgOID;
}
@ -699,6 +611,7 @@ nsCertOverrideService::GetValidityOverride(const nsAString & aHostNameWithPort,
nsresult
nsCertOverrideService::AddEntryToList(const nsACString &hostWithPortUTF8,
const PRBool aIsTemporary,
const nsACString &fingerprintAlgOID,
const nsACString &fingerprint,
nsCertOverride::OverrideBits ob,
@ -717,6 +630,7 @@ nsCertOverrideService::AddEntryToList(const nsACString &hostWithPortUTF8,
nsCertOverride &settings = entry->mSettings;
settings.mHostWithPortUTF8 = hostWithPortUTF8;
settings.mIsTemporary = aIsTemporary;
settings.mFingerprintAlgOID = fingerprintAlgOID;
settings.mFingerprint = fingerprint;
settings.mOverrideBits = ob;
@ -793,9 +707,11 @@ matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
return !found_mismatch;
}
struct nsCertAndInt
struct nsCertAndBoolsAndInt
{
nsIX509Cert *cert;
PRBool aCheckTemporaries;
PRBool aCheckPermanents;
PRUint32 counter;
SECOidTag mOidTagForStoringNewHashes;
@ -806,12 +722,20 @@ PR_STATIC_CALLBACK(PLDHashOperator)
FindMatchingCertCallback(nsCertOverrideEntry *aEntry,
void *aArg)
{
nsCertAndInt *cai = (nsCertAndInt *)aArg;
nsCertAndBoolsAndInt *cai = (nsCertAndBoolsAndInt *)aArg;
if (cai && aEntry)
{
const nsCertOverride &settings = aEntry->mSettings;
if (matchesDBKey(cai->cert, settings.mDBKey.get())) {
PRBool still_ok = PR_TRUE;
if ((settings.mIsTemporary && !cai->aCheckTemporaries)
||
(!settings.mIsTemporary && !cai->aCheckPermanents)) {
still_ok = PR_FALSE;
}
if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
nsCAutoString cert_fingerprint;
nsresult rv;
if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
@ -834,13 +758,17 @@ FindMatchingCertCallback(nsCertOverrideEntry *aEntry,
NS_IMETHODIMP
nsCertOverrideService::IsCertUsedForOverrides(nsIX509Cert *aCert,
PRBool aCheckTemporaries,
PRBool aCheckPermanents,
PRUint32 *_retval)
{
NS_ENSURE_ARG(aCert);
NS_ENSURE_ARG(_retval);
nsCertAndInt cai;
nsCertAndBoolsAndInt cai;
cai.cert = aCert;
cai.aCheckTemporaries = aCheckTemporaries;
cai.aCheckPermanents = aCheckPermanents;
cai.counter = 0;
cai.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
cai.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;

Просмотреть файл

@ -68,6 +68,7 @@ public:
nsCertOverride &operator=(const nsCertOverride &other)
{
mHostWithPortUTF8 = other.mHostWithPortUTF8;
mIsTemporary = other.mIsTemporary;
mFingerprintAlgOID = other.mFingerprintAlgOID;
mFingerprint = other.mFingerprint;
mOverrideBits = other.mOverrideBits;
@ -76,6 +77,7 @@ public:
}
nsCString mHostWithPortUTF8;
PRBool mIsTemporary; // true: session only, false: stored on disk
nsCString mFingerprint;
nsCString mFingerprintAlgOID;
OverrideBits mOverrideBits;
@ -183,6 +185,7 @@ protected:
nsresult Read();
nsresult Write();
nsresult AddEntryToList(const nsACString &hostWithPortUTF8,
const PRBool aIsTemporary,
const nsACString &algo_oid,
const nsACString &fingerprint,
nsCertOverride::OverrideBits ob,

Просмотреть файл

@ -144,6 +144,7 @@ nsCertTreeDispInfo::nsCertTreeDispInfo()
:mAddonInfo(nsnull)
,mTypeOfEntry(direct_db)
,mOverrideBits(nsCertOverride::ob_None)
,mIsTemporary(PR_TRUE)
{
}
@ -153,6 +154,7 @@ nsCertTreeDispInfo::nsCertTreeDispInfo(nsCertTreeDispInfo &other)
mTypeOfEntry = other.mTypeOfEntry;
mHostWithPort = other.mHostWithPort;
mOverrideBits = other.mOverrideBits;
mIsTemporary = other.mIsTemporary;
}
nsCertTreeDispInfo::~nsCertTreeDispInfo()
@ -389,6 +391,7 @@ MatchingCertOverridesCallback(const nsCertOverride &aSettings,
certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override;
certdi->mHostWithPort = NS_ConvertUTF8toUTF16(aSettings.mHostWithPortUTF8);
certdi->mOverrideBits = aSettings.mOverrideBits;
certdi->mIsTemporary = aSettings.mIsTemporary;
NS_IF_ADDREF(certdi);
cap->array->InsertElementAt(cap->position, certdi);
cap->position++;
@ -445,6 +448,7 @@ AddRemaningHostPortOverridesCallback(const nsCertOverride &aSettings,
certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override;
certdi->mHostWithPort = NS_ConvertUTF8toUTF16(aSettings.mHostWithPortUTF8);
certdi->mOverrideBits = aSettings.mOverrideBits;
certdi->mIsTemporary = aSettings.mIsTemporary;
NS_IF_ADDREF(certdi);
cap->array->InsertElementAt(cap->position, certdi);
cap->position++;
@ -560,8 +564,11 @@ nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
if (wantThisCertIfNoOverrides || wantThisCertIfHaveOverrides) {
PRUint32 ocount = 0;
nsresult rv = mOverrideService->IsCertUsedForOverrides(pipCert, &ocount);
nsresult rv =
mOverrideService->IsCertUsedForOverrides(pipCert,
PR_TRUE, // we want temporaries
PR_TRUE, // we want permanents
&ocount);
if (wantThisCertIfNoOverrides) {
if (NS_FAILED(rv) || ocount == 0) {
// no overrides for this cert
@ -606,6 +613,7 @@ nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
certdi->mTypeOfEntry = nsCertTreeDispInfo::direct_db;
// not necessary: certdi->mHostWithPort.Clear();
certdi->mOverrideBits = nsCertOverride::ob_None;
certdi->mIsTemporary = PR_FALSE;
mDispInfo.InsertElementAt(InsertPosition, certdi);
++count;
++InsertPosition;
@ -1237,6 +1245,10 @@ nsCertTree::GetCellText(PRInt32 row, nsITreeColumn* col,
else {
_retval = NS_LITERAL_STRING("*");
}
} else if (NS_LITERAL_STRING("lifetimecol").Equals(colID)) {
const char *stringID =
(certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent";
rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval);
} else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) {
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
PRUint32 type = nsIX509Cert::UNKNOWN_CERT;

Просмотреть файл

@ -100,6 +100,7 @@ public:
} mTypeOfEntry;
nsString mHostWithPort;
nsCertOverride::OverrideBits mOverrideBits;
PRBool mIsTemporary;
};
class nsCertTree : public nsICertTree

Просмотреть файл

@ -2720,20 +2720,22 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
// it is fine to continue without the nsICertOverrideService
PRUint32 storedOverrideBits = 0;
PRUint32 overrideBits = 0;
if (overrideService)
{
PRBool haveStoredOverride;
PRBool haveOverride;
PRBool isTemporaryOverride; // we don't care
nsrv = overrideService->HasMatchingOverride(hostWithPortStringUTF16,
ix509,
&storedOverrideBits,
&haveStoredOverride);
if (NS_SUCCEEDED(nsrv) && haveStoredOverride)
&overrideBits,
&isTemporaryOverride,
&haveOverride);
if (NS_SUCCEEDED(nsrv) && haveOverride)
{
// remove the errors that are already overriden
remaining_display_errors -= storedOverrideBits;
remaining_display_errors -= overrideBits;
}
}