Bug 387480, Support network-fetched cert import in Web Sites tab of Cert Mgr Most code contributed by Johnathan Nightingale, some by me r=me, sr=rrelyea blocking1.9=beltzner

This commit is contained in:
kaie@kuix.de 2007-10-03 04:56:06 -07:00
parent 4826252f22
commit 4a67feba15
8 changed files with 449 additions and 2 deletions

View File

@ -39,7 +39,7 @@
<!ENTITY certmgr.tab.mine "Your Certificates">
<!ENTITY certmgr.tab.others "Other People's">
<!ENTITY certmgr.tab.websites "Web Sites">
<!ENTITY certmgr.tab.websites2 "Internet Sites">
<!ENTITY certmgr.tab.ca "Authorities">
<!ENTITY certmgr.tab.orphan "Extra">
@ -128,3 +128,14 @@
<!ENTITY certmgr.fields.accesskey "V">
<!ENTITY certmgr.hierarchy.label "Certificate Hierarchy">
<!ENTITY certmgr.hierarchy.accesskey "C">
<!ENTITY certmgr.addException.label "Add Exception…">
<!ENTITY certmgr.addException.accesskey "x">
<!ENTITY exceptionMgr.title "Add Security Exception">
<!ENTITY exceptionMgr.exceptionButton "Confirm Security Exception">
<!ENTITY exceptionMgr.supplementalWarning "Legitimate banks, stores, and other public sites will not ask you to do this.">
<!ENTITY exceptionMgr.certlocation.caption "Internet Site">
<!ENTITY exceptionMgr.certlocation.url "Location:">
<!ENTITY exceptionMgr.certlocation.download "Get Certificate">
<!ENTITY exceptionMgr.certstatus.caption "Certificate Status">
<!ENTITY exceptionMgr.certstatus.viewCert "View…">

View File

@ -199,3 +199,20 @@ writeFileAccessDenied=Access denied
writeFileIsLocked=File is locked
writeFileNoDeviceSpace=No space left on device
writeFileUnknownError=Unknown error
#Add Security Exception dialog
addExceptionBrandedWarning=You are about to override how %S identifies sites.
addExceptionInvalidHeader=This site attempts to identity itself with invalid information.
addExceptionDomainMismatchShort=Wrong Site
addExceptionDomainMismatchLong=Certificate belongs to a different site, which could indicate an identity theft.
addExceptionExpiredShort=Outdated Information
addExceptionExpiredLong=Certificate is not currently valid. It is impossible to verify whether this identity was reported as stolen or lost.
addExceptionUnverifiedShort=Unknown Identity
addExceptionUnverifiedLong=Certificate is not trusted, because it hasn't been verified by a recognized authority.
addExceptionValidShort=Valid Certificate
addExceptionValidLong=This site provides valid, verified identification. There is no need to add an exception.
addExceptionCheckingShort=Checking Information
addExceptionCheckingLong=Attempting to identify the site...
addExceptionNoCertShort=No Information Available
addExceptionNoCertLong=Unable to obtain identification status for the given site.
addExceptionConnectionFailed=Connection Failed

View File

@ -100,6 +100,10 @@
label="&certmgr.delete2.label;"
accesskey="&certmgr.delete.accesskey;"
disabled="true" oncommand="deleteCerts();"/>
<button id="websites_exceptionButton"
label="&certmgr.addException.label;"
accesskey="&certmgr.addException.accesskey;"
oncommand="addException();"/>
</hbox>
</vbox>
</overlay>

View File

@ -620,3 +620,16 @@ function addWebSiteCert()
caTreeView.selection.clearSelection();
}
}
function addException()
{
window.openDialog('chrome://pippki/content/exceptionDialog.xul', "",
'chrome,centerscreen,modal');
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
certcache.cacheAllCerts();
serverTreeView.loadCertsFromCache(certcache, nsIX509Cert.SERVER_CERT);
serverTreeView.selection.clearSelection();
orphanTreeView.loadCertsFromCache(certcache, nsIX509Cert.UNKNOWN_CERT);
orphanTreeView.selection.clearSelection();
}

View File

@ -65,7 +65,7 @@
<tabs id="certMgrTabbox">
<tab id="mine_tab" label="&certmgr.tab.mine;"/>
<tab id="others_tab" label="&certmgr.tab.others;"/>
<tab id="websites_tab" label="&certmgr.tab.websites;"/>
<tab id="websites_tab" label="&certmgr.tab.websites2;"/>
<!-- FIXME Add selected="true" to ca_tab when 373525 gets fixed. -->
<tab id="ca_tab" label="&certmgr.tab.ca;"/>
<tab id="orphan_tab" label="&certmgr.tab.orphan;"/>

View File

@ -0,0 +1,294 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Johnathan Nightingale <johnath@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var gDialog;
var gBundleBrand;
var gPKIBundle;
var gSSLStatus;
var gCert;
var gChecking;
var gBroken;
var gNeedReset;
function badCertListener() {}
badCertListener.prototype = {
getInterface: function (aIID) {
return this.QueryInterface(aIID);
},
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIBadCertListener2) ||
aIID.equals(Components.interfaces.nsIInterfaceRequestor) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
handle_test_result: function () {
if (gSSLStatus)
gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
},
notifyCertProblem: function MSR_notifyCertProblem(socketInfo, sslStatus, targetHost) {
gBroken = true;
gSSLStatus = sslStatus;
this.handle_test_result();
return true; // suppress error UI
}
}
function initExceptionDialog() {
gNeedReset = false;
gDialog = document.documentElement;
gBundleBrand = srGetStrBundle("chrome://branding/locale/brand.properties");
gPKIBundle = srGetStrBundle("chrome://pippki/locale/pippki.properties");
var brandName = gBundleBrand.GetStringFromName("brandShortName");
setText("warningText", gPKIBundle.formatStringFromName("addExceptionBrandedWarning",
[brandName], 1));
gDialog.getButton("extra1").disabled = true;
}
/**
* Attempt to download the certificate for the location specified, and populate
* the Certificate Status section with the result.
*/
function checkCert() {
gCert = null;
gSSLStatus = null;
gChecking = true;
gBroken = false;
updateCertStatus();
var req = new XMLHttpRequest();
var uri = getURI();
try {
if(uri) {
req.open('GET', uri.prePath, false);
req.channel.notificationCallbacks = new badCertListener();
req.send(null);
}
} catch (e) {
// We *expect* exceptions if there are problems with the certificate
// presented by the site. Log it, just in case, but we can proceed here,
// with appropriate sanity checks
Components.utils.reportError(e);
} finally {
gChecking = false;
}
if(req.channel && req.channel.securityInfo) {
const Ci = Components.interfaces;
gSSLStatus = req.channel.securityInfo
.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
gCert = gSSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
}
updateCertStatus();
}
/**
* Build and return a URI, based on the information supplied in the
* Certificate Location fields
*/
function getURI() {
// Use fixup service instead of just ioservice's newURI since it's quite likely
// that the host will be supplied without a protocol prefix, resulting in malformed
// uri exceptions being thrown.
var fus = Components.classes["@mozilla.org/docshell/urifixup;1"]
.getService(Components.interfaces.nsIURIFixup);
var uri = fus.createFixupURI(document.getElementById("locationTextBox").value, 0);
if(!uri)
return null;
if(uri.scheme == "http")
uri.scheme = "https";
if (uri.port == -1)
uri.port = 443;
return uri;
}
function resetDialog() {
document.getElementById("viewCertButton").disabled = true;
gDialog.getButton("extra1").disabled = true;
setText("headerDescription", "");
setText("statusDescription", "");
setText("statusLongDescription", "");
setText("status2Description", "");
setText("status2LongDescription", "");
setText("status3Description", "");
setText("status3LongDescription", "");
}
/**
* Called by input textboxes to manage UI state
*/
function handleTextChange() {
var checkCertButton = document.getElementById('checkCertButton');
checkCertButton.disabled = !(document.getElementById("locationTextBox").value);
if (gNeedReset) {
gNeedReset = false;
resetDialog();
}
}
function updateCertStatus() {
var shortDesc, longDesc;
var shortDesc2, longDesc2;
var shortDesc3, longDesc3;
var use2 = false;
var use3 = false;
if(gCert) {
if(gBroken) {
var mms = "addExceptionDomainMismatchShort";
var mml = "addExceptionDomainMismatchLong";
var exs = "addExceptionExpiredShort";
var exl = "addExceptionExpiredLong";
var uts = "addExceptionUnverifiedShort";
var utl = "addExceptionUnverifiedLong";
var use1 = false;
if (gSSLStatus.isDomainMismatch) {
use1 = true;
shortDesc = mms;
longDesc = mml;
}
if (gSSLStatus.isNotValidAtThisTime) {
if (!use1) {
use1 = true;
shortDesc = exs;
longDesc = exl;
}
else {
use2 = true;
shortDesc2 = exs;
longDesc2 = exl;
}
}
if (gSSLStatus.isUntrusted) {
if (!use1) {
use1 = true;
shortDesc = uts;
longDesc = utl;
}
else if (!use2) {
use2 = true;
shortDesc2 = uts;
longDesc2 = utl;
}
else {
use3 = true;
shortDesc3 = uts;
longDesc3 = utl;
}
}
// In these cases, we do want to enable the "Add Exception" button
gDialog.getButton("extra1").disabled = false;
setText("headerDescription", gPKIBundle.GetStringFromName("addExceptionInvalidHeader"));
}
else {
shortDesc = "addExceptionValidShort";
longDesc = "addExceptionValidLong";
gDialog.getButton("extra1").disabled = true;
}
document.getElementById("viewCertButton").disabled = false;
}
else if (gChecking) {
shortDesc = "addExceptionCheckingShort";
longDesc = "addExceptionCheckingLong";
document.getElementById("viewCertButton").disabled = true;
gDialog.getButton("extra1").disabled = true;
}
else {
shortDesc = "addExceptionNoCertShort";
longDesc = "addExceptionNoCertLong";
document.getElementById("viewCertButton").disabled = true;
gDialog.getButton("extra1").disabled = true;
}
setText("statusDescription", gPKIBundle.GetStringFromName(shortDesc));
setText("statusLongDescription", gPKIBundle.GetStringFromName(longDesc));
if (use2) {
setText("status2Description", gPKIBundle.GetStringFromName(shortDesc2));
setText("status2LongDescription", gPKIBundle.GetStringFromName(longDesc2));
}
if (use3) {
setText("status3Description", gPKIBundle.GetStringFromName(shortDesc3));
setText("status3LongDescription", gPKIBundle.GetStringFromName(longDesc3));
}
gNeedReset = true;
}
/**
* Handle user request to display certificate details
*/
function viewCertButtonClick() {
if (gCert)
viewCertHelper(this, gCert);
}
/**
* Handle user request to add an exception for the specified cert
*/
function addException() {
if(!gCert || !gSSLStatus)
return;
var overrideService = Components.classes["@mozilla.org/security/certoverride;1"]
.getService(Components.interfaces.nsICertOverrideService);
var flags = 0;
if(gSSLStatus.isUntrusted)
flags |= overrideService.ERROR_UNTRUSTED;
if(gSSLStatus.isDomainMismatch)
flags |= overrideService.ERROR_MISMATCH;
if(gSSLStatus.isNotValidAtThisTime)
flags |= overrideService.ERROR_TIME;
overrideService.rememberValidityOverride(
getURI().hostPort,
gCert,
flags);
gDialog.acceptDialog();
}

View File

@ -0,0 +1,106 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is mozilla.org code.
-
- The Initial Developer of the Original Code is
- Mozilla Corp
- Portions created by the Initial Developer are Copyright (C) 2007
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Kai Engert <kengert@redhat.com>
- Johnathan Nightingale <johnath@mozilla.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://pippki/locale/certManager.dtd">
<dialog id="exceptiondialog"
windowtype="mozilla:exceptiondialog"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&exceptionMgr.title;"
buttons="cancel,extra1"
buttonlabelextra1="&exceptionMgr.exceptionButton;"
style="width: 500px; height: 480px;"
onload="initExceptionDialog();"
ondialogextra1="addException();"
persist="screenX screenY width height"
defaultButton="null">
<script type="application/x-javascript" src="chrome://global/content/strres.js"/>
<script type="application/x-javascript" src="chrome://pippki/content/pippki.js"/>
<script type="application/x-javascript" src="chrome://pippki/content/exceptionDialog.js"/>
<hbox>
<vbox>
<image src="chrome://global/skin/icons/warning-large.png"/>
<spacer flex="1"/>
</vbox>
<vbox flex="1">
<description id="warningText"
style="whitespace: -moz-pre-wrap"/>
<description id="warningSupplemental"
style="font-weight: bold; whitespace: -moz-pre-wrap;">
&exceptionMgr.supplementalWarning;
</description>
</vbox>
</hbox>
<groupbox id="locationGroupBox">
<caption label="&exceptionMgr.certlocation.caption;"/>
<hbox align="center">
<label control="locationTextBox" value="&exceptionMgr.certlocation.url;"/>
<textbox id="locationTextBox" flex="1" oninput="handleTextChange();" value="https://"/>
<button id="checkCertButton" disabled="true"
label="&exceptionMgr.certlocation.download;" onclick="checkCert();"/>
</hbox>
</groupbox>
<groupbox id="certStatusGroupBox" flex="1">
<caption label="&exceptionMgr.certstatus.caption;"/>
<hbox>
<description id="headerDescription" style="whitespace: -moz-pre-wrap;"
flex="1"/>
<vbox>
<button id="viewCertButton" label="&exceptionMgr.certstatus.viewCert;"
disabled="true" onclick="viewCertButtonClick();"/>
</vbox>
</hbox>
<description id="statusDescription"
style="font-weight: bold; padding-bottom: 1em;"/>
<description id="statusLongDescription" style="whitespace: -moz-pre-wrap;"/>
<description id="status2Description"
style="font-weight: bold; padding-bottom: 1em;"/>
<description id="status2LongDescription" style="whitespace: -moz-pre-wrap;"/>
<description id="status3Description"
style="font-weight: bold; padding-bottom: 1em;"/>
<description id="status3LongDescription" style="whitespace: -moz-pre-wrap;"/>
<spacer flex="1"/>
</groupbox>
</dialog>

View File

@ -31,6 +31,8 @@ pippki.jar:
content/pippki/editemailcert.xul (content/editemailcert.xul)
content/pippki/editsslcert.xul (content/editsslcert.xul)
content/pippki/editcerts.js (content/editcerts.js)
content/pippki/exceptionDialog.xul (content/exceptionDialog.xul)
content/pippki/exceptionDialog.js (content/exceptionDialog.js)
content/pippki/deletecert.xul (content/deletecert.xul)
content/pippki/deletecert.js (content/deletecert.js)
content/pippki/viewCertDetails.js (content/viewCertDetails.js)