forked from mirrors/gecko-dev
Bug 1561435 - Format security/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D35928 --HG-- extra : source : 4e926f91b17c2b13cdaf13e017629286275dbc00
This commit is contained in:
parent
77c95c13f4
commit
858f3b554b
148 changed files with 12291 additions and 6121 deletions
|
|
@ -45,7 +45,6 @@ module.exports = {
|
|||
"overrides": [{
|
||||
"files": [
|
||||
"devtools/**",
|
||||
"security/**",
|
||||
"services/**",
|
||||
"servo/**",
|
||||
"startupcache/**",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
|
|||
toolkit/components/telemetry/healthreport-prefs.js
|
||||
|
||||
# Ignore all top-level directories for now.
|
||||
security/**
|
||||
services/**
|
||||
servo/**
|
||||
startupcache/**
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
|||
|
||||
var key;
|
||||
|
||||
var certdialogs = Cc["@mozilla.org/nsCertificateDialogs;1"].getService(Ci.nsICertificateDialogs);
|
||||
var certdialogs = Cc["@mozilla.org/nsCertificateDialogs;1"].getService(
|
||||
Ci.nsICertificateDialogs
|
||||
);
|
||||
|
||||
/**
|
||||
* List of certs currently selected in the active tab.
|
||||
|
|
@ -43,26 +45,32 @@ var emailTreeView;
|
|||
var userTreeView;
|
||||
|
||||
function LoadCerts() {
|
||||
certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
|
||||
certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
var certcache = certdb.getCerts();
|
||||
|
||||
caTreeView = Cc["@mozilla.org/security/nsCertTree;1"]
|
||||
.createInstance(Ci.nsICertTree);
|
||||
caTreeView = Cc["@mozilla.org/security/nsCertTree;1"].createInstance(
|
||||
Ci.nsICertTree
|
||||
);
|
||||
caTreeView.loadCertsFromCache(certcache, Ci.nsIX509Cert.CA_CERT);
|
||||
document.getElementById("ca-tree").view = caTreeView;
|
||||
|
||||
serverTreeView = Cc["@mozilla.org/security/nsCertTree;1"]
|
||||
.createInstance(Ci.nsICertTree);
|
||||
serverTreeView = Cc["@mozilla.org/security/nsCertTree;1"].createInstance(
|
||||
Ci.nsICertTree
|
||||
);
|
||||
serverTreeView.loadCertsFromCache(certcache, Ci.nsIX509Cert.SERVER_CERT);
|
||||
document.getElementById("server-tree").view = serverTreeView;
|
||||
|
||||
emailTreeView = Cc["@mozilla.org/security/nsCertTree;1"]
|
||||
.createInstance(Ci.nsICertTree);
|
||||
emailTreeView = Cc["@mozilla.org/security/nsCertTree;1"].createInstance(
|
||||
Ci.nsICertTree
|
||||
);
|
||||
emailTreeView.loadCertsFromCache(certcache, Ci.nsIX509Cert.EMAIL_CERT);
|
||||
document.getElementById("email-tree").view = emailTreeView;
|
||||
|
||||
userTreeView = Cc["@mozilla.org/security/nsCertTree;1"]
|
||||
.createInstance(Ci.nsICertTree);
|
||||
userTreeView = Cc["@mozilla.org/security/nsCertTree;1"].createInstance(
|
||||
Ci.nsICertTree
|
||||
);
|
||||
userTreeView.loadCertsFromCache(certcache, Ci.nsIX509Cert.USER_CERT);
|
||||
document.getElementById("user-tree").view = userTreeView;
|
||||
|
||||
|
|
@ -92,7 +100,9 @@ function getSelectedCerts() {
|
|||
selected_certs = [];
|
||||
var cert = null;
|
||||
var nr = 0;
|
||||
if (items != null) nr = items.getRangeCount();
|
||||
if (items != null) {
|
||||
nr = items.getRangeCount();
|
||||
}
|
||||
if (nr > 0) {
|
||||
for (let i = 0; i < nr; i++) {
|
||||
var o1 = {};
|
||||
|
|
@ -140,7 +150,9 @@ function getSelectedTreeItems() {
|
|||
selected_index = [];
|
||||
var tree_item = null;
|
||||
var nr = 0;
|
||||
if (items != null) nr = items.getRangeCount();
|
||||
if (items != null) {
|
||||
nr = items.getRangeCount();
|
||||
}
|
||||
if (nr > 0) {
|
||||
for (let i = 0; i < nr; i++) {
|
||||
var o1 = {};
|
||||
|
|
@ -225,7 +237,7 @@ async function promptError(aErrorCode) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
let [message] = await document.l10n.formatValues([{id: msgName}]);
|
||||
let [message] = await document.l10n.formatValues([{ id: msgName }]);
|
||||
let prompter = Services.ww.getNewPrompter(window);
|
||||
prompter.alert(null, message);
|
||||
}
|
||||
|
|
@ -258,11 +270,7 @@ function ca_enableButtons() {
|
|||
}
|
||||
|
||||
function mine_enableButtons() {
|
||||
let idList = [
|
||||
"mine_viewButton",
|
||||
"mine_backupButton",
|
||||
"mine_deleteButton",
|
||||
];
|
||||
let idList = ["mine_viewButton", "mine_backupButton", "mine_deleteButton"];
|
||||
enableButtonsForCertTree(userTreeView, idList);
|
||||
}
|
||||
|
||||
|
|
@ -276,11 +284,7 @@ function websites_enableButtons() {
|
|||
}
|
||||
|
||||
function email_enableButtons() {
|
||||
let idList = [
|
||||
"email_viewButton",
|
||||
"email_exportButton",
|
||||
"email_deleteButton",
|
||||
];
|
||||
let idList = ["email_viewButton", "email_exportButton", "email_deleteButton"];
|
||||
enableButtonsForCertTree(emailTreeView, idList);
|
||||
}
|
||||
|
||||
|
|
@ -293,19 +297,25 @@ async function backupCerts() {
|
|||
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let [backupFileDialog, filePkcs12Spec] = await document.l10n.formatValues([
|
||||
{id: "choose-p12-backup-file-dialog"},
|
||||
{id: "file-browse-pkcs12-spec"},
|
||||
{ id: "choose-p12-backup-file-dialog" },
|
||||
{ id: "file-browse-pkcs12-spec" },
|
||||
]);
|
||||
fp.init(window, backupFileDialog, Ci.nsIFilePicker.modeSave);
|
||||
fp.appendFilter(filePkcs12Spec, "*.p12");
|
||||
fp.appendFilters(Ci.nsIFilePicker.filterAll);
|
||||
fp.defaultExtension = "p12";
|
||||
fp.open(rv => {
|
||||
if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
|
||||
if (
|
||||
rv == Ci.nsIFilePicker.returnOK ||
|
||||
rv == Ci.nsIFilePicker.returnReplace
|
||||
) {
|
||||
let password = {};
|
||||
if (certdialogs.setPKCS12FilePassword(window, password)) {
|
||||
let errorCode = certdb.exportPKCS12File(fp.file, selected_certs,
|
||||
password.value);
|
||||
let errorCode = certdb.exportPKCS12File(
|
||||
fp.file,
|
||||
selected_certs,
|
||||
password.value
|
||||
);
|
||||
promptError(errorCode);
|
||||
}
|
||||
}
|
||||
|
|
@ -322,17 +332,25 @@ function editCerts() {
|
|||
getSelectedCerts();
|
||||
|
||||
for (let cert of selected_certs) {
|
||||
window.openDialog("chrome://pippki/content/editcacert.xul", "",
|
||||
"chrome,centerscreen,modal", cert);
|
||||
window.openDialog(
|
||||
"chrome://pippki/content/editcacert.xul",
|
||||
"",
|
||||
"chrome,centerscreen,modal",
|
||||
cert
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreCerts() {
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let [restoreFileDialog, filePkcs12Spec, fileCertSpec] = await document.l10n.formatValues([
|
||||
{id: "choose-p12-restore-file-dialog"},
|
||||
{id: "file-browse-pkcs12-spec"},
|
||||
{id: "file-browse-certificate-spec"},
|
||||
let [
|
||||
restoreFileDialog,
|
||||
filePkcs12Spec,
|
||||
fileCertSpec,
|
||||
] = await document.l10n.formatValues([
|
||||
{ id: "choose-p12-restore-file-dialog" },
|
||||
{ id: "file-browse-pkcs12-spec" },
|
||||
{ id: "file-browse-certificate-spec" },
|
||||
]);
|
||||
fp.init(window, restoreFileDialog, Ci.nsIFilePicker.modeOpen);
|
||||
fp.appendFilter(filePkcs12Spec, "*.p12; *.pfx");
|
||||
|
|
@ -355,10 +373,14 @@ async function restoreCerts() {
|
|||
}
|
||||
|
||||
if (isX509FileType) {
|
||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
let fstream = Cc[
|
||||
"@mozilla.org/network/file-input-stream;1"
|
||||
].createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(fp.file, -1, 0, 0);
|
||||
let dataString = NetUtil.readInputStreamToString(fstream, fstream.available());
|
||||
let dataString = NetUtil.readInputStreamToString(
|
||||
fstream,
|
||||
fstream.available()
|
||||
);
|
||||
let dataArray = [];
|
||||
for (let i = 0; i < dataString.length; i++) {
|
||||
dataArray.push(dataString.charCodeAt(i));
|
||||
|
|
@ -370,16 +392,24 @@ async function restoreCerts() {
|
|||
return prompter;
|
||||
},
|
||||
};
|
||||
certdb.importUserCertificate(dataArray, dataArray.length, interfaceRequestor);
|
||||
certdb.importUserCertificate(
|
||||
dataArray,
|
||||
dataArray.length,
|
||||
interfaceRequestor
|
||||
);
|
||||
} else {
|
||||
// Otherwise, assume it's a PKCS12 file and import it that way.
|
||||
let password = {};
|
||||
let errorCode = Ci.nsIX509CertDB.ERROR_BAD_PASSWORD;
|
||||
while (errorCode == Ci.nsIX509CertDB.ERROR_BAD_PASSWORD &&
|
||||
certdialogs.getPKCS12FilePassword(window, password)) {
|
||||
while (
|
||||
errorCode == Ci.nsIX509CertDB.ERROR_BAD_PASSWORD &&
|
||||
certdialogs.getPKCS12FilePassword(window, password)
|
||||
) {
|
||||
errorCode = certdb.importPKCS12File(fp.file, password.value);
|
||||
if (errorCode == Ci.nsIX509CertDB.ERROR_BAD_PASSWORD &&
|
||||
password.value.length == 0) {
|
||||
if (
|
||||
errorCode == Ci.nsIX509CertDB.ERROR_BAD_PASSWORD &&
|
||||
password.value.length == 0
|
||||
) {
|
||||
// It didn't like empty string password, try no password.
|
||||
errorCode = certdb.importPKCS12File(fp.file, null);
|
||||
}
|
||||
|
|
@ -415,10 +445,10 @@ function deleteCerts() {
|
|||
}
|
||||
|
||||
const treeViewMap = {
|
||||
"mine_tab": userTreeView,
|
||||
"websites_tab": serverTreeView,
|
||||
"ca_tab": caTreeView,
|
||||
"others_tab": emailTreeView,
|
||||
mine_tab: userTreeView,
|
||||
websites_tab: serverTreeView,
|
||||
ca_tab: caTreeView,
|
||||
others_tab: emailTreeView,
|
||||
};
|
||||
let selTab = document.getElementById("certMgrTabbox").selectedItem;
|
||||
let selTabID = selTab.getAttribute("id");
|
||||
|
|
@ -430,9 +460,14 @@ function deleteCerts() {
|
|||
let retVals = {
|
||||
deleteConfirmed: false,
|
||||
};
|
||||
window.openDialog("chrome://pippki/content/deletecert.xul", "",
|
||||
"chrome,centerscreen,modal", selTabID, selected_tree_items,
|
||||
retVals);
|
||||
window.openDialog(
|
||||
"chrome://pippki/content/deletecert.xul",
|
||||
"",
|
||||
"chrome,centerscreen,modal",
|
||||
selTabID,
|
||||
selected_tree_items,
|
||||
retVals
|
||||
);
|
||||
|
||||
if (retVals.deleteConfirmed) {
|
||||
let treeView = treeViewMap[selTabID];
|
||||
|
|
@ -461,8 +496,8 @@ function viewCerts() {
|
|||
async function addCACerts() {
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let [importCa, fileCertSpec] = await document.l10n.formatValues([
|
||||
{id: "import-ca-certs-prompt"},
|
||||
{id: "file-browse-certificate-spec"},
|
||||
{ id: "import-ca-certs-prompt" },
|
||||
{ id: "file-browse-certificate-spec" },
|
||||
]);
|
||||
fp.init(window, importCa, Ci.nsIFilePicker.modeOpen);
|
||||
fp.appendFilter(fileCertSpec, gCertFileTypes);
|
||||
|
|
@ -479,8 +514,8 @@ async function addCACerts() {
|
|||
async function addEmailCert() {
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let [importEmail, fileCertSpec] = await document.l10n.formatValues([
|
||||
{id: "import-email-cert-prompt"},
|
||||
{id: "file-browse-certificate-spec"},
|
||||
{ id: "import-email-cert-prompt" },
|
||||
{ id: "file-browse-certificate-spec" },
|
||||
]);
|
||||
fp.init(window, importEmail, Ci.nsIFilePicker.modeOpen);
|
||||
fp.appendFilter(fileCertSpec, gCertFileTypes);
|
||||
|
|
@ -498,8 +533,11 @@ async function addEmailCert() {
|
|||
}
|
||||
|
||||
function addException() {
|
||||
window.openDialog("chrome://pippki/content/exceptionDialog.xul", "",
|
||||
"chrome,centerscreen,modal");
|
||||
window.openDialog(
|
||||
"chrome://pippki/content/exceptionDialog.xul",
|
||||
"",
|
||||
"chrome,centerscreen,modal"
|
||||
);
|
||||
var certcache = certdb.getCerts();
|
||||
serverTreeView.loadCertsFromCache(certcache, Ci.nsIX509Cert.SERVER_CERT);
|
||||
serverTreeView.selection.clearSelection();
|
||||
|
|
|
|||
|
|
@ -57,7 +57,11 @@ function AddUsage(l10nId) {
|
|||
|
||||
function setWindowName() {
|
||||
let cert = window.arguments[0].QueryInterface(Ci.nsIX509Cert);
|
||||
window.document.l10n.setAttributes(window.document.documentElement, "cert-viewer-title", {certName: cert.displayName});
|
||||
window.document.l10n.setAttributes(
|
||||
window.document.documentElement,
|
||||
"cert-viewer-title",
|
||||
{ certName: cert.displayName }
|
||||
);
|
||||
|
||||
//
|
||||
// Set the cert attributes for viewing
|
||||
|
|
@ -83,14 +87,13 @@ const certificateUsageToStringBundleName = {
|
|||
};
|
||||
|
||||
const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
|
||||
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
|
||||
const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12;
|
||||
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
|
||||
const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
|
||||
const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21;
|
||||
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
|
||||
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
||||
|
||||
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
|
||||
const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12;
|
||||
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
|
||||
const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
|
||||
const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21;
|
||||
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
|
||||
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
||||
|
||||
/**
|
||||
* Updates the usage display area given the results from asyncDetermineUsages.
|
||||
|
|
@ -106,8 +109,8 @@ const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
|||
function displayUsages(results) {
|
||||
document.getElementById("verify_pending").setAttribute("hidden", "true");
|
||||
let verified = document.getElementById("verified");
|
||||
let someSuccess = results.some(result =>
|
||||
result.errorCode == PRErrorCodeSuccess
|
||||
let someSuccess = results.some(
|
||||
result => result.errorCode == PRErrorCodeSuccess
|
||||
);
|
||||
if (someSuccess) {
|
||||
document.l10n.setAttributes(verified, "cert-verified");
|
||||
|
|
@ -121,25 +124,39 @@ function displayUsages(results) {
|
|||
AddCertChain("treesetDump", getBestChain(results));
|
||||
} else {
|
||||
const errorRankings = [
|
||||
{ error: SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
bundleString: "cert-not-verified-cert-revoked" },
|
||||
{ error: SEC_ERROR_UNTRUSTED_CERT,
|
||||
bundleString: "cert-not-verified-cert-not-trusted" },
|
||||
{ error: SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
bundleString: "cert-not-verified-issuer-not-trusted" },
|
||||
{ error: SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
bundleString: "cert-not-verified_algorithm-disabled" },
|
||||
{ error: SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
bundleString: "cert-not-verified-cert-expired" },
|
||||
{ error: SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE,
|
||||
bundleString: "cert-not-verified-ca-invalid" },
|
||||
{ error: SEC_ERROR_UNKNOWN_ISSUER,
|
||||
bundleString: "cert-not-verified-issuer-unknown" },
|
||||
{
|
||||
error: SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
bundleString: "cert-not-verified-cert-revoked",
|
||||
},
|
||||
{
|
||||
error: SEC_ERROR_UNTRUSTED_CERT,
|
||||
bundleString: "cert-not-verified-cert-not-trusted",
|
||||
},
|
||||
{
|
||||
error: SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
bundleString: "cert-not-verified-issuer-not-trusted",
|
||||
},
|
||||
{
|
||||
error: SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
bundleString: "cert-not-verified_algorithm-disabled",
|
||||
},
|
||||
{
|
||||
error: SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
bundleString: "cert-not-verified-cert-expired",
|
||||
},
|
||||
{
|
||||
error: SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE,
|
||||
bundleString: "cert-not-verified-ca-invalid",
|
||||
},
|
||||
{
|
||||
error: SEC_ERROR_UNKNOWN_ISSUER,
|
||||
bundleString: "cert-not-verified-issuer-unknown",
|
||||
},
|
||||
];
|
||||
let errorPresentFlag = false;
|
||||
for (let errorRanking of errorRankings) {
|
||||
let errorPresent = results.some(result =>
|
||||
result.errorCode == errorRanking.error
|
||||
let errorPresent = results.some(
|
||||
result => result.errorCode == errorRanking.error
|
||||
);
|
||||
if (errorPresent) {
|
||||
document.l10n.setAttributes(verified, errorRanking.bundleString);
|
||||
|
|
@ -159,8 +176,12 @@ function displayUsages(results) {
|
|||
|
||||
function addChildrenToTree(parentTree, label, value, addTwistie) {
|
||||
let treeChild1 = document.createXULElement("treechildren");
|
||||
let treeElement = addTreeItemToTreeChild(treeChild1, label, value,
|
||||
addTwistie);
|
||||
let treeElement = addTreeItemToTreeChild(
|
||||
treeChild1,
|
||||
label,
|
||||
value,
|
||||
addTwistie
|
||||
);
|
||||
parentTree.appendChild(treeChild1);
|
||||
return treeElement;
|
||||
}
|
||||
|
|
@ -184,8 +205,9 @@ function addTreeItemToTreeChild(treeChild, label, value, addTwistie) {
|
|||
}
|
||||
|
||||
function displaySelected() {
|
||||
var asn1Tree = document.getElementById("prettyDumpTree")
|
||||
.view.QueryInterface(Ci.nsIASN1Tree);
|
||||
var asn1Tree = document
|
||||
.getElementById("prettyDumpTree")
|
||||
.view.QueryInterface(Ci.nsIASN1Tree);
|
||||
var items = asn1Tree.selection;
|
||||
var certDumpVal = document.getElementById("certDumpVal");
|
||||
if (items.currentIndex != -1) {
|
||||
|
|
@ -197,8 +219,9 @@ function displaySelected() {
|
|||
}
|
||||
|
||||
function BuildPrettyPrint(cert) {
|
||||
var certDumpTree = Cc["@mozilla.org/security/nsASN1Tree;1"].
|
||||
createInstance(Ci.nsIASN1Tree);
|
||||
var certDumpTree = Cc["@mozilla.org/security/nsASN1Tree;1"].createInstance(
|
||||
Ci.nsIASN1Tree
|
||||
);
|
||||
certDumpTree.loadASN1Structure(cert.ASN1Structure);
|
||||
document.getElementById("prettyDumpTree").view = certDumpTree;
|
||||
}
|
||||
|
|
@ -234,15 +257,18 @@ function DisplayGeneralDataFromCert(cert) {
|
|||
}
|
||||
|
||||
function updateCertDump() {
|
||||
var asn1Tree = document.getElementById("prettyDumpTree")
|
||||
.view.QueryInterface(Ci.nsIASN1Tree);
|
||||
var asn1Tree = document
|
||||
.getElementById("prettyDumpTree")
|
||||
.view.QueryInterface(Ci.nsIASN1Tree);
|
||||
|
||||
var tree = document.getElementById("treesetDump");
|
||||
if (tree.currentIndex >= 0) {
|
||||
var item = tree.view.getItemAtIndex(tree.currentIndex);
|
||||
var dbKey = item.firstChild.firstChild.getAttribute("display");
|
||||
// Get the cert from the cert database
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
var cert = certdb.findCertByDBKey(dbKey);
|
||||
asn1Tree.loadASN1Structure(cert.ASN1Structure);
|
||||
}
|
||||
|
|
@ -252,8 +278,10 @@ function updateCertDump() {
|
|||
function getCurrentCert() {
|
||||
var realIndex;
|
||||
var tree = document.getElementById("treesetDump");
|
||||
if (tree.view.selection.isSelected(tree.currentIndex)
|
||||
&& document.getElementById("prettyprint_tab").selected) {
|
||||
if (
|
||||
tree.view.selection.isSelected(tree.currentIndex) &&
|
||||
document.getElementById("prettyprint_tab").selected
|
||||
) {
|
||||
/* if the user manually selected a cert on the Details tab,
|
||||
then take that one */
|
||||
realIndex = tree.currentIndex;
|
||||
|
|
@ -266,7 +294,9 @@ function getCurrentCert() {
|
|||
if (realIndex >= 0) {
|
||||
var item = tree.view.getItemAtIndex(realIndex);
|
||||
var dbKey = item.firstChild.firstChild.getAttribute("display");
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
var cert = certdb.findCertByDBKey(dbKey);
|
||||
return cert;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,9 @@ function setPassword(event) {
|
|||
// checkPasswords() should have prevented this path from being reached.
|
||||
} else {
|
||||
if (pw1.value == "") {
|
||||
var secmoddb = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB);
|
||||
var secmoddb = Cc[
|
||||
"@mozilla.org/security/pkcs11moduledb;1"
|
||||
].getService(Ci.nsIPKCS11ModuleDB);
|
||||
if (secmoddb.isFIPSEnabled) {
|
||||
// empty passwords are not allowed in FIPS mode
|
||||
doPrompt(bundle.getString("pw_change2empty_in_fips_mode"));
|
||||
|
|
@ -93,9 +95,11 @@ function setPassword(event) {
|
|||
if (passok) {
|
||||
token.changePassword(oldpw, pw1.value);
|
||||
if (pw1.value == "") {
|
||||
doPrompt(bundle.getString("pw_erased_ok")
|
||||
+ " "
|
||||
+ bundle.getString("pw_empty_warning"));
|
||||
doPrompt(
|
||||
bundle.getString("pw_erased_ok") +
|
||||
" " +
|
||||
bundle.getString("pw_empty_warning")
|
||||
);
|
||||
} else {
|
||||
doPrompt(bundle.getString("pw_change_ok"));
|
||||
}
|
||||
|
|
@ -113,8 +117,11 @@ function setPassword(event) {
|
|||
} else {
|
||||
token.initPassword(pw1.value);
|
||||
if (pw1.value == "") {
|
||||
doPrompt(bundle.getString("pw_not_wanted") + " " +
|
||||
bundle.getString("pw_empty_warning"));
|
||||
doPrompt(
|
||||
bundle.getString("pw_not_wanted") +
|
||||
" " +
|
||||
bundle.getString("pw_empty_warning")
|
||||
);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
|
|
@ -162,8 +169,8 @@ function setPasswordStrength() {
|
|||
upper = 3;
|
||||
}
|
||||
|
||||
let pwstrength = (pwlength * 10) - 20 + (numeric * 10) + (numsymbols * 15) +
|
||||
(upper * 10);
|
||||
let pwstrength =
|
||||
pwlength * 10 - 20 + numeric * 10 + numsymbols * 15 + upper * 10;
|
||||
|
||||
// Clamp strength to [0, 100].
|
||||
if (pwstrength < 0) {
|
||||
|
|
@ -195,5 +202,5 @@ function checkPasswords() {
|
|||
}
|
||||
}
|
||||
|
||||
document.documentElement.getButton("accept").disabled = (pw1 != pw2);
|
||||
document.documentElement.getButton("accept").disabled = pw1 != pw2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,9 @@ var rememberBox;
|
|||
|
||||
function onLoad() {
|
||||
bundle = document.getElementById("pippki_bundle");
|
||||
let rememberSetting =
|
||||
Services.prefs.getBoolPref("security.remember_cert_checkbox_default_setting");
|
||||
let rememberSetting = Services.prefs.getBoolPref(
|
||||
"security.remember_cert_checkbox_default_setting"
|
||||
);
|
||||
|
||||
rememberBox = document.getElementById("rememberBox");
|
||||
rememberBox.label = bundle.getString("clientAuthRemember");
|
||||
|
|
@ -69,11 +70,13 @@ function onLoad() {
|
|||
let issuerOrg = window.arguments[2];
|
||||
let port = window.arguments[3];
|
||||
let formattedOrg = bundle.getFormattedString("clientAuthMessage1", [org]);
|
||||
let formattedIssuerOrg = bundle.getFormattedString("clientAuthMessage2",
|
||||
[issuerOrg]);
|
||||
let formattedHostnameAndPort =
|
||||
bundle.getFormattedString("clientAuthHostnameAndPort",
|
||||
[hostname, port.toString()]);
|
||||
let formattedIssuerOrg = bundle.getFormattedString("clientAuthMessage2", [
|
||||
issuerOrg,
|
||||
]);
|
||||
let formattedHostnameAndPort = bundle.getFormattedString(
|
||||
"clientAuthHostnameAndPort",
|
||||
[hostname, port.toString()]
|
||||
);
|
||||
setText("hostname", formattedHostnameAndPort);
|
||||
setText("organization", formattedOrg);
|
||||
setText("issuer", formattedIssuerOrg);
|
||||
|
|
@ -83,9 +86,10 @@ function onLoad() {
|
|||
for (let i = 0; i < certArray.length; i++) {
|
||||
let menuItemNode = document.createXULElement("menuitem");
|
||||
let cert = certArray.queryElementAt(i, Ci.nsIX509Cert);
|
||||
let nickAndSerial =
|
||||
bundle.getFormattedString("clientAuthNickAndSerial",
|
||||
[cert.displayName, cert.serialNumber]);
|
||||
let nickAndSerial = bundle.getFormattedString("clientAuthNickAndSerial", [
|
||||
cert.displayName,
|
||||
cert.serialNumber,
|
||||
]);
|
||||
menuItemNode.setAttribute("value", i);
|
||||
menuItemNode.setAttribute("label", nickAndSerial); // This is displayed.
|
||||
selectElement.menupopup.appendChild(menuItemNode);
|
||||
|
|
@ -98,8 +102,10 @@ function onLoad() {
|
|||
document.addEventListener("dialogaccept", doOK);
|
||||
document.addEventListener("dialogcancel", doCancel);
|
||||
|
||||
Services.obs.notifyObservers(document.getElementById("certAuthAsk"),
|
||||
"cert-dialog-loaded");
|
||||
Services.obs.notifyObservers(
|
||||
document.getElementById("certAuthAsk"),
|
||||
"cert-dialog-loaded"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -112,25 +118,30 @@ function setDetails() {
|
|||
let detailLines = [
|
||||
bundle.getFormattedString("clientAuthIssuedTo", [cert.subjectName]),
|
||||
bundle.getFormattedString("clientAuthSerial", [cert.serialNumber]),
|
||||
bundle.getFormattedString("clientAuthValidityPeriod",
|
||||
[cert.validity.notBeforeLocalTime,
|
||||
cert.validity.notAfterLocalTime]),
|
||||
bundle.getFormattedString("clientAuthValidityPeriod", [
|
||||
cert.validity.notBeforeLocalTime,
|
||||
cert.validity.notAfterLocalTime,
|
||||
]),
|
||||
];
|
||||
let keyUsages = cert.keyUsages;
|
||||
if (keyUsages) {
|
||||
detailLines.push(bundle.getFormattedString("clientAuthKeyUsages",
|
||||
[keyUsages]));
|
||||
detailLines.push(
|
||||
bundle.getFormattedString("clientAuthKeyUsages", [keyUsages])
|
||||
);
|
||||
}
|
||||
let emailAddresses = cert.getEmailAddresses();
|
||||
if (emailAddresses.length > 0) {
|
||||
let joinedAddresses = emailAddresses.join(", ");
|
||||
detailLines.push(bundle.getFormattedString("clientAuthEmailAddresses",
|
||||
[joinedAddresses]));
|
||||
detailLines.push(
|
||||
bundle.getFormattedString("clientAuthEmailAddresses", [joinedAddresses])
|
||||
);
|
||||
}
|
||||
detailLines.push(bundle.getFormattedString("clientAuthIssuedBy",
|
||||
[cert.issuerName]));
|
||||
detailLines.push(bundle.getFormattedString("clientAuthStoredOn",
|
||||
[cert.tokenName]));
|
||||
detailLines.push(
|
||||
bundle.getFormattedString("clientAuthIssuedBy", [cert.issuerName])
|
||||
);
|
||||
detailLines.push(
|
||||
bundle.getFormattedString("clientAuthStoredOn", [cert.tokenName])
|
||||
);
|
||||
|
||||
document.getElementById("details").value = detailLines.join("\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ function getLabelForCertTreeItem(certTreeItem) {
|
|||
}
|
||||
}
|
||||
|
||||
document.l10n.setAttributes(element, "cert-with-serial", { serialNumber: cert.serialNumber});
|
||||
document.l10n.setAttributes(element, "cert-with-serial", {
|
||||
serialNumber: cert.serialNumber,
|
||||
});
|
||||
return element;
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +82,10 @@ function onLoad() {
|
|||
return;
|
||||
}
|
||||
|
||||
document.l10n.setAttributes(document.documentElement, prefixForType + "title");
|
||||
document.l10n.setAttributes(
|
||||
document.documentElement,
|
||||
prefixForType + "title"
|
||||
);
|
||||
document.l10n.setAttributes(confirm, prefixForType + "confirm");
|
||||
document.l10n.setAttributes(impact, prefixForType + "impact");
|
||||
|
||||
|
|
|
|||
|
|
@ -4,24 +4,28 @@
|
|||
"use strict";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
var secmoddb;
|
||||
var skip_enable_buttons = false;
|
||||
|
||||
/* Do the initial load of all PKCS# modules and list them. */
|
||||
function LoadModules() {
|
||||
secmoddb = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB);
|
||||
secmoddb = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
|
||||
Ci.nsIPKCS11ModuleDB
|
||||
);
|
||||
RefreshDeviceList();
|
||||
}
|
||||
|
||||
async function doPrompt(l10n_id) {
|
||||
let [msg] = await document.l10n.formatValues([{id: l10n_id}]);
|
||||
let [msg] = await document.l10n.formatValues([{ id: l10n_id }]);
|
||||
Services.prompt.alert(window, null, msg);
|
||||
}
|
||||
|
||||
async function doConfirm(l10n_id) {
|
||||
let [msg] = await document.l10n.formatValues([{id: l10n_id}]);
|
||||
let [msg] = await document.l10n.formatValues([{ id: l10n_id }]);
|
||||
return Services.prompt.confirm(window, null, msg);
|
||||
}
|
||||
|
||||
|
|
@ -56,8 +60,8 @@ function SetFIPSButton() {
|
|||
*/
|
||||
function AddModule(module, slots) {
|
||||
var tree = document.getElementById("device_list");
|
||||
var item = document.createXULElement("treeitem");
|
||||
var row = document.createXULElement("treerow");
|
||||
var item = document.createXULElement("treeitem");
|
||||
var row = document.createXULElement("treerow");
|
||||
var cell = document.createXULElement("treecell");
|
||||
cell.setAttribute("label", module.name);
|
||||
row.appendChild(cell);
|
||||
|
|
@ -99,7 +103,8 @@ function getSelectedItem() {
|
|||
let kind = item.getAttribute("pk11kind");
|
||||
if (kind == "slot") {
|
||||
selected_slot = item.slotObject;
|
||||
} else { // (kind == "module")
|
||||
} else {
|
||||
// (kind == "module")
|
||||
selected_module = item.module;
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +128,7 @@ function enableButtons() {
|
|||
// so grab the token type
|
||||
var selected_token = selected_slot.getToken();
|
||||
if (selected_token != null) {
|
||||
if (selected_token.needsLogin() || !(selected_token.needsUserInit)) {
|
||||
if (selected_token.needsLogin() || !selected_token.needsUserInit) {
|
||||
pw_toggle = "false";
|
||||
if (selected_token.needsLogin()) {
|
||||
if (selected_token.isLoggedIn()) {
|
||||
|
|
@ -134,22 +139,28 @@ function enableButtons() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!Services.policies.isAllowed("createMasterPassword") &&
|
||||
selected_token.isInternalKeyToken &&
|
||||
!selected_token.hasPassword) {
|
||||
if (
|
||||
!Services.policies.isAllowed("createMasterPassword") &&
|
||||
selected_token.isInternalKeyToken &&
|
||||
!selected_token.hasPassword
|
||||
) {
|
||||
pw_toggle = "true";
|
||||
}
|
||||
}
|
||||
showSlotInfo();
|
||||
}
|
||||
document.getElementById("login_button")
|
||||
.setAttribute("disabled", login_toggle);
|
||||
document.getElementById("logout_button")
|
||||
.setAttribute("disabled", logout_toggle);
|
||||
document.getElementById("change_pw_button")
|
||||
.setAttribute("disabled", pw_toggle);
|
||||
document.getElementById("unload_button")
|
||||
.setAttribute("disabled", unload_toggle);
|
||||
document
|
||||
.getElementById("login_button")
|
||||
.setAttribute("disabled", login_toggle);
|
||||
document
|
||||
.getElementById("logout_button")
|
||||
.setAttribute("disabled", logout_toggle);
|
||||
document
|
||||
.getElementById("change_pw_button")
|
||||
.setAttribute("disabled", pw_toggle);
|
||||
document
|
||||
.getElementById("unload_button")
|
||||
.setAttribute("disabled", unload_toggle);
|
||||
}
|
||||
|
||||
// clear the display of information for the slot
|
||||
|
|
@ -176,55 +187,90 @@ function ClearDeviceList() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// show a list of info about a slot
|
||||
function showSlotInfo() {
|
||||
var present = true;
|
||||
ClearInfoList();
|
||||
switch (selected_slot.status) {
|
||||
case Ci.nsIPKCS11Slot.SLOT_DISABLED:
|
||||
AddInfoRow("devinfo-status", {l10nID: "devinfo-status-disabled"}, "tok_status");
|
||||
present = false;
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_NOT_PRESENT:
|
||||
AddInfoRow("devinfo-status", {l10nID: "devinfo-status-not-present"}, "tok_status");
|
||||
present = false;
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED:
|
||||
AddInfoRow("devinfo-status", {l10nID: "devinfo-status-uninitialized"}, "tok_status");
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN:
|
||||
AddInfoRow("devinfo-status", {l10nID: "devinfo-status-not-logged-in"}, "tok_status");
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_LOGGED_IN:
|
||||
AddInfoRow("devinfo-status", {l10nID: "devinfo-status-logged-in"}, "tok_status");
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_READY:
|
||||
AddInfoRow("devinfo-status", {l10nID: "devinfo-status-ready"}, "tok_status");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
case Ci.nsIPKCS11Slot.SLOT_DISABLED:
|
||||
AddInfoRow(
|
||||
"devinfo-status",
|
||||
{ l10nID: "devinfo-status-disabled" },
|
||||
"tok_status"
|
||||
);
|
||||
present = false;
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_NOT_PRESENT:
|
||||
AddInfoRow(
|
||||
"devinfo-status",
|
||||
{ l10nID: "devinfo-status-not-present" },
|
||||
"tok_status"
|
||||
);
|
||||
present = false;
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED:
|
||||
AddInfoRow(
|
||||
"devinfo-status",
|
||||
{ l10nID: "devinfo-status-uninitialized" },
|
||||
"tok_status"
|
||||
);
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN:
|
||||
AddInfoRow(
|
||||
"devinfo-status",
|
||||
{ l10nID: "devinfo-status-not-logged-in" },
|
||||
"tok_status"
|
||||
);
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_LOGGED_IN:
|
||||
AddInfoRow(
|
||||
"devinfo-status",
|
||||
{ l10nID: "devinfo-status-logged-in" },
|
||||
"tok_status"
|
||||
);
|
||||
break;
|
||||
case Ci.nsIPKCS11Slot.SLOT_READY:
|
||||
AddInfoRow(
|
||||
"devinfo-status",
|
||||
{ l10nID: "devinfo-status-ready" },
|
||||
"tok_status"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
AddInfoRow("devinfo-desc", {label: selected_slot.desc}, "slot_desc");
|
||||
AddInfoRow("devinfo-man-id", {label: selected_slot.manID}, "slot_manID");
|
||||
AddInfoRow("devinfo-hwversion", {label: selected_slot.HWVersion}, "slot_hwv");
|
||||
AddInfoRow("devinfo-fwversion", {label: selected_slot.FWVersion}, "slot_fwv");
|
||||
AddInfoRow("devinfo-desc", { label: selected_slot.desc }, "slot_desc");
|
||||
AddInfoRow("devinfo-man-id", { label: selected_slot.manID }, "slot_manID");
|
||||
AddInfoRow(
|
||||
"devinfo-hwversion",
|
||||
{ label: selected_slot.HWVersion },
|
||||
"slot_hwv"
|
||||
);
|
||||
AddInfoRow(
|
||||
"devinfo-fwversion",
|
||||
{ label: selected_slot.FWVersion },
|
||||
"slot_fwv"
|
||||
);
|
||||
if (present) {
|
||||
showTokenInfo();
|
||||
showTokenInfo();
|
||||
}
|
||||
}
|
||||
|
||||
function showModuleInfo() {
|
||||
ClearInfoList();
|
||||
AddInfoRow("devinfo-modname", {label: selected_module.name}, "module_name");
|
||||
AddInfoRow("devinfo-modpath", {label: selected_module.libName}, "module_path");
|
||||
AddInfoRow("devinfo-modname", { label: selected_module.name }, "module_name");
|
||||
AddInfoRow(
|
||||
"devinfo-modpath",
|
||||
{ label: selected_module.libName },
|
||||
"module_path"
|
||||
);
|
||||
}
|
||||
|
||||
// add a row to the info list, as [col1 col2] (ex.: ["status" "logged in"])
|
||||
function AddInfoRow(l10nID, col2, cell_id) {
|
||||
var tree = document.getElementById("info_list");
|
||||
var item = document.createXULElement("treeitem");
|
||||
var row = document.createXULElement("treerow");
|
||||
var item = document.createXULElement("treeitem");
|
||||
var row = document.createXULElement("treerow");
|
||||
var cell1 = document.createXULElement("treecell");
|
||||
document.l10n.setAttributes(cell1, l10nID);
|
||||
cell1.setAttribute("crop", "never");
|
||||
|
|
@ -274,8 +320,7 @@ function doLogout() {
|
|||
} else {
|
||||
document.l10n.setAttributes(tok_status, "devinfo-status-not-logged-in");
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
enableButtons();
|
||||
}
|
||||
|
||||
|
|
@ -288,8 +333,7 @@ function doLoad() {
|
|||
|
||||
async function deleteSelected() {
|
||||
getSelectedItem();
|
||||
if (selected_module &&
|
||||
(await doConfirm("del-module-warning"))) {
|
||||
if (selected_module && (await doConfirm("del-module-warning"))) {
|
||||
try {
|
||||
secmoddb.deleteModule(selected_module.name);
|
||||
} catch (e) {
|
||||
|
|
@ -311,13 +355,18 @@ async function doUnload() {
|
|||
|
||||
function changePassword() {
|
||||
getSelectedItem();
|
||||
let params = Cc["@mozilla.org/embedcomp/dialogparam;1"]
|
||||
.createInstance(Ci.nsIDialogParamBlock);
|
||||
let params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(
|
||||
Ci.nsIDialogParamBlock
|
||||
);
|
||||
let objects = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
objects.appendElement(selected_slot.getToken());
|
||||
params.objects = objects;
|
||||
window.openDialog("changepassword.xul", "", "chrome,centerscreen,modal",
|
||||
params);
|
||||
window.openDialog(
|
||||
"changepassword.xul",
|
||||
"",
|
||||
"chrome,centerscreen,modal",
|
||||
params
|
||||
);
|
||||
showSlotInfo();
|
||||
enableButtons();
|
||||
}
|
||||
|
|
@ -326,11 +375,27 @@ function changePassword() {
|
|||
|
||||
function showTokenInfo() {
|
||||
var selected_token = selected_slot.getToken();
|
||||
AddInfoRow("devinfo-label", {label: selected_token.tokenName}, "tok_label");
|
||||
AddInfoRow("devinfo-man-id", {label: selected_token.tokenManID}, "tok_manID");
|
||||
AddInfoRow("devinfo-serialnum", {label: selected_token.tokenSerialNumber}, "tok_sNum");
|
||||
AddInfoRow("devinfo-hwversion", {label: selected_token.tokenHWVersion}, "tok_hwv");
|
||||
AddInfoRow("devinfo-fwversion", {label: selected_token.tokenFWVersion}, "tok_fwv");
|
||||
AddInfoRow("devinfo-label", { label: selected_token.tokenName }, "tok_label");
|
||||
AddInfoRow(
|
||||
"devinfo-man-id",
|
||||
{ label: selected_token.tokenManID },
|
||||
"tok_manID"
|
||||
);
|
||||
AddInfoRow(
|
||||
"devinfo-serialnum",
|
||||
{ label: selected_token.tokenSerialNumber },
|
||||
"tok_sNum"
|
||||
);
|
||||
AddInfoRow(
|
||||
"devinfo-hwversion",
|
||||
{ label: selected_token.tokenHWVersion },
|
||||
"tok_hwv"
|
||||
);
|
||||
AddInfoRow(
|
||||
"devinfo-fwversion",
|
||||
{ label: selected_token.tokenFWVersion },
|
||||
"tok_fwv"
|
||||
);
|
||||
}
|
||||
|
||||
function toggleFIPS() {
|
||||
|
|
@ -339,7 +404,9 @@ function toggleFIPS() {
|
|||
// In FIPS mode the password must be non-empty.
|
||||
// This is different from what we allow in NON-Fips mode.
|
||||
|
||||
var tokendb = Cc["@mozilla.org/security/pk11tokendb;1"].getService(Ci.nsIPK11TokenDB);
|
||||
var tokendb = Cc["@mozilla.org/security/pk11tokendb;1"].getService(
|
||||
Ci.nsIPK11TokenDB
|
||||
);
|
||||
var internal_token = tokendb.getInternalKeyToken(); // nsIPK11Token
|
||||
if (!internal_token.hasPassword) {
|
||||
// Token has either no or an empty password.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
/* import-globals-from pippki.js */
|
||||
"use strict";
|
||||
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
/**
|
||||
* Cert to edit the trust of.
|
||||
* @type nsIX509Cert
|
||||
|
|
@ -21,15 +22,23 @@ function onLoad() {
|
|||
document.addEventListener("dialogaccept", onDialogAccept);
|
||||
|
||||
let certMsg = document.getElementById("certmsg");
|
||||
document.l10n.setAttributes(certMsg, "edit-trust-ca", { certName: gCert.commonName});
|
||||
document.l10n.setAttributes(certMsg, "edit-trust-ca", {
|
||||
certName: gCert.commonName,
|
||||
});
|
||||
|
||||
let sslCheckbox = document.getElementById("trustSSL");
|
||||
sslCheckbox.checked = gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL);
|
||||
sslCheckbox.checked = gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL
|
||||
);
|
||||
|
||||
let emailCheckbox = document.getElementById("trustEmail");
|
||||
emailCheckbox.checked = gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL);
|
||||
emailCheckbox.checked = gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ var gBroken;
|
|||
var gNeedReset;
|
||||
var gSecHistogram;
|
||||
|
||||
const {PrivateBrowsingUtils} = ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
const { PrivateBrowsingUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
||||
);
|
||||
|
||||
function initExceptionDialog() {
|
||||
gNeedReset = false;
|
||||
|
|
@ -21,10 +23,7 @@ function initExceptionDialog() {
|
|||
let warningText = document.getElementById("warningText");
|
||||
document.l10n.setAttributes(warningText, "add-exception-branded-warning");
|
||||
let confirmButton = gDialog.getButton("extra1");
|
||||
let l10nUpdatedElements = [
|
||||
confirmButton,
|
||||
warningText,
|
||||
];
|
||||
let l10nUpdatedElements = [confirmButton, warningText];
|
||||
confirmButton.disabled = true;
|
||||
|
||||
var args = window.arguments;
|
||||
|
|
@ -71,7 +70,9 @@ function initExceptionDialog() {
|
|||
l10nUpdatedElements.push(element);
|
||||
}
|
||||
|
||||
document.l10n.translateElements(l10nUpdatedElements).then(() => window.sizeToContent());
|
||||
document.l10n
|
||||
.translateElements(l10nUpdatedElements)
|
||||
.then(() => window.sizeToContent());
|
||||
|
||||
document.addEventListener("dialogextra1", addException);
|
||||
document.addEventListener("dialogextra2", checkCert);
|
||||
|
|
@ -89,13 +90,16 @@ function initExceptionDialog() {
|
|||
*/
|
||||
function grabCert(req, evt) {
|
||||
if (req.channel && req.channel.securityInfo) {
|
||||
gSecInfo = req.channel.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
gSecInfo = req.channel.securityInfo.QueryInterface(
|
||||
Ci.nsITransportSecurityInfo
|
||||
);
|
||||
gCert = gSecInfo ? gSecInfo.serverCert : null;
|
||||
}
|
||||
gBroken = evt.type == "error";
|
||||
gChecking = false;
|
||||
document.l10n.translateElements(updateCertStatus()).then(() => window.sizeToContent());
|
||||
document.l10n
|
||||
.translateElements(updateCertStatus())
|
||||
.then(() => window.sizeToContent());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -175,8 +179,7 @@ function resetDialog() {
|
|||
*/
|
||||
function handleTextChange() {
|
||||
var checkCertButton = document.getElementById("checkCertButton");
|
||||
checkCertButton.disabled =
|
||||
!(document.getElementById("locationTextBox").value);
|
||||
checkCertButton.disabled = !document.getElementById("locationTextBox").value;
|
||||
if (gNeedReset) {
|
||||
gNeedReset = false;
|
||||
resetDialog();
|
||||
|
|
@ -189,7 +192,8 @@ function updateCertStatus() {
|
|||
var shortDesc3, longDesc3;
|
||||
var use2 = false;
|
||||
var use3 = false;
|
||||
let bucketId = Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_BASE;
|
||||
let bucketId =
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_BASE;
|
||||
let l10nUpdatedElements = [];
|
||||
if (gCert) {
|
||||
if (gBroken) {
|
||||
|
|
@ -201,38 +205,43 @@ function updateCertStatus() {
|
|||
var utl = "add-exception-unverified-or-bad-signature-long";
|
||||
var use1 = false;
|
||||
if (gSecInfo.isDomainMismatch) {
|
||||
bucketId += Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_DOMAIN;
|
||||
bucketId +=
|
||||
Ci.nsISecurityUITelemetry
|
||||
.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_DOMAIN;
|
||||
use1 = true;
|
||||
shortDesc = mms;
|
||||
longDesc = mml;
|
||||
longDesc = mml;
|
||||
}
|
||||
if (gSecInfo.isNotValidAtThisTime) {
|
||||
bucketId += Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_TIME;
|
||||
bucketId +=
|
||||
Ci.nsISecurityUITelemetry
|
||||
.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_TIME;
|
||||
if (!use1) {
|
||||
use1 = true;
|
||||
shortDesc = exs;
|
||||
longDesc = exl;
|
||||
longDesc = exl;
|
||||
} else {
|
||||
use2 = true;
|
||||
shortDesc2 = exs;
|
||||
longDesc2 = exl;
|
||||
longDesc2 = exl;
|
||||
}
|
||||
}
|
||||
if (gSecInfo.isUntrusted) {
|
||||
bucketId +=
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_UNTRUSTED;
|
||||
Ci.nsISecurityUITelemetry
|
||||
.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_UNTRUSTED;
|
||||
if (!use1) {
|
||||
use1 = true;
|
||||
shortDesc = uts;
|
||||
longDesc = utl;
|
||||
longDesc = utl;
|
||||
} else if (!use2) {
|
||||
use2 = true;
|
||||
shortDesc2 = uts;
|
||||
longDesc2 = utl;
|
||||
longDesc2 = utl;
|
||||
} else {
|
||||
use3 = true;
|
||||
shortDesc3 = uts;
|
||||
longDesc3 = utl;
|
||||
longDesc3 = utl;
|
||||
}
|
||||
}
|
||||
gSecHistogram.add(bucketId);
|
||||
|
|
@ -249,11 +258,14 @@ function updateCertStatus() {
|
|||
pe.checked = !inPrivateBrowsing;
|
||||
|
||||
let headerDescription = document.getElementById("headerDescription");
|
||||
document.l10n.setAttributes(headerDescription, "add-exception-invalid-header");
|
||||
document.l10n.setAttributes(
|
||||
headerDescription,
|
||||
"add-exception-invalid-header"
|
||||
);
|
||||
l10nUpdatedElements.push(headerDescription);
|
||||
} else {
|
||||
shortDesc = "add-exception-valid-short";
|
||||
longDesc = "add-exception-valid-long";
|
||||
longDesc = "add-exception-valid-long";
|
||||
gDialog.getButton("extra1").disabled = true;
|
||||
document.getElementById("permanent").disabled = true;
|
||||
}
|
||||
|
|
@ -266,7 +278,7 @@ function updateCertStatus() {
|
|||
Services.obs.notifyObservers(null, "cert-exception-ui-ready");
|
||||
} else if (gChecking) {
|
||||
shortDesc = "add-exception-checking-short";
|
||||
longDesc = "add-exception-checking-long";
|
||||
longDesc = "add-exception-checking-long";
|
||||
// We're checking the certificate, so we disable the Get Certificate
|
||||
// button to make sure that the user can't interrupt the process and
|
||||
// trigger another certificate fetch.
|
||||
|
|
@ -276,7 +288,7 @@ function updateCertStatus() {
|
|||
document.getElementById("permanent").disabled = true;
|
||||
} else {
|
||||
shortDesc = "add-exception-no-cert-short";
|
||||
longDesc = "add-exception-no-cert-long";
|
||||
longDesc = "add-exception-no-cert-long";
|
||||
// We're done checking the certificate, so allow the user to check it again.
|
||||
document.getElementById("checkCertButton").disabled = false;
|
||||
document.getElementById("viewCertButton").disabled = true;
|
||||
|
|
@ -292,7 +304,9 @@ function updateCertStatus() {
|
|||
|
||||
if (use2) {
|
||||
let status2Description = document.getElementById("status2Description");
|
||||
let status2LongDescription = document.getElementById("status2LongDescription");
|
||||
let status2LongDescription = document.getElementById(
|
||||
"status2LongDescription"
|
||||
);
|
||||
document.l10n.setAttributes(status2Description, shortDesc2);
|
||||
document.l10n.setAttributes(status2LongDescription, longDesc2);
|
||||
l10nUpdatedElements.push(status2Description);
|
||||
|
|
@ -301,7 +315,9 @@ function updateCertStatus() {
|
|||
|
||||
if (use3) {
|
||||
let status3Description = document.getElementById("status3Description");
|
||||
let status3LongDescription = document.getElementById("status3LongDescription");
|
||||
let status3LongDescription = document.getElementById(
|
||||
"status3LongDescription"
|
||||
);
|
||||
document.l10n.setAttributes(status3Description, shortDesc3);
|
||||
document.l10n.setAttributes(status3LongDescription, longDesc3);
|
||||
l10nUpdatedElements.push(status3Description);
|
||||
|
|
@ -316,7 +332,9 @@ function updateCertStatus() {
|
|||
* Handle user request to display certificate details
|
||||
*/
|
||||
function viewCertButtonClick() {
|
||||
gSecHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_VIEW_CERT);
|
||||
gSecHistogram.add(
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_VIEW_CERT
|
||||
);
|
||||
if (gCert) {
|
||||
viewCertHelper(this, gCert);
|
||||
}
|
||||
|
|
@ -330,41 +348,49 @@ function addException() {
|
|||
return;
|
||||
}
|
||||
|
||||
var overrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
var overrideService = Cc["@mozilla.org/security/certoverride;1"].getService(
|
||||
Ci.nsICertOverrideService
|
||||
);
|
||||
var flags = 0;
|
||||
let confirmBucketId =
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_BASE;
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_BASE;
|
||||
if (gSecInfo.isUntrusted) {
|
||||
flags |= overrideService.ERROR_UNTRUSTED;
|
||||
confirmBucketId +=
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_UNTRUSTED;
|
||||
Ci.nsISecurityUITelemetry
|
||||
.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_UNTRUSTED;
|
||||
}
|
||||
if (gSecInfo.isDomainMismatch) {
|
||||
flags |= overrideService.ERROR_MISMATCH;
|
||||
confirmBucketId +=
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_DOMAIN;
|
||||
Ci.nsISecurityUITelemetry
|
||||
.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_DOMAIN;
|
||||
}
|
||||
if (gSecInfo.isNotValidAtThisTime) {
|
||||
flags |= overrideService.ERROR_TIME;
|
||||
confirmBucketId +=
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_TIME;
|
||||
Ci.nsISecurityUITelemetry
|
||||
.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_TIME;
|
||||
}
|
||||
|
||||
var permanentCheckbox = document.getElementById("permanent");
|
||||
var shouldStorePermanently = permanentCheckbox.checked &&
|
||||
!inPrivateBrowsingMode();
|
||||
var shouldStorePermanently =
|
||||
permanentCheckbox.checked && !inPrivateBrowsingMode();
|
||||
if (!permanentCheckbox.checked) {
|
||||
gSecHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_DONT_REMEMBER_EXCEPTION);
|
||||
gSecHistogram.add(
|
||||
Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_DONT_REMEMBER_EXCEPTION
|
||||
);
|
||||
}
|
||||
|
||||
gSecHistogram.add(confirmBucketId);
|
||||
var uri = getURI();
|
||||
overrideService.rememberValidityOverride(
|
||||
uri.asciiHost, uri.port,
|
||||
uri.asciiHost,
|
||||
uri.port,
|
||||
gCert,
|
||||
flags,
|
||||
!shouldStorePermanently);
|
||||
!shouldStorePermanently
|
||||
);
|
||||
|
||||
let args = window.arguments;
|
||||
if (args && args[0]) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ document.addEventListener("dialogaccept", onDialogAccept);
|
|||
|
||||
async function onBrowseBtnPress() {
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let [loadPK11ModuleFilePickerTitle] = await document.l10n.formatValues([{id: "load-pk11-module-file-picker-title"}]);
|
||||
let [loadPK11ModuleFilePickerTitle] = await document.l10n.formatValues([
|
||||
{ id: "load-pk11-module-file-picker-title" },
|
||||
]);
|
||||
fp.init(window, loadPK11ModuleFilePickerTitle, Ci.nsIFilePicker.modeOpen);
|
||||
fp.appendFilters(Ci.nsIFilePicker.filterAll);
|
||||
fp.open(rv => {
|
||||
|
|
@ -35,8 +37,9 @@ async function onBrowseBtnPress() {
|
|||
function onDialogAccept(event) {
|
||||
let nameBox = document.getElementById("device_name");
|
||||
let pathBox = document.getElementById("device_path");
|
||||
let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
|
||||
.getService(Ci.nsIPKCS11ModuleDB);
|
||||
let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
|
||||
Ci.nsIPKCS11ModuleDB
|
||||
);
|
||||
|
||||
try {
|
||||
pkcs11ModuleDB.addModule(nameBox.value, pathBox.value, 0, 0);
|
||||
|
|
@ -47,7 +50,7 @@ function onDialogAccept(event) {
|
|||
}
|
||||
|
||||
async function addModuleFailure(l10nID) {
|
||||
let [AddModuleFailure] = await document.l10n.formatValues([{id: l10nID}]);
|
||||
let [AddModuleFailure] = await document.l10n.formatValues([{ id: l10nID }]);
|
||||
alertPromptService(null, AddModuleFailure);
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +65,10 @@ function validateModuleName() {
|
|||
dialogNode.setAttribute("buttondisabledaccept", true);
|
||||
}
|
||||
if (name == "Root Certs") {
|
||||
document.l10n.setAttributes(helpText, "load-module-help-root-certs-module-name");
|
||||
document.l10n.setAttributes(
|
||||
helpText,
|
||||
"load-module-help-root-certs-module-name"
|
||||
);
|
||||
dialogNode.setAttribute("buttondisabledaccept", true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,13 @@ function viewCertHelper(parent, cert) {
|
|||
return;
|
||||
}
|
||||
|
||||
Services.ww.openWindow(parent, "chrome://pippki/content/certViewer.xul",
|
||||
"_blank", "centerscreen,chrome", cert);
|
||||
Services.ww.openWindow(
|
||||
parent,
|
||||
"chrome://pippki/content/certViewer.xul",
|
||||
"_blank",
|
||||
"centerscreen,chrome",
|
||||
cert
|
||||
);
|
||||
}
|
||||
|
||||
function getDERString(cert) {
|
||||
|
|
@ -44,8 +49,9 @@ function getDERString(cert) {
|
|||
}
|
||||
|
||||
function getPKCS7String(certArray) {
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"]
|
||||
.createInstance(Ci.nsIX509CertList);
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"].createInstance(
|
||||
Ci.nsIX509CertList
|
||||
);
|
||||
for (let cert of certArray) {
|
||||
certList.addCert(cert);
|
||||
}
|
||||
|
|
@ -57,17 +63,20 @@ function getPEMString(cert) {
|
|||
// Wrap the Base64 string into lines of 64 characters with CRLF line breaks
|
||||
// (as specified in RFC 1421).
|
||||
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
|
||||
return "-----BEGIN CERTIFICATE-----\r\n"
|
||||
+ wrapped
|
||||
+ "\r\n-----END CERTIFICATE-----\r\n";
|
||||
return (
|
||||
"-----BEGIN CERTIFICATE-----\r\n" +
|
||||
wrapped +
|
||||
"\r\n-----END CERTIFICATE-----\r\n"
|
||||
);
|
||||
}
|
||||
|
||||
function alertPromptService(title, message) {
|
||||
// XXX Bug 1425832 - Using Services.prompt here causes tests to report memory
|
||||
// leaks.
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"].
|
||||
getService(Ci.nsIPromptService);
|
||||
var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(
|
||||
Ci.nsIPromptService
|
||||
);
|
||||
ps.alert(window, title, message);
|
||||
}
|
||||
|
||||
|
|
@ -86,10 +95,11 @@ function certToFilename(cert) {
|
|||
let filename = cert.displayName;
|
||||
|
||||
// Remove unneeded and/or unsafe characters.
|
||||
filename = filename.replace(/\s/g, "")
|
||||
.replace(/\./g, "_")
|
||||
.replace(/\\/g, "")
|
||||
.replace(/\//g, "");
|
||||
filename = filename
|
||||
.replace(/\s/g, "")
|
||||
.replace(/\./g, "_")
|
||||
.replace(/\\/g, "")
|
||||
.replace(/\//g, "");
|
||||
|
||||
// Ci.nsIFilePicker.defaultExtension is more of a suggestion to some
|
||||
// implementations, so we include the extension in the file name as well. This
|
||||
|
|
@ -110,17 +120,17 @@ async function exportToFile(parent, cert) {
|
|||
}
|
||||
|
||||
let formats = {
|
||||
"base64": "*.crt; *.pem",
|
||||
base64: "*.crt; *.pem",
|
||||
"base64-chain": "*.crt; *.pem",
|
||||
"der": "*.der",
|
||||
"pkcs7": "*.p7c",
|
||||
der: "*.der",
|
||||
pkcs7: "*.p7c",
|
||||
"pkcs7-chain": "*.p7c",
|
||||
};
|
||||
let [saveCertAs, ...formatLabels] =
|
||||
await document.l10n.formatValues([
|
||||
"save-cert-as",
|
||||
...Object.keys(formats).map(f => "cert-format-" + f),
|
||||
].map(id => ({id})));
|
||||
let [saveCertAs, ...formatLabels] = await document.l10n.formatValues(
|
||||
["save-cert-as", ...Object.keys(formats).map(f => "cert-format-" + f)].map(
|
||||
id => ({ id })
|
||||
)
|
||||
);
|
||||
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(parent, saveCertAs, Ci.nsIFilePicker.modeSave);
|
||||
|
|
@ -134,8 +144,10 @@ async function exportToFile(parent, cert) {
|
|||
fp.open(resolve);
|
||||
});
|
||||
|
||||
if (filePickerResult != Ci.nsIFilePicker.returnOK &&
|
||||
filePickerResult != Ci.nsIFilePicker.returnReplace) {
|
||||
if (
|
||||
filePickerResult != Ci.nsIFilePicker.returnOK &&
|
||||
filePickerResult != Ci.nsIFilePicker.returnReplace
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -175,11 +187,11 @@ async function exportToFile(parent, cert) {
|
|||
const PRErrorCodeSuccess = 0;
|
||||
|
||||
// Certificate usages we care about in the certificate viewer.
|
||||
const certificateUsageSSLClient = 0x0001;
|
||||
const certificateUsageSSLServer = 0x0002;
|
||||
const certificateUsageSSLCA = 0x0008;
|
||||
const certificateUsageEmailSigner = 0x0010;
|
||||
const certificateUsageEmailRecipient = 0x0020;
|
||||
const certificateUsageSSLClient = 0x0001;
|
||||
const certificateUsageSSLServer = 0x0002;
|
||||
const certificateUsageSSLCA = 0x0008;
|
||||
const certificateUsageEmailSigner = 0x0010;
|
||||
const certificateUsageEmailRecipient = 0x0020;
|
||||
|
||||
// A map from the name of a certificate usage to the value of the usage.
|
||||
// Useful for printing debugging information and for enumerating all supported
|
||||
|
|
@ -205,18 +217,29 @@ const certificateUsages = {
|
|||
function asyncDetermineUsages(cert) {
|
||||
let promises = [];
|
||||
let now = Date.now() / 1000;
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
Object.keys(certificateUsages).forEach(usageString => {
|
||||
promises.push(new Promise((resolve, reject) => {
|
||||
let usage = certificateUsages[usageString];
|
||||
certdb.asyncVerifyCertAtTime(cert, usage, 0, null, now,
|
||||
(aPRErrorCode, aVerifiedChain, aHasEVPolicy) => {
|
||||
resolve({ usageString,
|
||||
errorCode: aPRErrorCode,
|
||||
chain: aVerifiedChain });
|
||||
});
|
||||
}));
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
let usage = certificateUsages[usageString];
|
||||
certdb.asyncVerifyCertAtTime(
|
||||
cert,
|
||||
usage,
|
||||
0,
|
||||
null,
|
||||
now,
|
||||
(aPRErrorCode, aVerifiedChain, aHasEVPolicy) => {
|
||||
resolve({
|
||||
usageString,
|
||||
errorCode: aPRErrorCode,
|
||||
chain: aVerifiedChain,
|
||||
});
|
||||
}
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
|
@ -236,9 +259,13 @@ function asyncDetermineUsages(cert) {
|
|||
* certificate chain for the given usage, or null if there is none.
|
||||
*/
|
||||
function getBestChain(results) {
|
||||
let usages = [ certificateUsageSSLServer, certificateUsageSSLClient,
|
||||
certificateUsageEmailSigner, certificateUsageEmailRecipient,
|
||||
certificateUsageSSLCA ];
|
||||
let usages = [
|
||||
certificateUsageSSLServer,
|
||||
certificateUsageSSLClient,
|
||||
certificateUsageEmailSigner,
|
||||
certificateUsageEmailRecipient,
|
||||
certificateUsageSSLCA,
|
||||
];
|
||||
for (let usage of usages) {
|
||||
let chain = getChainForUsage(results, usage);
|
||||
if (chain) {
|
||||
|
|
@ -262,8 +289,10 @@ function getBestChain(results) {
|
|||
*/
|
||||
function getChainForUsage(results, usage) {
|
||||
for (let result of results) {
|
||||
if (certificateUsages[result.usageString] == usage &&
|
||||
result.errorCode == PRErrorCodeSuccess) {
|
||||
if (
|
||||
certificateUsages[result.usageString] == usage &&
|
||||
result.errorCode == PRErrorCodeSuccess
|
||||
) {
|
||||
return Array.from(result.chain.getEnumerator());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
"use strict";
|
||||
|
||||
function onLoad() {
|
||||
let protectedAuthThread =
|
||||
window.arguments[0].QueryInterface(Ci.nsIProtectedAuthThread);
|
||||
let protectedAuthThread = window.arguments[0].QueryInterface(
|
||||
Ci.nsIProtectedAuthThread
|
||||
);
|
||||
|
||||
if (!protectedAuthThread) {
|
||||
window.close();
|
||||
|
|
|
|||
|
|
@ -7,22 +7,26 @@
|
|||
document.addEventListener("dialogaccept", resetPassword);
|
||||
|
||||
function resetPassword() {
|
||||
var pk11db = Cc["@mozilla.org/security/pk11tokendb;1"]
|
||||
.getService(Ci.nsIPK11TokenDB);
|
||||
var pk11db = Cc["@mozilla.org/security/pk11tokendb;1"].getService(
|
||||
Ci.nsIPK11TokenDB
|
||||
);
|
||||
var token = pk11db.getInternalKeyToken();
|
||||
token.reset();
|
||||
|
||||
try {
|
||||
Services.logins.removeAllLogins();
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
var bundle = document.getElementById("pippki_bundle");
|
||||
var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService();
|
||||
var promptService = Cc[
|
||||
"@mozilla.org/embedcomp/prompt-service;1"
|
||||
].getService();
|
||||
promptService = promptService.QueryInterface(Ci.nsIPromptService);
|
||||
if (promptService && bundle) {
|
||||
promptService.alert(window,
|
||||
bundle.getString("resetPasswordConfirmationTitle"),
|
||||
bundle.getString("resetPasswordConfirmationMessage"));
|
||||
promptService.alert(
|
||||
window,
|
||||
bundle.getString("resetPasswordConfirmationTitle"),
|
||||
bundle.getString("resetPasswordConfirmationMessage")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,8 +90,12 @@ function getPasswordStrength(password) {
|
|||
upperAlphaStrength = 3;
|
||||
}
|
||||
|
||||
let strength = (lengthStrength * 10) - 20 + (numericStrength * 10) +
|
||||
(symbolStrength * 15) + (upperAlphaStrength * 10);
|
||||
let strength =
|
||||
lengthStrength * 10 -
|
||||
20 +
|
||||
numericStrength * 10 +
|
||||
symbolStrength * 15 +
|
||||
upperAlphaStrength * 10;
|
||||
if (strength < 0) {
|
||||
strength = 0;
|
||||
}
|
||||
|
|
@ -118,5 +122,5 @@ function onPasswordInput(recalculatePasswordStrength) {
|
|||
// Disable the accept button if the two passwords don't match, and enable it
|
||||
// if the passwords do match.
|
||||
let pw2 = document.getElementById("pw2").value;
|
||||
document.documentElement.getButton("accept").disabled = (pw1 != pw2);
|
||||
document.documentElement.getButton("accept").disabled = pw1 != pw2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,13 +292,29 @@ class DER {
|
|||
let tag = this._peekByte();
|
||||
if (!tagList.includes(tag)) {
|
||||
throw new Error(
|
||||
`unexpected tag: found ${tag} instead of one of ${tagList}`);
|
||||
`unexpected tag: found ${tag} instead of one of ${tagList}`
|
||||
);
|
||||
}
|
||||
return this._readExpectedTLV(tag);
|
||||
}
|
||||
}
|
||||
|
||||
this.DER = { UNIVERSAL, CONSTRUCTED, CONTEXT_SPECIFIC, INTEGER, BIT_STRING,
|
||||
NULL, OBJECT_IDENTIFIER, PrintableString, TeletexString, IA5String,
|
||||
UTCTime, GeneralizedTime, UTF8String, SEQUENCE, SET, DER };
|
||||
this.DER = {
|
||||
UNIVERSAL,
|
||||
CONSTRUCTED,
|
||||
CONTEXT_SPECIFIC,
|
||||
INTEGER,
|
||||
BIT_STRING,
|
||||
NULL,
|
||||
OBJECT_IDENTIFIER,
|
||||
PrintableString,
|
||||
TeletexString,
|
||||
IA5String,
|
||||
UTCTime,
|
||||
GeneralizedTime,
|
||||
UTF8String,
|
||||
SEQUENCE,
|
||||
SET,
|
||||
DER,
|
||||
};
|
||||
this.EXPORTED_SYMBOLS = ["DER"];
|
||||
|
|
|
|||
|
|
@ -3,36 +3,50 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = [
|
||||
"RemoteSecuritySettings",
|
||||
];
|
||||
const EXPORTED_SYMBOLS = ["RemoteSecuritySettings"];
|
||||
|
||||
const {RemoteSettings} = ChromeUtils.import("resource://services-settings/remote-settings.js");
|
||||
const { RemoteSettings } = ChromeUtils.import(
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {X509} = ChromeUtils.import("resource://gre/modules/psm/X509.jsm", null);
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { X509 } = ChromeUtils.import(
|
||||
"resource://gre/modules/psm/X509.jsm",
|
||||
null
|
||||
);
|
||||
|
||||
const INTERMEDIATES_BUCKET_PREF = "security.remote_settings.intermediates.bucket";
|
||||
const INTERMEDIATES_CHECKED_SECONDS_PREF = "security.remote_settings.intermediates.checked";
|
||||
const INTERMEDIATES_COLLECTION_PREF = "security.remote_settings.intermediates.collection";
|
||||
const INTERMEDIATES_DL_PER_POLL_PREF = "security.remote_settings.intermediates.downloads_per_poll";
|
||||
const INTERMEDIATES_DL_PARALLEL_REQUESTS = "security.remote_settings.intermediates.parallel_downloads";
|
||||
const INTERMEDIATES_ENABLED_PREF = "security.remote_settings.intermediates.enabled";
|
||||
const INTERMEDIATES_SIGNER_PREF = "security.remote_settings.intermediates.signer";
|
||||
const LOGLEVEL_PREF = "browser.policies.loglevel";
|
||||
const INTERMEDIATES_BUCKET_PREF =
|
||||
"security.remote_settings.intermediates.bucket";
|
||||
const INTERMEDIATES_CHECKED_SECONDS_PREF =
|
||||
"security.remote_settings.intermediates.checked";
|
||||
const INTERMEDIATES_COLLECTION_PREF =
|
||||
"security.remote_settings.intermediates.collection";
|
||||
const INTERMEDIATES_DL_PER_POLL_PREF =
|
||||
"security.remote_settings.intermediates.downloads_per_poll";
|
||||
const INTERMEDIATES_DL_PARALLEL_REQUESTS =
|
||||
"security.remote_settings.intermediates.parallel_downloads";
|
||||
const INTERMEDIATES_ENABLED_PREF =
|
||||
"security.remote_settings.intermediates.enabled";
|
||||
const INTERMEDIATES_SIGNER_PREF =
|
||||
"security.remote_settings.intermediates.signer";
|
||||
const LOGLEVEL_PREF = "browser.policies.loglevel";
|
||||
|
||||
const ONECRL_BUCKET_PREF = "services.settings.security.onecrl.bucket";
|
||||
const ONECRL_BUCKET_PREF = "services.settings.security.onecrl.bucket";
|
||||
const ONECRL_COLLECTION_PREF = "services.settings.security.onecrl.collection";
|
||||
const ONECRL_SIGNER_PREF = "services.settings.security.onecrl.signer";
|
||||
const ONECRL_CHECKED_PREF = "services.settings.security.onecrl.checked";
|
||||
const ONECRL_SIGNER_PREF = "services.settings.security.onecrl.signer";
|
||||
const ONECRL_CHECKED_PREF = "services.settings.security.onecrl.checked";
|
||||
|
||||
const PINNING_ENABLED_PREF = "services.blocklist.pinning.enabled";
|
||||
const PINNING_BUCKET_PREF = "services.blocklist.pinning.bucket";
|
||||
const PINNING_COLLECTION_PREF = "services.blocklist.pinning.collection";
|
||||
const PINNING_ENABLED_PREF = "services.blocklist.pinning.enabled";
|
||||
const PINNING_BUCKET_PREF = "services.blocklist.pinning.bucket";
|
||||
const PINNING_COLLECTION_PREF = "services.blocklist.pinning.collection";
|
||||
const PINNING_CHECKED_SECONDS_PREF = "services.blocklist.pinning.checked";
|
||||
const PINNING_SIGNER_PREF = "services.blocklist.pinning.signer";
|
||||
const PINNING_SIGNER_PREF = "services.blocklist.pinning.signer";
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
|
|
@ -43,7 +57,11 @@ XPCOMUtils.defineLazyGetter(this, "baseAttachmentsURL", async () => {
|
|||
const serverInfo = await (await fetch(`${server}/`, {
|
||||
credentials: "omit",
|
||||
})).json();
|
||||
const {capabilities: {attachments: {base_url}}} = serverInfo;
|
||||
const {
|
||||
capabilities: {
|
||||
attachments: { base_url },
|
||||
},
|
||||
} = serverInfo;
|
||||
return base_url;
|
||||
});
|
||||
|
||||
|
|
@ -59,15 +77,24 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|||
});
|
||||
|
||||
function hexify(data) {
|
||||
return Array.from(data, (c, i) => data.charCodeAt(i).toString(16).padStart(2, "0")).join("");
|
||||
return Array.from(data, (c, i) =>
|
||||
data
|
||||
.charCodeAt(i)
|
||||
.toString(16)
|
||||
.padStart(2, "0")
|
||||
).join("");
|
||||
}
|
||||
|
||||
// Hash a UTF-8 string into a hex string with SHA256
|
||||
function getHash(str) {
|
||||
// return the two-digit hexadecimal code for a byte
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
|
||||
Ci.nsICryptoHash
|
||||
);
|
||||
hasher.init(Ci.nsICryptoHash.SHA256);
|
||||
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
|
||||
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
|
||||
Ci.nsIStringInputStream
|
||||
);
|
||||
stringStream.data = str;
|
||||
hasher.updateFromStream(stringStream, -1);
|
||||
|
||||
|
|
@ -100,7 +127,9 @@ class CRLiteState {
|
|||
this.state = state;
|
||||
}
|
||||
}
|
||||
CRLiteState.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsICRLiteState]);
|
||||
CRLiteState.prototype.QueryInterface = ChromeUtils.generateQI([
|
||||
Ci.nsICRLiteState,
|
||||
]);
|
||||
|
||||
class CertInfo {
|
||||
constructor(cert, subject) {
|
||||
|
|
@ -124,8 +153,9 @@ class IssuerAndSerialRevocationState extends RevocationState {
|
|||
this.serial = serial;
|
||||
}
|
||||
}
|
||||
IssuerAndSerialRevocationState.prototype.QueryInterface =
|
||||
ChromeUtils.generateQI([Ci.nsIIssuerAndSerialRevocationState]);
|
||||
IssuerAndSerialRevocationState.prototype.QueryInterface = ChromeUtils.generateQI(
|
||||
[Ci.nsIIssuerAndSerialRevocationState]
|
||||
);
|
||||
|
||||
class SubjectAndPubKeyRevocationState extends RevocationState {
|
||||
constructor(subject, pubKey, state) {
|
||||
|
|
@ -134,11 +164,12 @@ class SubjectAndPubKeyRevocationState extends RevocationState {
|
|||
this.pubKey = pubKey;
|
||||
}
|
||||
}
|
||||
SubjectAndPubKeyRevocationState.prototype.QueryInterface =
|
||||
ChromeUtils.generateQI([Ci.nsISubjectAndPubKeyRevocationState]);
|
||||
SubjectAndPubKeyRevocationState.prototype.QueryInterface = ChromeUtils.generateQI(
|
||||
[Ci.nsISubjectAndPubKeyRevocationState]
|
||||
);
|
||||
|
||||
function setRevocations(certStorage, revocations) {
|
||||
return new Promise((resolve) =>
|
||||
return new Promise(resolve =>
|
||||
certStorage.setRevocations(revocations, resolve)
|
||||
);
|
||||
}
|
||||
|
|
@ -148,79 +179,109 @@ function setRevocations(certStorage, revocations) {
|
|||
*
|
||||
* @param {Object} data Current records in the local db.
|
||||
*/
|
||||
const updateCertBlocklist = AppConstants.MOZ_NEW_CERT_STORAGE ?
|
||||
async function ({ data: { current, created, updated, deleted } }) {
|
||||
const certList = Cc["@mozilla.org/security/certstorage;1"]
|
||||
.getService(Ci.nsICertStorage);
|
||||
let items = [];
|
||||
const updateCertBlocklist = AppConstants.MOZ_NEW_CERT_STORAGE
|
||||
? async function({ data: { current, created, updated, deleted } }) {
|
||||
const certList = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let items = [];
|
||||
|
||||
// See if we have prior revocation data (this can happen when we can't open
|
||||
// the database and we have to re-create it (see bug 1546361)).
|
||||
let hasPriorRevocationData = await new Promise((resolve) => {
|
||||
certList.hasPriorData(Ci.nsICertStorage.DATA_TYPE_REVOCATION, (rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
resolve(hasPriorData);
|
||||
} else {
|
||||
// If calling hasPriorData failed, assume we need to reload
|
||||
// everything (even though it's unlikely doing so will succeed).
|
||||
resolve(false);
|
||||
}
|
||||
// See if we have prior revocation data (this can happen when we can't open
|
||||
// the database and we have to re-create it (see bug 1546361)).
|
||||
let hasPriorRevocationData = await new Promise(resolve => {
|
||||
certList.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_REVOCATION,
|
||||
(rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
resolve(hasPriorData);
|
||||
} else {
|
||||
// If calling hasPriorData failed, assume we need to reload
|
||||
// everything (even though it's unlikely doing so will succeed).
|
||||
resolve(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// If we don't have prior data, make it so we re-load everything.
|
||||
if (!hasPriorRevocationData) {
|
||||
deleted = [];
|
||||
updated = [];
|
||||
created = current;
|
||||
}
|
||||
|
||||
for (let item of deleted) {
|
||||
if (item.issuerName && item.serialNumber) {
|
||||
items.push(new IssuerAndSerialRevocationState(item.issuerName,
|
||||
item.serialNumber, Ci.nsICertStorage.STATE_UNSET));
|
||||
} else if (item.subject && item.pubKeyHash) {
|
||||
items.push(new SubjectAndPubKeyRevocationState(item.subject,
|
||||
item.pubKeyHash, Ci.nsICertStorage.STATE_UNSET));
|
||||
// If we don't have prior data, make it so we re-load everything.
|
||||
if (!hasPriorRevocationData) {
|
||||
deleted = [];
|
||||
updated = [];
|
||||
created = current;
|
||||
}
|
||||
}
|
||||
|
||||
const toAdd = created.concat(updated.map(u => u.new));
|
||||
|
||||
for (let item of toAdd) {
|
||||
if (item.issuerName && item.serialNumber) {
|
||||
items.push(new IssuerAndSerialRevocationState(item.issuerName,
|
||||
item.serialNumber, Ci.nsICertStorage.STATE_ENFORCE));
|
||||
} else if (item.subject && item.pubKeyHash) {
|
||||
items.push(new SubjectAndPubKeyRevocationState(item.subject,
|
||||
item.pubKeyHash, Ci.nsICertStorage.STATE_ENFORCE));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await setRevocations(certList, items);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
} : async function ({ data: { current: records } }) {
|
||||
const certList = Cc["@mozilla.org/security/certblocklist;1"]
|
||||
.getService(Ci.nsICertBlocklist);
|
||||
for (let item of records) {
|
||||
try {
|
||||
for (let item of deleted) {
|
||||
if (item.issuerName && item.serialNumber) {
|
||||
certList.revokeCertByIssuerAndSerial(item.issuerName,
|
||||
item.serialNumber);
|
||||
items.push(
|
||||
new IssuerAndSerialRevocationState(
|
||||
item.issuerName,
|
||||
item.serialNumber,
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
)
|
||||
);
|
||||
} else if (item.subject && item.pubKeyHash) {
|
||||
certList.revokeCertBySubjectAndPubKey(item.subject,
|
||||
item.pubKeyHash);
|
||||
items.push(
|
||||
new SubjectAndPubKeyRevocationState(
|
||||
item.subject,
|
||||
item.pubKeyHash,
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const toAdd = created.concat(updated.map(u => u.new));
|
||||
|
||||
for (let item of toAdd) {
|
||||
if (item.issuerName && item.serialNumber) {
|
||||
items.push(
|
||||
new IssuerAndSerialRevocationState(
|
||||
item.issuerName,
|
||||
item.serialNumber,
|
||||
Ci.nsICertStorage.STATE_ENFORCE
|
||||
)
|
||||
);
|
||||
} else if (item.subject && item.pubKeyHash) {
|
||||
items.push(
|
||||
new SubjectAndPubKeyRevocationState(
|
||||
item.subject,
|
||||
item.pubKeyHash,
|
||||
Ci.nsICertStorage.STATE_ENFORCE
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await setRevocations(certList, items);
|
||||
} catch (e) {
|
||||
// Prevent errors relating to individual blocklist entries from causing sync to fail.
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
certList.saveEntries();
|
||||
};
|
||||
: async function({ data: { current: records } }) {
|
||||
const certList = Cc["@mozilla.org/security/certblocklist;1"].getService(
|
||||
Ci.nsICertBlocklist
|
||||
);
|
||||
for (let item of records) {
|
||||
try {
|
||||
if (item.issuerName && item.serialNumber) {
|
||||
certList.revokeCertByIssuerAndSerial(
|
||||
item.issuerName,
|
||||
item.serialNumber
|
||||
);
|
||||
} else if (item.subject && item.pubKeyHash) {
|
||||
certList.revokeCertBySubjectAndPubKey(
|
||||
item.subject,
|
||||
item.pubKeyHash
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// Prevent errors relating to individual blocklist entries from causing sync to fail.
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
certList.saveEntries();
|
||||
};
|
||||
|
||||
/**
|
||||
* Modify the appropriate security pins based on records from the remote
|
||||
|
|
@ -233,8 +294,9 @@ async function updatePinningList({ data: { current: records } }) {
|
|||
return;
|
||||
}
|
||||
|
||||
const siteSecurityService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
const siteSecurityService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
|
||||
// clear the current preload list
|
||||
siteSecurityService.clearPreloads();
|
||||
|
|
@ -245,15 +307,20 @@ async function updatePinningList({ data: { current: records } }) {
|
|||
const { pinType, pins = [], versions } = item;
|
||||
if (versions.includes(Services.appinfo.version)) {
|
||||
if (pinType == "KeyPin" && pins.length) {
|
||||
siteSecurityService.setKeyPins(item.hostName,
|
||||
siteSecurityService.setKeyPins(
|
||||
item.hostName,
|
||||
item.includeSubdomains,
|
||||
item.expires,
|
||||
pins, true);
|
||||
pins,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (pinType == "STSPin") {
|
||||
siteSecurityService.setHSTSPreload(item.hostName,
|
||||
siteSecurityService.setHSTSPreload(
|
||||
item.hostName,
|
||||
item.includeSubdomains,
|
||||
item.expires);
|
||||
item.expires
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -271,18 +338,24 @@ var RemoteSecuritySettings = {
|
|||
* @returns {Object} intantiated clients for security remote settings.
|
||||
*/
|
||||
init() {
|
||||
const OneCRLBlocklistClient = RemoteSettings(Services.prefs.getCharPref(ONECRL_COLLECTION_PREF), {
|
||||
bucketNamePref: ONECRL_BUCKET_PREF,
|
||||
lastCheckTimePref: ONECRL_CHECKED_PREF,
|
||||
signerName: Services.prefs.getCharPref(ONECRL_SIGNER_PREF),
|
||||
});
|
||||
const OneCRLBlocklistClient = RemoteSettings(
|
||||
Services.prefs.getCharPref(ONECRL_COLLECTION_PREF),
|
||||
{
|
||||
bucketNamePref: ONECRL_BUCKET_PREF,
|
||||
lastCheckTimePref: ONECRL_CHECKED_PREF,
|
||||
signerName: Services.prefs.getCharPref(ONECRL_SIGNER_PREF),
|
||||
}
|
||||
);
|
||||
OneCRLBlocklistClient.on("sync", updateCertBlocklist);
|
||||
|
||||
const PinningBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PINNING_COLLECTION_PREF), {
|
||||
bucketNamePref: PINNING_BUCKET_PREF,
|
||||
lastCheckTimePref: PINNING_CHECKED_SECONDS_PREF,
|
||||
signerName: Services.prefs.getCharPref(PINNING_SIGNER_PREF),
|
||||
});
|
||||
const PinningBlocklistClient = RemoteSettings(
|
||||
Services.prefs.getCharPref(PINNING_COLLECTION_PREF),
|
||||
{
|
||||
bucketNamePref: PINNING_BUCKET_PREF,
|
||||
lastCheckTimePref: PINNING_CHECKED_SECONDS_PREF,
|
||||
signerName: Services.prefs.getCharPref(PINNING_SIGNER_PREF),
|
||||
}
|
||||
);
|
||||
PinningBlocklistClient.on("sync", updatePinningList);
|
||||
|
||||
let IntermediatePreloadsClient;
|
||||
|
|
@ -300,16 +373,21 @@ var RemoteSecuritySettings = {
|
|||
|
||||
class IntermediatePreloads {
|
||||
constructor() {
|
||||
this.client = RemoteSettings(Services.prefs.getCharPref(INTERMEDIATES_COLLECTION_PREF), {
|
||||
bucketNamePref: INTERMEDIATES_BUCKET_PREF,
|
||||
lastCheckTimePref: INTERMEDIATES_CHECKED_SECONDS_PREF,
|
||||
signerName: Services.prefs.getCharPref(INTERMEDIATES_SIGNER_PREF),
|
||||
localFields: ["cert_import_complete"],
|
||||
});
|
||||
this.client = RemoteSettings(
|
||||
Services.prefs.getCharPref(INTERMEDIATES_COLLECTION_PREF),
|
||||
{
|
||||
bucketNamePref: INTERMEDIATES_BUCKET_PREF,
|
||||
lastCheckTimePref: INTERMEDIATES_CHECKED_SECONDS_PREF,
|
||||
signerName: Services.prefs.getCharPref(INTERMEDIATES_SIGNER_PREF),
|
||||
localFields: ["cert_import_complete"],
|
||||
}
|
||||
);
|
||||
|
||||
this.client.on("sync", this.onSync.bind(this));
|
||||
Services.obs.addObserver(this.onObservePollEnd.bind(this),
|
||||
"remote-settings:changes-poll-end");
|
||||
Services.obs.addObserver(
|
||||
this.onObservePollEnd.bind(this),
|
||||
"remote-settings:changes-poll-end"
|
||||
);
|
||||
|
||||
log.debug("Intermediate Preloading: constructor");
|
||||
}
|
||||
|
|
@ -320,13 +398,23 @@ class IntermediatePreloads {
|
|||
|
||||
if (!Services.prefs.getBoolPref(INTERMEDIATES_ENABLED_PREF, true)) {
|
||||
log.debug("Intermediate Preloading is disabled");
|
||||
Services.obs.notifyObservers(null, "remote-security-settings:intermediates-updated", "disabled");
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"remote-security-settings:intermediates-updated",
|
||||
"disabled"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Download attachments that are awaiting download, up to a max.
|
||||
const maxDownloadsPerRun = Services.prefs.getIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
const parallelDownloads = Services.prefs.getIntPref(INTERMEDIATES_DL_PARALLEL_REQUESTS, 8);
|
||||
const maxDownloadsPerRun = Services.prefs.getIntPref(
|
||||
INTERMEDIATES_DL_PER_POLL_PREF,
|
||||
100
|
||||
);
|
||||
const parallelDownloads = Services.prefs.getIntPref(
|
||||
INTERMEDIATES_DL_PARALLEL_REQUESTS,
|
||||
8
|
||||
);
|
||||
|
||||
// Bug 1519256: Move this to a separate method that's on a separate timer
|
||||
// with a higher frequency (so we can attempt to download outstanding
|
||||
|
|
@ -334,17 +422,22 @@ class IntermediatePreloads {
|
|||
|
||||
// See if we have prior cert data (this can happen when we can't open the database and we
|
||||
// have to re-create it (see bug 1546361)).
|
||||
const certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let hasPriorCertData = await new Promise((resolve) => {
|
||||
certStorage.hasPriorData(Ci.nsICertStorage.DATA_TYPE_CERTIFICATE, (rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
resolve(hasPriorData);
|
||||
} else {
|
||||
// If calling hasPriorData failed, assume we need to reload everything (even though
|
||||
// it's unlikely doing so will succeed).
|
||||
resolve(false);
|
||||
const certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let hasPriorCertData = await new Promise(resolve => {
|
||||
certStorage.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_CERTIFICATE,
|
||||
(rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
resolve(hasPriorData);
|
||||
} else {
|
||||
// If calling hasPriorData failed, assume we need to reload everything (even though
|
||||
// it's unlikely doing so will succeed).
|
||||
resolve(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
const col = await this.client.openCollection();
|
||||
// If we don't have prior data, make it so we re-load everything.
|
||||
|
|
@ -352,7 +445,7 @@ class IntermediatePreloads {
|
|||
const { data: current } = await col.list({ order: "" }); // no sort needed.
|
||||
const toReset = current.filter(record => record.cert_import_complete);
|
||||
await col.db.execute(transaction => {
|
||||
toReset.forEach((record) => {
|
||||
toReset.forEach(record => {
|
||||
transaction.update({ ...record, cert_import_complete: false });
|
||||
});
|
||||
});
|
||||
|
|
@ -363,7 +456,11 @@ class IntermediatePreloads {
|
|||
log.debug(`There are ${waiting.length} intermediates awaiting download.`);
|
||||
if (waiting.length == 0) {
|
||||
// Nothing to do.
|
||||
Services.obs.notifyObservers(null, "remote-security-settings:intermediates-updated", "success");
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"remote-security-settings:intermediates-updated",
|
||||
"success"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -371,33 +468,38 @@ class IntermediatePreloads {
|
|||
let recordsCertsAndSubjects = [];
|
||||
for (let i = 0; i < toDownload.length; i += parallelDownloads) {
|
||||
const chunk = toDownload.slice(i, i + parallelDownloads);
|
||||
const downloaded = await Promise.all(chunk.map(record => this.maybeDownloadAttachment(record)));
|
||||
const downloaded = await Promise.all(
|
||||
chunk.map(record => this.maybeDownloadAttachment(record))
|
||||
);
|
||||
recordsCertsAndSubjects = recordsCertsAndSubjects.concat(downloaded);
|
||||
}
|
||||
|
||||
let certInfos = [];
|
||||
let recordsToUpdate = [];
|
||||
for (let {record, cert, subject} of recordsCertsAndSubjects) {
|
||||
for (let { record, cert, subject } of recordsCertsAndSubjects) {
|
||||
if (cert && subject) {
|
||||
certInfos.push(new CertInfo(cert, subject));
|
||||
recordsToUpdate.push(record);
|
||||
}
|
||||
}
|
||||
let result = await new Promise((resolve) => {
|
||||
let result = await new Promise(resolve => {
|
||||
certStorage.addCerts(certInfos, resolve);
|
||||
}).catch((err) => err);
|
||||
}).catch(err => err);
|
||||
if (result != Cr.NS_OK) {
|
||||
Cu.reportError(`certStorage.addCerts failed: ${result}`);
|
||||
return;
|
||||
}
|
||||
await col.db.execute(transaction => {
|
||||
recordsToUpdate.forEach((record) => {
|
||||
recordsToUpdate.forEach(record => {
|
||||
transaction.update({ ...record, cert_import_complete: true });
|
||||
});
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, "remote-security-settings:intermediates-updated",
|
||||
"success");
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"remote-security-settings:intermediates-updated",
|
||||
"success"
|
||||
);
|
||||
}
|
||||
|
||||
async onObservePollEnd(subject, topic, data) {
|
||||
|
|
@ -419,15 +521,20 @@ class IntermediatePreloads {
|
|||
|
||||
log.debug(`Removing ${deleted.length} Intermediate certificates`);
|
||||
await this.removeCerts(deleted);
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let hasPriorCRLiteData = await new Promise((resolve) => {
|
||||
certStorage.hasPriorData(Ci.nsICertStorage.DATA_TYPE_CRLITE, (rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
resolve(hasPriorData);
|
||||
} else {
|
||||
resolve(false);
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let hasPriorCRLiteData = await new Promise(resolve => {
|
||||
certStorage.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_CRLITE,
|
||||
(rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
resolve(hasPriorData);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
if (!hasPriorCRLiteData) {
|
||||
deleted = [];
|
||||
|
|
@ -437,15 +544,26 @@ class IntermediatePreloads {
|
|||
const toAdd = created.concat(updated.map(u => u.new));
|
||||
let entries = [];
|
||||
for (let entry of deleted) {
|
||||
entries.push(new CRLiteState(entry.subjectDN, entry.pubKeyHash,
|
||||
Ci.nsICertStorage.STATE_UNSET));
|
||||
entries.push(
|
||||
new CRLiteState(
|
||||
entry.subjectDN,
|
||||
entry.pubKeyHash,
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
)
|
||||
);
|
||||
}
|
||||
for (let entry of toAdd) {
|
||||
entries.push(new CRLiteState(entry.subjectDN, entry.pubKeyHash,
|
||||
entry.crlite_enrolled ? Ci.nsICertStorage.STATE_ENFORCE
|
||||
: Ci.nsICertStorage.STATE_UNSET));
|
||||
entries.push(
|
||||
new CRLiteState(
|
||||
entry.subjectDN,
|
||||
entry.pubKeyHash,
|
||||
entry.crlite_enrolled
|
||||
? Ci.nsICertStorage.STATE_ENFORCE
|
||||
: Ci.nsICertStorage.STATE_UNSET
|
||||
)
|
||||
);
|
||||
}
|
||||
await new Promise((resolve) => certStorage.setCRLiteState(entries, resolve));
|
||||
await new Promise(resolve => certStorage.setCRLiteState(entries, resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -455,7 +573,9 @@ class IntermediatePreloads {
|
|||
* @return {Promise} resolves to a Uint8Array on success
|
||||
*/
|
||||
async _downloadAttachmentBytes(record) {
|
||||
const {attachment: {location}} = record;
|
||||
const {
|
||||
attachment: { location },
|
||||
} = record;
|
||||
const remoteFilePath = (await baseAttachmentsURL) + location;
|
||||
const headers = new Headers();
|
||||
headers.set("Accept-Encoding", "gzip");
|
||||
|
|
@ -463,15 +583,16 @@ class IntermediatePreloads {
|
|||
return fetch(remoteFilePath, {
|
||||
headers,
|
||||
credentials: "omit",
|
||||
}).then(resp => {
|
||||
log.debug(`Download fetch completed: ${resp.ok} ${resp.status}`);
|
||||
if (!resp.ok) {
|
||||
Cu.reportError(`Failed to fetch ${remoteFilePath}: ${resp.status}`);
|
||||
return Promise.reject();
|
||||
}
|
||||
return resp.arrayBuffer();
|
||||
})
|
||||
.then(buffer => new Uint8Array(buffer));
|
||||
.then(resp => {
|
||||
log.debug(`Download fetch completed: ${resp.ok} ${resp.status}`);
|
||||
if (!resp.ok) {
|
||||
Cu.reportError(`Failed to fetch ${remoteFilePath}: ${resp.status}`);
|
||||
return Promise.reject();
|
||||
}
|
||||
return resp.arrayBuffer();
|
||||
})
|
||||
.then(buffer => new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -487,7 +608,9 @@ class IntermediatePreloads {
|
|||
* name of the same.
|
||||
*/
|
||||
async maybeDownloadAttachment(record) {
|
||||
const {attachment: {hash, size}} = record;
|
||||
const {
|
||||
attachment: { hash, size },
|
||||
} = record;
|
||||
let result = { record, cert: null, subject: null };
|
||||
|
||||
let attachmentData;
|
||||
|
|
@ -506,7 +629,11 @@ class IntermediatePreloads {
|
|||
|
||||
// check the length
|
||||
if (attachmentData.length !== size) {
|
||||
log.debug(`Unexpected attachment length. Hash=${hash} Lengths ${attachmentData.length} != ${size}`);
|
||||
log.debug(
|
||||
`Unexpected attachment length. Hash=${hash} Lengths ${
|
||||
attachmentData.length
|
||||
} != ${size}`
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -514,7 +641,9 @@ class IntermediatePreloads {
|
|||
let dataAsString = gTextDecoder.decode(attachmentData);
|
||||
let calculatedHash = getHash(dataAsString);
|
||||
if (calculatedHash !== hash) {
|
||||
log.warn(`Invalid hash. CalculatedHash=${calculatedHash}, Hash=${hash}, data=${dataAsString}`);
|
||||
log.warn(
|
||||
`Invalid hash. CalculatedHash=${calculatedHash}, Hash=${hash}, data=${dataAsString}`
|
||||
);
|
||||
return result;
|
||||
}
|
||||
log.debug(`downloaded cert with hash=${hash}, size=${size}`);
|
||||
|
|
@ -530,7 +659,9 @@ class IntermediatePreloads {
|
|||
cert.parse(certBytes);
|
||||
// get the DER-encoded subject and get a base64-encoded string from it
|
||||
// TODO(bug 1542028): add getters for _der and _bytes
|
||||
subjectBase64 = btoa(bytesToString(cert.tbsCertificate.subject._der._bytes));
|
||||
subjectBase64 = btoa(
|
||||
bytesToString(cert.tbsCertificate.subject._der._bytes)
|
||||
);
|
||||
} catch (err) {
|
||||
Cu.reportError(`Failed to decode cert: ${err}`);
|
||||
return result;
|
||||
|
|
@ -545,11 +676,13 @@ class IntermediatePreloads {
|
|||
}
|
||||
|
||||
async removeCerts(recordsToRemove) {
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let hashes = recordsToRemove.map(record => record.derHash);
|
||||
let result = await new Promise((resolve) => {
|
||||
certStorage.removeCertsByHashes(hashes, resolve);
|
||||
}).catch((err) => err);
|
||||
let result = await new Promise(resolve => {
|
||||
certStorage.removeCertsByHashes(hashes, resolve);
|
||||
}).catch(err => err);
|
||||
if (result != Cr.NS_OK) {
|
||||
Cu.reportError(`Failed to remove some intermediate certificates`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class OID {
|
|||
let value = bytes.shift();
|
||||
accumulator *= 128;
|
||||
if (value > 128) {
|
||||
accumulator += (value - 128);
|
||||
accumulator += value - 128;
|
||||
} else {
|
||||
accumulator += value;
|
||||
this._values.push(accumulator);
|
||||
|
|
@ -412,10 +412,14 @@ class AttributeTypeAndValue extends DecodedDER {
|
|||
// We don't support universalString or bmpString.
|
||||
// IA5String is supported because it is valid if `type == id-emailaddress`.
|
||||
// Lint TODO: validate that the type of string is valid given `type`.
|
||||
this._value.parse(contents.readTLVChoice([ DER.UTF8String,
|
||||
DER.PrintableString,
|
||||
DER.TeletexString,
|
||||
DER.IA5String ]));
|
||||
this._value.parse(
|
||||
contents.readTLVChoice([
|
||||
DER.UTF8String,
|
||||
DER.PrintableString,
|
||||
DER.TeletexString,
|
||||
DER.IA5String,
|
||||
])
|
||||
);
|
||||
contents.assertAtEnd();
|
||||
this._der.assertAtEnd();
|
||||
}
|
||||
|
|
@ -534,7 +538,8 @@ class Time extends DecodedDER {
|
|||
let s1 = this._validateDigit(contents.readByte());
|
||||
let s2 = this._validateDigit(contents.readByte());
|
||||
let second = s1 * 10 + s2;
|
||||
if (second > 60) { // leap-seconds mean this can be as much as 60
|
||||
if (second > 60) {
|
||||
// leap-seconds mean this can be as much as 60
|
||||
throw new Error(ERROR_TIME_NOT_VALID);
|
||||
}
|
||||
|
||||
|
|
@ -545,8 +550,7 @@ class Time extends DecodedDER {
|
|||
// Lint TODO: verify that the Time doesn't specify a nonsensical
|
||||
// month/day/etc.
|
||||
// months are zero-indexed in JS
|
||||
this._time = new Date(Date.UTC(year, month - 1, day, hour, minute,
|
||||
second));
|
||||
this._time = new Date(Date.UTC(year, month - 1, day, hour, minute, second));
|
||||
|
||||
contents.assertAtEnd();
|
||||
this._der.assertAtEnd();
|
||||
|
|
@ -586,10 +590,12 @@ class Validity extends DecodedDER {
|
|||
|
||||
parseOverride() {
|
||||
let contents = readSEQUENCEAndMakeDER(this._der);
|
||||
this._notBefore.parse(contents.readTLVChoice(
|
||||
[DER.UTCTime, DER.GeneralizedTime]));
|
||||
this._notAfter.parse(contents.readTLVChoice(
|
||||
[DER.UTCTime, DER.GeneralizedTime]));
|
||||
this._notBefore.parse(
|
||||
contents.readTLVChoice([DER.UTCTime, DER.GeneralizedTime])
|
||||
);
|
||||
this._notAfter.parse(
|
||||
contents.readTLVChoice([DER.UTCTime, DER.GeneralizedTime])
|
||||
);
|
||||
contents.assertAtEnd();
|
||||
this._der.assertAtEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var FakeTransportSecurityInfo = function() {
|
||||
};
|
||||
var FakeTransportSecurityInfo = function() {};
|
||||
|
||||
FakeTransportSecurityInfo.prototype = {
|
||||
serverCert: null,
|
||||
|
|
@ -22,9 +21,13 @@ FakeTransportSecurityInfo.prototype = {
|
|||
|
||||
function whenNewWindowLoaded(aOptions, aCallback) {
|
||||
let win = OpenBrowserWindow(aOptions);
|
||||
win.addEventListener("load", function() {
|
||||
aCallback(win);
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
aCallback(win);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
// This is a template to help porting global private browsing tests
|
||||
|
|
@ -35,26 +38,39 @@ function test() {
|
|||
let windowsToClose = [];
|
||||
let testURI = "about:blank";
|
||||
let uri;
|
||||
let gSSService = Cc["@mozilla.org/ssservice;1"].
|
||||
getService(Ci.nsISiteSecurityService);
|
||||
let gSSService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
|
||||
function privacyFlags(aIsPrivateMode) {
|
||||
return aIsPrivateMode ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
|
||||
}
|
||||
|
||||
function doTest(aIsPrivateMode, aWindow, aCallback) {
|
||||
BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then(() => {
|
||||
let secInfo = new FakeTransportSecurityInfo();
|
||||
uri = aWindow.Services.io.newURI("https://localhost/img.png");
|
||||
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
|
||||
"max-age=1000", secInfo, privacyFlags(aIsPrivateMode),
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
|
||||
privacyFlags(aIsPrivateMode)),
|
||||
"checking sts host");
|
||||
BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then(
|
||||
() => {
|
||||
let secInfo = new FakeTransportSecurityInfo();
|
||||
uri = aWindow.Services.io.newURI("https://localhost/img.png");
|
||||
gSSService.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
"max-age=1000",
|
||||
secInfo,
|
||||
privacyFlags(aIsPrivateMode),
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
ok(
|
||||
gSSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
privacyFlags(aIsPrivateMode)
|
||||
),
|
||||
"checking sts host"
|
||||
);
|
||||
|
||||
aCallback();
|
||||
});
|
||||
aCallback();
|
||||
}
|
||||
);
|
||||
|
||||
BrowserTestUtils.loadURI(aWindow.gBrowser.selectedBrowser, testURI);
|
||||
}
|
||||
|
|
@ -65,11 +81,13 @@ function test() {
|
|||
// execute should only be called when need, like when you are opening
|
||||
// web pages on the test. If calling executeSoon() is not necesary, then
|
||||
// call whenNewWindowLoaded() instead of testOnWindow() on your test.
|
||||
executeSoon(function() { aCallback(aWin); });
|
||||
executeSoon(function() {
|
||||
aCallback(aWin);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// this function is called after calling finish() on the test.
|
||||
// this function is called after calling finish() on the test.
|
||||
registerCleanupFunction(function() {
|
||||
windowsToClose.forEach(function(aWin) {
|
||||
aWin.close();
|
||||
|
|
@ -79,14 +97,14 @@ function test() {
|
|||
});
|
||||
|
||||
// test first when on private mode
|
||||
testOnWindow({private: true}, function(aWin) {
|
||||
testOnWindow({ private: true }, function(aWin) {
|
||||
doTest(true, aWin, function() {
|
||||
// test when not on private mode
|
||||
testOnWindow({}, function(aWin) {
|
||||
doTest(false, aWin, function() {
|
||||
// test again when on private mode
|
||||
testOnWindow({private: true}, function(aWin) {
|
||||
doTest(true, aWin, function () {
|
||||
testOnWindow({ private: true }, function(aWin) {
|
||||
doTest(true, aWin, function() {
|
||||
finish();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,27 +8,34 @@
|
|||
// certificates are valid for or what errors prevented the certificates from
|
||||
// being verified.
|
||||
|
||||
var { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
var { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
var { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
add_task(async function testCAandTitle() {
|
||||
let cert = await readCertificate("ca.pem", "CTu,CTu,CTu");
|
||||
let win = await displayCertificate(cert);
|
||||
checkUsages(win, [{id: "verify-ssl-ca", args: null}]);
|
||||
checkUsages(win, [{ id: "verify-ssl-ca", args: null }]);
|
||||
checkDetailsPane(win, ["ca"]);
|
||||
|
||||
// There's no real need to test the title for every cert, so we just test it
|
||||
// once here.
|
||||
Assert.deepEqual(win.document.l10n.getAttributes(win.document.documentElement),
|
||||
{args: { certName: "ca"}, id: "cert-viewer-title"},
|
||||
"Actual and expected title should match");
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(win.document.documentElement),
|
||||
{ args: { certName: "ca" }, id: "cert-viewer-title" },
|
||||
"Actual and expected title should match"
|
||||
);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
add_task(async function testSSLEndEntity() {
|
||||
let cert = await readCertificate("ssl-ee.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkUsages(win, [{id: "verify-ssl-server", args: null}, {id: "verify-ssl-client", args: null}]);
|
||||
checkUsages(win, [
|
||||
{ id: "verify-ssl-server", args: null },
|
||||
{ id: "verify-ssl-client", args: null },
|
||||
]);
|
||||
checkDetailsPane(win, ["ca", "ssl-ee"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -36,7 +43,10 @@ add_task(async function testSSLEndEntity() {
|
|||
add_task(async function testEmailEndEntity() {
|
||||
let cert = await readCertificate("email-ee.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkUsages(win, [{id: "verify-email-recip", args: null}, {id: "verify-email-signer", args: null}]);
|
||||
checkUsages(win, [
|
||||
{ id: "verify-email-recip", args: null },
|
||||
{ id: "verify-email-signer", args: null },
|
||||
]);
|
||||
checkDetailsPane(win, ["ca", "email-ee"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -44,7 +54,7 @@ add_task(async function testEmailEndEntity() {
|
|||
add_task(async function testCodeSignEndEntity() {
|
||||
let cert = await readCertificate("code-ee.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkError(win, {id: "cert-not-verified-unknown", args: null});
|
||||
checkError(win, { id: "cert-not-verified-unknown", args: null });
|
||||
checkDetailsPane(win, ["code-ee"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -52,7 +62,7 @@ add_task(async function testCodeSignEndEntity() {
|
|||
add_task(async function testExpired() {
|
||||
let cert = await readCertificate("expired-ca.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkError(win, {id: "cert-not-verified-cert-expired", args: null});
|
||||
checkError(win, { id: "cert-not-verified-cert-expired", args: null });
|
||||
checkDetailsPane(win, ["expired-ca"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
|
|
@ -60,7 +70,7 @@ add_task(async function testExpired() {
|
|||
// same task.
|
||||
let eeCert = await readCertificate("ee-from-expired-ca.pem", ",,");
|
||||
let eeWin = await displayCertificate(eeCert);
|
||||
checkError(eeWin, {id: "cert-not-verified-ca-invalid", args: null});
|
||||
checkError(eeWin, { id: "cert-not-verified-ca-invalid", args: null });
|
||||
checkDetailsPane(eeWin, ["ee-from-expired-ca"]);
|
||||
await BrowserTestUtils.closeWindow(eeWin);
|
||||
});
|
||||
|
|
@ -68,7 +78,7 @@ add_task(async function testExpired() {
|
|||
add_task(async function testUnknownIssuer() {
|
||||
let cert = await readCertificate("unknown-issuer.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkError(win, {id: "cert-not-verified-issuer-unknown", args: null});
|
||||
checkError(win, { id: "cert-not-verified-issuer-unknown", args: null });
|
||||
checkDetailsPane(win, ["unknown-issuer"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -76,7 +86,7 @@ add_task(async function testUnknownIssuer() {
|
|||
add_task(async function testInsecureAlgo() {
|
||||
let cert = await readCertificate("md5-ee.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkError(win, {id: "cert-not-verified_algorithm-disabled", args: null});
|
||||
checkError(win, { id: "cert-not-verified_algorithm-disabled", args: null });
|
||||
checkDetailsPane(win, ["md5-ee"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -84,7 +94,7 @@ add_task(async function testInsecureAlgo() {
|
|||
add_task(async function testUntrusted() {
|
||||
let cert = await readCertificate("untrusted-ca.pem", "p,p,p");
|
||||
let win = await displayCertificate(cert);
|
||||
checkError(win, {id: "cert-not-verified-cert-not-trusted", args: null});
|
||||
checkError(win, { id: "cert-not-verified-cert-not-trusted", args: null });
|
||||
checkDetailsPane(win, ["untrusted-ca"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
|
|
@ -92,7 +102,7 @@ add_task(async function testUntrusted() {
|
|||
// same task.
|
||||
let eeCert = await readCertificate("ee-from-untrusted-ca.pem", ",,");
|
||||
let eeWin = await displayCertificate(eeCert);
|
||||
checkError(eeWin, {id: "cert-not-verified-issuer-not-trusted", args: null});
|
||||
checkError(eeWin, { id: "cert-not-verified-issuer-not-trusted", args: null });
|
||||
checkDetailsPane(eeWin, ["ee-from-untrusted-ca"]);
|
||||
await BrowserTestUtils.closeWindow(eeWin);
|
||||
});
|
||||
|
|
@ -102,29 +112,44 @@ add_task(async function testRevoked() {
|
|||
// problem if another test re-uses a certificate with this same key (perhaps
|
||||
// likely) and subject (less likely).
|
||||
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
||||
let certBlocklist = Cc["@mozilla.org/security/certstorage;1"]
|
||||
.getService(Ci.nsICertStorage);
|
||||
let result = await new Promise((resolve) =>
|
||||
certBlocklist.setRevocations([{
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISubjectAndPubKeyRevocationState]),
|
||||
subject: "MBIxEDAOBgNVBAMMB3Jldm9rZWQ=", // CN=revoked
|
||||
pubKey: "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=", // hash of the shared key
|
||||
state: Ci.nsICertStorage.STATE_ENFORCE, // yes, we want this to be revoked
|
||||
}], resolve));
|
||||
let certBlocklist = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let result = await new Promise(resolve =>
|
||||
certBlocklist.setRevocations(
|
||||
[
|
||||
{
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISubjectAndPubKeyRevocationState,
|
||||
]),
|
||||
subject: "MBIxEDAOBgNVBAMMB3Jldm9rZWQ=", // CN=revoked
|
||||
pubKey: "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=", // hash of the shared key
|
||||
state: Ci.nsICertStorage.STATE_ENFORCE, // yes, we want this to be revoked
|
||||
},
|
||||
],
|
||||
resolve
|
||||
)
|
||||
);
|
||||
Assert.equal(result, Cr.NS_OK, "setting revocation state should succeed");
|
||||
} else {
|
||||
let certBlocklist = Cc["@mozilla.org/security/certblocklist;1"]
|
||||
.getService(Ci.nsICertBlocklist);
|
||||
let certBlocklist = Cc["@mozilla.org/security/certblocklist;1"].getService(
|
||||
Ci.nsICertBlocklist
|
||||
);
|
||||
certBlocklist.revokeCertBySubjectAndPubKey(
|
||||
"MBIxEDAOBgNVBAMMB3Jldm9rZWQ=", // CN=revoked
|
||||
"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8="); // hash of the shared key
|
||||
"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8="
|
||||
); // hash of the shared key
|
||||
}
|
||||
let cert = await readCertificate("revoked.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
// As of bug 1312827, OneCRL only applies to TLS web server certificates, so
|
||||
// this certificate will actually verify successfully for every end-entity
|
||||
// usage except TLS web server.
|
||||
checkUsages(win, [{id: "verify-email-recip", args: null}, {id: "verify-email-signer", args: null}, {id: "verify-ssl-client", args: null}]);
|
||||
checkUsages(win, [
|
||||
{ id: "verify-email-recip", args: null },
|
||||
{ id: "verify-email-signer", args: null },
|
||||
{ id: "verify-ssl-client", args: null },
|
||||
]);
|
||||
checkDetailsPane(win, ["ca", "revoked"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -136,7 +161,7 @@ add_task(async function testInvalid() {
|
|||
// message in this case.
|
||||
let cert = await readCertificate("invalid.pem", ",,");
|
||||
let win = await displayCertificate(cert);
|
||||
checkError(win, {id: "cert-not-verified-unknown", args: null});
|
||||
checkError(win, { id: "cert-not-verified-unknown", args: null });
|
||||
checkDetailsPane(win, ["invalid"]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -162,11 +187,21 @@ add_task(async function testLongOID() {
|
|||
* viewer window when the usages have been determined.
|
||||
*/
|
||||
function displayCertificate(certificate) {
|
||||
let win = window.openDialog("chrome://pippki/content/certViewer.xul", "",
|
||||
"", certificate);
|
||||
return TestUtils.topicObserved("ViewCertDetails:CertUsagesDone",
|
||||
(subject, data) => subject == win)
|
||||
.then(([subject, data]) => subject, error => { throw error; });
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/certViewer.xul",
|
||||
"",
|
||||
"",
|
||||
certificate
|
||||
);
|
||||
return TestUtils.topicObserved(
|
||||
"ViewCertDetails:CertUsagesDone",
|
||||
(subject, data) => subject == win
|
||||
).then(
|
||||
([subject, data]) => subject,
|
||||
error => {
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -183,8 +218,10 @@ function getUsages(win) {
|
|||
let determinedUsages = [];
|
||||
let verifyInfoBox = win.document.getElementById("verify_info_box");
|
||||
Array.from(verifyInfoBox.children).forEach(child => {
|
||||
if (child.getAttribute("hidden") != "true" &&
|
||||
child.getAttribute("id") != "verified") {
|
||||
if (
|
||||
child.getAttribute("hidden") != "true" &&
|
||||
child.getAttribute("id") != "verified"
|
||||
) {
|
||||
determinedUsages.push(win.document.l10n.getAttributes(child));
|
||||
}
|
||||
});
|
||||
|
|
@ -219,16 +256,24 @@ function getError(win) {
|
|||
* An array of object with l10n ids of expected usage descriptions.
|
||||
*/
|
||||
function checkUsages(win, usagesL10nIds) {
|
||||
Assert.deepEqual(getError(win),
|
||||
{ id: "cert-verified", args: null },
|
||||
"should have successful verification message");
|
||||
Assert.deepEqual(
|
||||
getError(win),
|
||||
{ id: "cert-verified", args: null },
|
||||
"should have successful verification message"
|
||||
);
|
||||
let determinedUsages = getUsages(win);
|
||||
usagesL10nIds.sort(compareL10Ids);
|
||||
Assert.deepEqual(determinedUsages.length, usagesL10nIds.length,
|
||||
"number of usages as determined by cert viewer should be equal");
|
||||
Assert.deepEqual(
|
||||
determinedUsages.length,
|
||||
usagesL10nIds.length,
|
||||
"number of usages as determined by cert viewer should be equal"
|
||||
);
|
||||
while (usagesL10nIds.length > 0) {
|
||||
Assert.deepEqual(determinedUsages.pop(), usagesL10nIds.pop(),
|
||||
"usages as determined by cert viewer should be equal");
|
||||
Assert.deepEqual(
|
||||
determinedUsages.pop(),
|
||||
usagesL10nIds.pop(),
|
||||
"usages as determined by cert viewer should be equal"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,10 +288,16 @@ function checkUsages(win, usagesL10nIds) {
|
|||
*/
|
||||
function checkError(win, errorL10nId) {
|
||||
let determinedUsages = getUsages(win);
|
||||
Assert.equal(determinedUsages.length, 0,
|
||||
"should not have any successful usages in error case");
|
||||
Assert.deepEqual(getError(win), errorL10nId,
|
||||
"determined error should be the same as expected error");
|
||||
Assert.equal(
|
||||
determinedUsages.length,
|
||||
0,
|
||||
"should not have any successful usages in error case"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
getError(win),
|
||||
errorL10nId,
|
||||
"determined error should be the same as expected error"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -262,11 +313,17 @@ function checkError(win, errorL10nId) {
|
|||
function checkDetailsPane(win, names) {
|
||||
let tree = win.document.getElementById("treesetDump");
|
||||
let nodes = tree.querySelectorAll("treecell");
|
||||
Assert.equal(nodes.length, names.length,
|
||||
"details pane: should have the expected number of cert names");
|
||||
Assert.equal(
|
||||
nodes.length,
|
||||
names.length,
|
||||
"details pane: should have the expected number of cert names"
|
||||
);
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
Assert.equal(nodes[i].getAttribute("label"), names[i],
|
||||
"details pain: should have expected cert name");
|
||||
Assert.equal(
|
||||
nodes[i].getAttribute("label"),
|
||||
names[i],
|
||||
"details pain: should have expected cert name"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,4 +344,3 @@ function compareL10Ids(ida, idb) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ function test() {
|
|||
|
||||
// This test relies on the test timing out in order to indicate failure so
|
||||
// let's add a dummy pass.
|
||||
ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
|
||||
ok(
|
||||
true,
|
||||
"Each test requires at least one pass, fail or todo so here is a pass."
|
||||
);
|
||||
|
||||
gBugWindow = window.openDialog("chrome://pippki/content/certManager.xul");
|
||||
gBugWindow.addEventListener("load", onLoad);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
// authentication. Also tests that nsIClientAuthDialogs.chooseCertificate
|
||||
// is called at the appropriate times and with the correct arguments.
|
||||
|
||||
const { MockRegistrar } =
|
||||
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
|
||||
const { MockRegistrar } = ChromeUtils.import(
|
||||
"resource://testing-common/MockRegistrar.jsm"
|
||||
);
|
||||
|
||||
const DialogState = {
|
||||
// Assert that chooseCertificate() is never called.
|
||||
|
|
@ -53,25 +54,47 @@ const gClientAuthDialogs = {
|
|||
this._chooseCertificateCalled = value;
|
||||
},
|
||||
|
||||
chooseCertificate(ctx, hostname, port, organization, issuerOrg, certList,
|
||||
selectedIndex) {
|
||||
chooseCertificate(
|
||||
ctx,
|
||||
hostname,
|
||||
port,
|
||||
organization,
|
||||
issuerOrg,
|
||||
certList,
|
||||
selectedIndex
|
||||
) {
|
||||
this.chooseCertificateCalled = true;
|
||||
Assert.notEqual(this.state, DialogState.ASSERT_NOT_CALLED,
|
||||
"chooseCertificate() should be called only when expected");
|
||||
Assert.notEqual(
|
||||
this.state,
|
||||
DialogState.ASSERT_NOT_CALLED,
|
||||
"chooseCertificate() should be called only when expected"
|
||||
);
|
||||
|
||||
let caud = ctx.QueryInterface(Ci.nsIClientAuthUserDecision);
|
||||
Assert.notEqual(caud, null,
|
||||
"nsIClientAuthUserDecision should be queryable from the " +
|
||||
"given context");
|
||||
Assert.notEqual(
|
||||
caud,
|
||||
null,
|
||||
"nsIClientAuthUserDecision should be queryable from the " +
|
||||
"given context"
|
||||
);
|
||||
caud.rememberClientAuthCertificate = this.rememberClientAuthCertificate;
|
||||
|
||||
Assert.equal(hostname, "requireclientcert.example.com",
|
||||
"Hostname should be 'requireclientcert.example.com'");
|
||||
Assert.equal(
|
||||
hostname,
|
||||
"requireclientcert.example.com",
|
||||
"Hostname should be 'requireclientcert.example.com'"
|
||||
);
|
||||
Assert.equal(port, 443, "Port should be 443");
|
||||
Assert.equal(organization, "",
|
||||
"Server cert Organization should be empty/not present");
|
||||
Assert.equal(issuerOrg, "Mozilla Testing",
|
||||
"Server cert issuer Organization should be 'Mozilla Testing'");
|
||||
Assert.equal(
|
||||
organization,
|
||||
"",
|
||||
"Server cert Organization should be empty/not present"
|
||||
);
|
||||
Assert.equal(
|
||||
issuerOrg,
|
||||
"Mozilla Testing",
|
||||
"Server cert issuer Organization should be 'Mozilla Testing'"
|
||||
);
|
||||
|
||||
// For mochitests, only the cert at build/pgo/certs/mochitest.client should
|
||||
// be selectable, so we do some brief checks to confirm this.
|
||||
|
|
@ -79,8 +102,11 @@ const gClientAuthDialogs = {
|
|||
Assert.equal(certList.length, 1, "Only 1 certificate should be available");
|
||||
let cert = certList.queryElementAt(0, Ci.nsIX509Cert);
|
||||
Assert.notEqual(cert, null, "Cert list should contain an nsIX509Cert");
|
||||
Assert.equal(cert.commonName, "Mochitest client",
|
||||
"Cert CN should be 'Mochitest client'");
|
||||
Assert.equal(
|
||||
cert.commonName,
|
||||
"Mochitest client",
|
||||
"Cert CN should be 'Mochitest client'"
|
||||
);
|
||||
|
||||
if (this.state == DialogState.RETURN_CERT_SELECTED) {
|
||||
selectedIndex.value = 0;
|
||||
|
|
@ -93,9 +119,10 @@ const gClientAuthDialogs = {
|
|||
};
|
||||
|
||||
add_task(async function setup() {
|
||||
let clientAuthDialogsCID =
|
||||
MockRegistrar.register("@mozilla.org/nsClientAuthDialogs;1",
|
||||
gClientAuthDialogs);
|
||||
let clientAuthDialogsCID = MockRegistrar.register(
|
||||
"@mozilla.org/nsClientAuthDialogs;1",
|
||||
gClientAuthDialogs
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(clientAuthDialogsCID);
|
||||
});
|
||||
|
|
@ -115,14 +142,16 @@ add_task(async function setup() {
|
|||
*/
|
||||
async function testHelper(prefValue, expectedURL, options = undefined) {
|
||||
gClientAuthDialogs.chooseCertificateCalled = false;
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["security.default_personal_cert", prefValue],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["security.default_personal_cert", prefValue]],
|
||||
});
|
||||
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow(options);
|
||||
|
||||
await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser,
|
||||
"https://requireclientcert.example.com:443");
|
||||
await BrowserTestUtils.loadURI(
|
||||
win.gBrowser.selectedBrowser,
|
||||
"https://requireclientcert.example.com:443"
|
||||
);
|
||||
|
||||
// |loadedURL| will be a string URL if browserLoaded() wins the race, or
|
||||
// |undefined| if waitForErrorPage() wins the race.
|
||||
|
|
@ -131,9 +160,11 @@ async function testHelper(prefValue, expectedURL, options = undefined) {
|
|||
BrowserTestUtils.waitForErrorPage(win.gBrowser.selectedBrowser),
|
||||
]);
|
||||
Assert.equal(expectedURL, loadedURL, "Expected and actual URLs should match");
|
||||
Assert.equal(gClientAuthDialogs.chooseCertificateCalled,
|
||||
prefValue == "Ask Every Time",
|
||||
"chooseCertificate should have been called if we were expecting it to be called");
|
||||
Assert.equal(
|
||||
gClientAuthDialogs.chooseCertificateCalled,
|
||||
prefValue == "Ask Every Time",
|
||||
"chooseCertificate should have been called if we were expecting it to be called"
|
||||
);
|
||||
|
||||
await win.close();
|
||||
|
||||
|
|
@ -147,7 +178,10 @@ async function testHelper(prefValue, expectedURL, options = undefined) {
|
|||
// and that nsIClientAuthDialogs.chooseCertificate() is never called.
|
||||
add_task(async function testCertChosenAutomatically() {
|
||||
gClientAuthDialogs.state = DialogState.ASSERT_NOT_CALLED;
|
||||
await testHelper("Select Automatically", "https://requireclientcert.example.com/");
|
||||
await testHelper(
|
||||
"Select Automatically",
|
||||
"https://requireclientcert.example.com/"
|
||||
);
|
||||
// This clears all saved client auth certificate state so we don't influence
|
||||
// subsequent tests.
|
||||
sdr.logoutAndTeardown();
|
||||
|
|
@ -179,8 +213,12 @@ add_task(async function testCertChosenByUser() {
|
|||
add_task(async function testClearPrivateBrowsingState() {
|
||||
gClientAuthDialogs.rememberClientAuthCertificate = true;
|
||||
gClientAuthDialogs.state = DialogState.RETURN_CERT_SELECTED;
|
||||
await testHelper("Ask Every Time", "https://requireclientcert.example.com/", {private: true});
|
||||
await testHelper("Ask Every Time", "https://requireclientcert.example.com/", {private: true});
|
||||
await testHelper("Ask Every Time", "https://requireclientcert.example.com/", {
|
||||
private: true,
|
||||
});
|
||||
await testHelper("Ask Every Time", "https://requireclientcert.example.com/", {
|
||||
private: true,
|
||||
});
|
||||
await testHelper("Ask Every Time", "https://requireclientcert.example.com/");
|
||||
// NB: we don't `sdr.logoutAndTeardown()` in between the two calls to
|
||||
// `testHelper` because that would clear all client auth certificate state and
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ const TEST_ORG = "Test Org";
|
|||
const TEST_ISSUER_ORG = "Test Issuer Org";
|
||||
const TEST_PORT = 123;
|
||||
|
||||
var certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
/**
|
||||
* Test certificate (i.e. build/pgo/certs/mochitest.client).
|
||||
* @type nsIX509Cert
|
||||
|
|
@ -33,15 +34,28 @@ function openClientAuthDialog(cert) {
|
|||
let certList = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
certList.appendElement(cert);
|
||||
|
||||
let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
|
||||
.createInstance(Ci.nsIWritablePropertyBag2);
|
||||
let win = window.openDialog("chrome://pippki/content/clientauthask.xul", "",
|
||||
"", TEST_HOSTNAME, TEST_ORG, TEST_ISSUER_ORG,
|
||||
TEST_PORT, certList, returnVals);
|
||||
let returnVals = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
||||
Ci.nsIWritablePropertyBag2
|
||||
);
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/clientauthask.xul",
|
||||
"",
|
||||
"",
|
||||
TEST_HOSTNAME,
|
||||
TEST_ORG,
|
||||
TEST_ISSUER_ORG,
|
||||
TEST_PORT,
|
||||
certList,
|
||||
returnVals
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => resolve([win, returnVals]));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => resolve([win, returnVals]));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -56,25 +70,65 @@ function openClientAuthDialog(cert) {
|
|||
* The notAfterLocalTime attribute of mochitest.client.
|
||||
*/
|
||||
function checkDialogContents(win, notBefore, notAfter) {
|
||||
is(win.document.getElementById("hostname").textContent, `${TEST_HOSTNAME}:${TEST_PORT}`,
|
||||
"Actual and expected hostname and port should be equal");
|
||||
is(win.document.getElementById("organization").textContent, `Organization: “${TEST_ORG}”`,
|
||||
"Actual and expected organization should be equal");
|
||||
is(win.document.getElementById("issuer").textContent, `Issued Under: “${TEST_ISSUER_ORG}”`,
|
||||
"Actual and expected issuer organization should be equal");
|
||||
is(
|
||||
win.document.getElementById("hostname").textContent,
|
||||
`${TEST_HOSTNAME}:${TEST_PORT}`,
|
||||
"Actual and expected hostname and port should be equal"
|
||||
);
|
||||
is(
|
||||
win.document.getElementById("organization").textContent,
|
||||
`Organization: “${TEST_ORG}”`,
|
||||
"Actual and expected organization should be equal"
|
||||
);
|
||||
is(
|
||||
win.document.getElementById("issuer").textContent,
|
||||
`Issued Under: “${TEST_ISSUER_ORG}”`,
|
||||
"Actual and expected issuer organization should be equal"
|
||||
);
|
||||
|
||||
is(win.document.getElementById("nicknames").label, "Mochitest client [03]",
|
||||
"Actual and expected selected cert nickname and serial should be equal");
|
||||
is(win.document.getElementById("nicknames").itemCount, 1, "correct number of items");
|
||||
is(
|
||||
win.document.getElementById("nicknames").label,
|
||||
"Mochitest client [03]",
|
||||
"Actual and expected selected cert nickname and serial should be equal"
|
||||
);
|
||||
is(
|
||||
win.document.getElementById("nicknames").itemCount,
|
||||
1,
|
||||
"correct number of items"
|
||||
);
|
||||
|
||||
let [subject, serialNum, validity, issuer, tokenName] =
|
||||
win.document.getElementById("details").value.split("\n");
|
||||
is(subject, "Issued to: CN=Mochitest client", "Actual and expected subject should be equal");
|
||||
is(serialNum, "Serial number: 03", "Actual and expected serial number should be equal");
|
||||
is(validity, `Valid from ${notBefore} to ${notAfter}`, "Actual and expected validity should be equal");
|
||||
is(issuer, "Issued by: OU=Profile Guided Optimization,O=Mozilla Testing,CN=Temporary Certificate Authority",
|
||||
"Actual and expected issuer should be equal");
|
||||
is(tokenName, "Stored on: Software Security Device", "Actual and expected token name should be equal");
|
||||
let [
|
||||
subject,
|
||||
serialNum,
|
||||
validity,
|
||||
issuer,
|
||||
tokenName,
|
||||
] = win.document.getElementById("details").value.split("\n");
|
||||
is(
|
||||
subject,
|
||||
"Issued to: CN=Mochitest client",
|
||||
"Actual and expected subject should be equal"
|
||||
);
|
||||
is(
|
||||
serialNum,
|
||||
"Serial number: 03",
|
||||
"Actual and expected serial number should be equal"
|
||||
);
|
||||
is(
|
||||
validity,
|
||||
`Valid from ${notBefore} to ${notAfter}`,
|
||||
"Actual and expected validity should be equal"
|
||||
);
|
||||
is(
|
||||
issuer,
|
||||
"Issued by: OU=Profile Guided Optimization,O=Mozilla Testing,CN=Temporary Certificate Authority",
|
||||
"Actual and expected issuer should be equal"
|
||||
);
|
||||
is(
|
||||
tokenName,
|
||||
"Stored on: Software Security Device",
|
||||
"Actual and expected token name should be equal"
|
||||
);
|
||||
}
|
||||
|
||||
function findCertByCommonName(commonName) {
|
||||
|
|
@ -95,8 +149,11 @@ add_task(async function setup() {
|
|||
// provided cert.
|
||||
add_task(async function testContents() {
|
||||
let [win] = await openClientAuthDialog(cert);
|
||||
checkDialogContents(win, cert.validity.notBeforeLocalTime,
|
||||
cert.validity.notAfterLocalTime);
|
||||
checkDialogContents(
|
||||
win,
|
||||
cert.validity.notBeforeLocalTime,
|
||||
cert.validity.notAfterLocalTime
|
||||
);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
|
|
@ -108,10 +165,19 @@ add_task(async function testAcceptDialogReturnValues() {
|
|||
win.document.getElementById("certAuthAsk").acceptDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
ok(retVals.get("certChosen"), "Return value should signal user chose a certificate");
|
||||
is(retVals.get("selectedIndex"), 0, "0 should be returned as the selected index");
|
||||
ok(retVals.get("rememberSelection"),
|
||||
"Return value should signal 'Remember this decision' checkbox was checked");
|
||||
ok(
|
||||
retVals.get("certChosen"),
|
||||
"Return value should signal user chose a certificate"
|
||||
);
|
||||
is(
|
||||
retVals.get("selectedIndex"),
|
||||
0,
|
||||
"0 should be returned as the selected index"
|
||||
);
|
||||
ok(
|
||||
retVals.get("rememberSelection"),
|
||||
"Return value should signal 'Remember this decision' checkbox was checked"
|
||||
);
|
||||
});
|
||||
|
||||
// Test that the right values are returned when the dialog is canceled.
|
||||
|
|
@ -122,8 +188,12 @@ add_task(async function testCancelDialogReturnValues() {
|
|||
win.document.getElementById("certAuthAsk").cancelDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
ok(!retVals.get("certChosen"),
|
||||
"Return value should signal user did not choose a certificate");
|
||||
ok(!retVals.get("rememberSelection"),
|
||||
"Return value should signal 'Remember this decision' checkbox was unchecked");
|
||||
ok(
|
||||
!retVals.get("certChosen"),
|
||||
"Return value should signal user did not choose a certificate"
|
||||
);
|
||||
ok(
|
||||
!retVals.get("rememberSelection"),
|
||||
"Return value should signal 'Remember this decision' checkbox was unchecked"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,24 +35,36 @@ const FAKE_HOST_PORT = "Fake host and port";
|
|||
* @type TestCase[]
|
||||
*/
|
||||
const TEST_CASES = [
|
||||
{ certFilename: null,
|
||||
{
|
||||
certFilename: null,
|
||||
expectedDisplayString: FAKE_HOST_PORT,
|
||||
expectedSerialNumber: null},
|
||||
{ certFilename: "has-cn.pem",
|
||||
expectedSerialNumber: null,
|
||||
},
|
||||
{
|
||||
certFilename: "has-cn.pem",
|
||||
expectedDisplayString: "Foo",
|
||||
expectedSerialNumber: null},
|
||||
{ certFilename: "has-ou.pem",
|
||||
expectedSerialNumber: null,
|
||||
},
|
||||
{
|
||||
certFilename: "has-ou.pem",
|
||||
expectedDisplayString: "Bar",
|
||||
expectedSerialNumber: null},
|
||||
{ certFilename: "has-o.pem",
|
||||
expectedSerialNumber: null,
|
||||
},
|
||||
{
|
||||
certFilename: "has-o.pem",
|
||||
expectedDisplayString: "Baz",
|
||||
expectedSerialNumber: null},
|
||||
{ certFilename: "has-non-empty-subject.pem",
|
||||
expectedSerialNumber: null,
|
||||
},
|
||||
{
|
||||
certFilename: "has-non-empty-subject.pem",
|
||||
expectedDisplayString: "C=US",
|
||||
expectedSerialNumber: null},
|
||||
{ certFilename: "has-empty-subject.pem",
|
||||
expectedSerialNumber: null,
|
||||
},
|
||||
{
|
||||
certFilename: "has-empty-subject.pem",
|
||||
expectedDisplayString: "Certificate with serial number: 0A",
|
||||
expectedSerialNumber: "0A"},
|
||||
expectedSerialNumber: "0A",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -70,12 +82,22 @@ function openDeleteCertConfirmDialog(tabID) {
|
|||
let retVals = {
|
||||
deleteConfirmed: false,
|
||||
};
|
||||
let win = window.openDialog("chrome://pippki/content/deletecert.xul", "", "",
|
||||
tabID, gCertArray, retVals);
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/deletecert.xul",
|
||||
"",
|
||||
"",
|
||||
tabID,
|
||||
gCertArray,
|
||||
retVals
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => resolve([win, retVals]));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => resolve([win, retVals]));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -106,35 +128,57 @@ add_task(async function setup() {
|
|||
* @param {String} expectedImpactL10nId
|
||||
* The l10n id of impact the dialog expected to show.
|
||||
*/
|
||||
async function testHelper(tabID, expectedTitleL10nId, expectedConfirmL10nId, expectedImpactL10nId) {
|
||||
async function testHelper(
|
||||
tabID,
|
||||
expectedTitleL10nId,
|
||||
expectedConfirmL10nId,
|
||||
expectedImpactL10nId
|
||||
) {
|
||||
let [win] = await openDeleteCertConfirmDialog(tabID);
|
||||
let certList = win.document.getElementById("certlist");
|
||||
|
||||
Assert.deepEqual(win.document.l10n.getAttributes(win.document.documentElement), expectedTitleL10nId,
|
||||
`Actual and expected titles should match for ${tabID}`);
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(win.document.documentElement),
|
||||
expectedTitleL10nId,
|
||||
`Actual and expected titles should match for ${tabID}`
|
||||
);
|
||||
let confirm = win.document.getElementById("confirm");
|
||||
Assert.deepEqual(win.document.l10n.getAttributes(confirm),
|
||||
expectedConfirmL10nId,
|
||||
`Actual and expected confirm message should match for ${tabID}`);
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(confirm),
|
||||
expectedConfirmL10nId,
|
||||
`Actual and expected confirm message should match for ${tabID}`
|
||||
);
|
||||
let impact = win.document.getElementById("impact");
|
||||
Assert.deepEqual(win.document.l10n.getAttributes(impact),
|
||||
expectedImpactL10nId,
|
||||
`Actual and expected impact should match for ${tabID}`);
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(impact),
|
||||
expectedImpactL10nId,
|
||||
`Actual and expected impact should match for ${tabID}`
|
||||
);
|
||||
|
||||
Assert.equal(certList.itemCount, TEST_CASES.length,
|
||||
`No. of certs displayed should match for ${tabID}`);
|
||||
Assert.equal(
|
||||
certList.itemCount,
|
||||
TEST_CASES.length,
|
||||
`No. of certs displayed should match for ${tabID}`
|
||||
);
|
||||
for (let i = 0; i < certList.itemCount; i++) {
|
||||
let item = certList.getItemAtIndex(i);
|
||||
if (TEST_CASES[i].expectedSerialNumber == null) {
|
||||
Assert.equal(item.label,
|
||||
TEST_CASES[i].expectedDisplayString,
|
||||
"Actual and expected display string should match for " +
|
||||
`index ${i} for ${tabID}`);
|
||||
Assert.equal(
|
||||
item.label,
|
||||
TEST_CASES[i].expectedDisplayString,
|
||||
"Actual and expected display string should match for " +
|
||||
`index ${i} for ${tabID}`
|
||||
);
|
||||
} else {
|
||||
Assert.deepEqual(win.document.l10n.getAttributes(item.children[0]),
|
||||
{id: "cert-with-serial", args: { serialNumber: TEST_CASES[i].expectedSerialNumber }},
|
||||
"Actual and expected display string should match for " +
|
||||
`index ${i} for ${tabID}`);
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(item.children[0]),
|
||||
{
|
||||
id: "cert-with-serial",
|
||||
args: { serialNumber: TEST_CASES[i].expectedSerialNumber },
|
||||
},
|
||||
"Actual and expected display string should match for " +
|
||||
`index ${i} for ${tabID}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,60 +187,84 @@ async function testHelper(tabID, expectedTitleL10nId, expectedConfirmL10nId, exp
|
|||
|
||||
// Test deleting certs from the "Your Certificates" tab.
|
||||
add_task(async function testDeletePersonalCerts() {
|
||||
const expectedTitleL10nId = {id: "delete-user-cert-title", args: null};
|
||||
const expectedConfirmL10nId = {id: "delete-user-cert-confirm", args: null};
|
||||
const expectedImpactL10nId = {id: "delete-user-cert-impact", args: null};
|
||||
await testHelper("mine_tab", expectedTitleL10nId, expectedConfirmL10nId,
|
||||
expectedImpactL10nId);
|
||||
const expectedTitleL10nId = { id: "delete-user-cert-title", args: null };
|
||||
const expectedConfirmL10nId = { id: "delete-user-cert-confirm", args: null };
|
||||
const expectedImpactL10nId = { id: "delete-user-cert-impact", args: null };
|
||||
await testHelper(
|
||||
"mine_tab",
|
||||
expectedTitleL10nId,
|
||||
expectedConfirmL10nId,
|
||||
expectedImpactL10nId
|
||||
);
|
||||
});
|
||||
|
||||
// Test deleting certs from the "People" tab.
|
||||
add_task(async function testDeleteOtherPeopleCerts() {
|
||||
const expectedTitleL10nId = {id: "delete-email-cert-title", args: null};
|
||||
const expectedTitleL10nId = { id: "delete-email-cert-title", args: null };
|
||||
// ’ doesn't seem to work when embedded in the following literals, which is
|
||||
// why escape codes are used instead.
|
||||
const expectedConfirmL10nId = {id: "delete-email-cert-confirm", args: null};
|
||||
const expectedImpactL10nId = {id: "delete-email-cert-impact", args: null};
|
||||
await testHelper("others_tab", expectedTitleL10nId, expectedConfirmL10nId,
|
||||
expectedImpactL10nId);
|
||||
const expectedConfirmL10nId = { id: "delete-email-cert-confirm", args: null };
|
||||
const expectedImpactL10nId = { id: "delete-email-cert-impact", args: null };
|
||||
await testHelper(
|
||||
"others_tab",
|
||||
expectedTitleL10nId,
|
||||
expectedConfirmL10nId,
|
||||
expectedImpactL10nId
|
||||
);
|
||||
});
|
||||
|
||||
// Test deleting certs from the "Servers" tab.
|
||||
add_task(async function testDeleteServerCerts() {
|
||||
const expectedTitleL10nId = {id: "delete-ssl-cert-title", args: null};
|
||||
const expectedConfirmL10nId = {id: "delete-ssl-cert-confirm", args: null};
|
||||
const expectedImpactL10nId = {id: "delete-ssl-cert-impact", args: null};
|
||||
await testHelper("websites_tab", expectedTitleL10nId, expectedConfirmL10nId,
|
||||
expectedImpactL10nId);
|
||||
const expectedTitleL10nId = { id: "delete-ssl-cert-title", args: null };
|
||||
const expectedConfirmL10nId = { id: "delete-ssl-cert-confirm", args: null };
|
||||
const expectedImpactL10nId = { id: "delete-ssl-cert-impact", args: null };
|
||||
await testHelper(
|
||||
"websites_tab",
|
||||
expectedTitleL10nId,
|
||||
expectedConfirmL10nId,
|
||||
expectedImpactL10nId
|
||||
);
|
||||
});
|
||||
|
||||
// Test deleting certs from the "Authorities" tab.
|
||||
add_task(async function testDeleteCACerts() {
|
||||
const expectedTitleL10nId = {id: "delete-ca-cert-title", args: null};
|
||||
const expectedConfirmL10nId = {id: "delete-ca-cert-confirm", args: null};
|
||||
const expectedImpactL10nId = {id: "delete-ca-cert-impact", args: null};
|
||||
await testHelper("ca_tab", expectedTitleL10nId, expectedConfirmL10nId,
|
||||
expectedImpactL10nId);
|
||||
const expectedTitleL10nId = { id: "delete-ca-cert-title", args: null };
|
||||
const expectedConfirmL10nId = { id: "delete-ca-cert-confirm", args: null };
|
||||
const expectedImpactL10nId = { id: "delete-ca-cert-impact", args: null };
|
||||
await testHelper(
|
||||
"ca_tab",
|
||||
expectedTitleL10nId,
|
||||
expectedConfirmL10nId,
|
||||
expectedImpactL10nId
|
||||
);
|
||||
});
|
||||
|
||||
// Test that the right values are returned when the dialog is accepted.
|
||||
add_task(async function testAcceptDialogReturnValues() {
|
||||
let [win, retVals] = await openDeleteCertConfirmDialog("ca_tab" /* arbitrary */);
|
||||
let [win, retVals] = await openDeleteCertConfirmDialog(
|
||||
"ca_tab" /* arbitrary */
|
||||
);
|
||||
info("Accepting dialog");
|
||||
win.document.getElementById("deleteCertificate").acceptDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(retVals.deleteConfirmed,
|
||||
"Return value should signal user accepted");
|
||||
Assert.ok(
|
||||
retVals.deleteConfirmed,
|
||||
"Return value should signal user accepted"
|
||||
);
|
||||
});
|
||||
|
||||
// Test that the right values are returned when the dialog is canceled.
|
||||
add_task(async function testCancelDialogReturnValues() {
|
||||
let [win, retVals] = await openDeleteCertConfirmDialog("ca_tab" /* arbitrary */);
|
||||
let [win, retVals] = await openDeleteCertConfirmDialog(
|
||||
"ca_tab" /* arbitrary */
|
||||
);
|
||||
info("Canceling dialog");
|
||||
win.document.getElementById("deleteCertificate").cancelDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(!retVals.deleteConfirmed,
|
||||
"Return value should signal user did not accept");
|
||||
Assert.ok(
|
||||
!retVals.deleteConfirmed,
|
||||
"Return value should signal user did not accept"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
// Tests that the cert download/import UI correctly identifies the cert being
|
||||
// downloaded, and allows the trust of the cert to be specified.
|
||||
|
||||
const { MockRegistrar } =
|
||||
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
|
||||
const { MockRegistrar } = ChromeUtils.import(
|
||||
"resource://testing-common/MockRegistrar.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* @typedef {TestCase}
|
||||
|
|
@ -24,12 +25,12 @@ const { MockRegistrar } =
|
|||
* @type TestCase[]
|
||||
*/
|
||||
const TEST_CASES = [
|
||||
{ certFilename: "has-cn.pem",
|
||||
expectedDisplayString: "Foo",
|
||||
cert: null },
|
||||
{ certFilename: "has-empty-subject.pem",
|
||||
{ certFilename: "has-cn.pem", expectedDisplayString: "Foo", cert: null },
|
||||
{
|
||||
certFilename: "has-empty-subject.pem",
|
||||
expectedDisplayString: "Certificate Authority (unnamed)",
|
||||
cert: null },
|
||||
cert: null,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -44,22 +45,35 @@ const TEST_CASES = [
|
|||
* 2. The return value nsIWritablePropertyBag2 passed to the dialog.
|
||||
*/
|
||||
function openCertDownloadDialog(cert) {
|
||||
let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
|
||||
.createInstance(Ci.nsIWritablePropertyBag2);
|
||||
let win = window.openDialog("chrome://pippki/content/downloadcert.xul", "",
|
||||
"", cert, returnVals);
|
||||
let returnVals = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
||||
Ci.nsIWritablePropertyBag2
|
||||
);
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/downloadcert.xul",
|
||||
"",
|
||||
"",
|
||||
cert,
|
||||
returnVals
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => resolve([win, returnVals]));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => resolve([win, returnVals]));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
for (let testCase of TEST_CASES) {
|
||||
testCase.cert = await readCertificate(testCase.certFilename, ",,");
|
||||
Assert.notEqual(testCase.cert, null,
|
||||
`'${testCase.certFilename}' should have been read`);
|
||||
Assert.notEqual(
|
||||
testCase.cert,
|
||||
null,
|
||||
`'${testCase.certFilename}' should have been read`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -71,10 +85,12 @@ add_task(async function testTrustHeaderAndViewCertButton() {
|
|||
let expectedTrustHeaderString =
|
||||
`Do you want to trust \u201C${testCase.expectedDisplayString}\u201D ` +
|
||||
"for the following purposes?";
|
||||
Assert.equal(win.document.getElementById("trustHeader").textContent,
|
||||
expectedTrustHeaderString,
|
||||
"Actual and expected trust header text should match for " +
|
||||
`${testCase.certFilename}`);
|
||||
Assert.equal(
|
||||
win.document.getElementById("trustHeader").textContent,
|
||||
expectedTrustHeaderString,
|
||||
"Actual and expected trust header text should match for " +
|
||||
`${testCase.certFilename}`
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
|
|
@ -89,12 +105,18 @@ add_task(async function testAcceptDialogReturnValues() {
|
|||
win.document.getElementById("download_cert").acceptDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(retVals.get("importConfirmed"),
|
||||
"Return value should signal user chose to import the cert");
|
||||
Assert.ok(retVals.get("trustForSSL"),
|
||||
"Return value should signal SSL trust checkbox was checked");
|
||||
Assert.ok(!retVals.get("trustForEmail"),
|
||||
"Return value should signal E-mail trust checkbox was unchecked");
|
||||
Assert.ok(
|
||||
retVals.get("importConfirmed"),
|
||||
"Return value should signal user chose to import the cert"
|
||||
);
|
||||
Assert.ok(
|
||||
retVals.get("trustForSSL"),
|
||||
"Return value should signal SSL trust checkbox was checked"
|
||||
);
|
||||
Assert.ok(
|
||||
!retVals.get("trustForEmail"),
|
||||
"Return value should signal E-mail trust checkbox was unchecked"
|
||||
);
|
||||
});
|
||||
|
||||
// Test that the right values are returned when the dialog is canceled.
|
||||
|
|
@ -104,6 +126,8 @@ add_task(async function testCancelDialogReturnValues() {
|
|||
win.document.getElementById("download_cert").cancelDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(!retVals.get("importConfirmed"),
|
||||
"Return value should signal user chose not to import the cert");
|
||||
Assert.ok(
|
||||
!retVals.get("importConfirmed"),
|
||||
"Return value should signal user chose not to import the cert"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
// reflects trust in the cert DB, and correctly updates trust in the cert DB
|
||||
// when requested.
|
||||
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
/**
|
||||
* The cert we're editing the trust of.
|
||||
|
|
@ -23,24 +24,42 @@ var gCert;
|
|||
* the window of the opened dialog.
|
||||
*/
|
||||
function openEditCertTrustDialog() {
|
||||
let win = window.openDialog("chrome://pippki/content/editcacert.xul", "", "",
|
||||
gCert);
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/editcacert.xul",
|
||||
"",
|
||||
"",
|
||||
gCert
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => resolve(win));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => resolve(win));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
// Initially trust ca.pem for SSL but not e-mail.
|
||||
gCert = await readCertificate("ca.pem", "CT,,");
|
||||
Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL),
|
||||
"Sanity check: ca.pem should be trusted for SSL");
|
||||
Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL),
|
||||
"Sanity check: ca.pem should not be trusted for e-mail");
|
||||
Assert.ok(
|
||||
gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL
|
||||
),
|
||||
"Sanity check: ca.pem should be trusted for SSL"
|
||||
);
|
||||
Assert.ok(
|
||||
!gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
),
|
||||
"Sanity check: ca.pem should not be trusted for e-mail"
|
||||
);
|
||||
});
|
||||
|
||||
// Tests the following:
|
||||
|
|
@ -52,10 +71,11 @@ add_task(async function testAcceptDialog() {
|
|||
|
||||
let sslCheckbox = win.document.getElementById("trustSSL");
|
||||
let emailCheckbox = win.document.getElementById("trustEmail");
|
||||
Assert.ok(sslCheckbox.checked,
|
||||
"Cert should be trusted for SSL in UI");
|
||||
Assert.ok(!emailCheckbox.checked,
|
||||
"Cert should not be trusted for e-mail in UI");
|
||||
Assert.ok(sslCheckbox.checked, "Cert should be trusted for SSL in UI");
|
||||
Assert.ok(
|
||||
!emailCheckbox.checked,
|
||||
"Cert should not be trusted for e-mail in UI"
|
||||
);
|
||||
|
||||
sslCheckbox.checked = false;
|
||||
emailCheckbox.checked = true;
|
||||
|
|
@ -64,12 +84,22 @@ add_task(async function testAcceptDialog() {
|
|||
win.document.getElementById("editCaCert").acceptDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL),
|
||||
"Cert should no longer be trusted for SSL");
|
||||
Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL),
|
||||
"Cert should now be trusted for e-mail");
|
||||
Assert.ok(
|
||||
!gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL
|
||||
),
|
||||
"Cert should no longer be trusted for SSL"
|
||||
);
|
||||
Assert.ok(
|
||||
gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
),
|
||||
"Cert should now be trusted for e-mail"
|
||||
);
|
||||
});
|
||||
|
||||
// Tests the following:
|
||||
|
|
@ -81,10 +111,8 @@ add_task(async function testCancelDialog() {
|
|||
|
||||
let sslCheckbox = win.document.getElementById("trustSSL");
|
||||
let emailCheckbox = win.document.getElementById("trustEmail");
|
||||
Assert.ok(!sslCheckbox.checked,
|
||||
"Cert should not be trusted for SSL in UI");
|
||||
Assert.ok(emailCheckbox.checked,
|
||||
"Cert should be trusted for e-mail in UI");
|
||||
Assert.ok(!sslCheckbox.checked, "Cert should not be trusted for SSL in UI");
|
||||
Assert.ok(emailCheckbox.checked, "Cert should be trusted for e-mail in UI");
|
||||
|
||||
sslCheckbox.checked = true;
|
||||
emailCheckbox.checked = false;
|
||||
|
|
@ -93,10 +121,20 @@ add_task(async function testCancelDialog() {
|
|||
win.document.getElementById("editCaCert").cancelDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL),
|
||||
"Cert should still not be trusted for SSL");
|
||||
Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL),
|
||||
"Cert should still be trusted for e-mail");
|
||||
Assert.ok(
|
||||
!gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL
|
||||
),
|
||||
"Cert should still not be trusted for SSL"
|
||||
);
|
||||
Assert.ok(
|
||||
gCertDB.isCertTrusted(
|
||||
gCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
),
|
||||
"Cert should still be trusted for e-mail"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,34 +24,33 @@
|
|||
* @type TestCase[]
|
||||
*/
|
||||
const TEST_CASES = [
|
||||
{ name: "empty",
|
||||
password1: "",
|
||||
password2: "",
|
||||
strength: "0" },
|
||||
{ name: "match-weak",
|
||||
password1: "foo",
|
||||
password2: "foo",
|
||||
strength: "10" },
|
||||
{ name: "match-medium",
|
||||
{ name: "empty", password1: "", password2: "", strength: "0" },
|
||||
{ name: "match-weak", password1: "foo", password2: "foo", strength: "10" },
|
||||
{
|
||||
name: "match-medium",
|
||||
password1: "foo123",
|
||||
password2: "foo123",
|
||||
strength: "60" },
|
||||
{ name: "match-strong",
|
||||
strength: "60",
|
||||
},
|
||||
{
|
||||
name: "match-strong",
|
||||
password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
|
||||
password2: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
|
||||
strength: "100" },
|
||||
{ name: "mismatch-weak",
|
||||
password1: "foo",
|
||||
password2: "bar",
|
||||
strength: "10" },
|
||||
{ name: "mismatch-medium",
|
||||
strength: "100",
|
||||
},
|
||||
{ name: "mismatch-weak", password1: "foo", password2: "bar", strength: "10" },
|
||||
{
|
||||
name: "mismatch-medium",
|
||||
password1: "foo123",
|
||||
password2: "bar",
|
||||
strength: "60" },
|
||||
{ name: "mismatch-strong",
|
||||
strength: "60",
|
||||
},
|
||||
{
|
||||
name: "mismatch-strong",
|
||||
password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
|
||||
password2: "bar",
|
||||
strength: "100" },
|
||||
strength: "100",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -64,14 +63,23 @@ const TEST_CASES = [
|
|||
* 2. The return value nsIWritablePropertyBag2 passed to the dialog.
|
||||
*/
|
||||
function openSetP12PasswordDialog() {
|
||||
let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
|
||||
.createInstance(Ci.nsIWritablePropertyBag2);
|
||||
let win = window.openDialog("chrome://pippki/content/setp12password.xul", "",
|
||||
"", returnVals);
|
||||
let returnVals = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
||||
Ci.nsIWritablePropertyBag2
|
||||
);
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/setp12password.xul",
|
||||
"",
|
||||
"",
|
||||
returnVals
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => resolve([win, returnVals]));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => resolve([win, returnVals]));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -79,9 +87,11 @@ function openSetP12PasswordDialog() {
|
|||
// focused.
|
||||
add_task(async function testFocus() {
|
||||
let [win] = await openSetP12PasswordDialog();
|
||||
Assert.equal(win.document.activeElement,
|
||||
win.document.getElementById("pw1"),
|
||||
"First password textbox should have focus");
|
||||
Assert.equal(
|
||||
win.document.activeElement,
|
||||
win.document.getElementById("pw1"),
|
||||
"First password textbox should have focus"
|
||||
);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
|
|
@ -101,13 +111,17 @@ add_task(async function testPasswordStrengthAndEquality() {
|
|||
password1Textbox.oninput();
|
||||
password2Textbox.oninput();
|
||||
|
||||
Assert.equal(win.document.documentElement.getButton("accept").disabled,
|
||||
password1Textbox.value != password2Textbox.value,
|
||||
"Actual and expected accept button disable state should " +
|
||||
`match for ${testCase.name}`);
|
||||
Assert.equal(strengthProgressBar.value, testCase.strength,
|
||||
"Actual and expected strength value should match for" +
|
||||
`${testCase.name}`);
|
||||
Assert.equal(
|
||||
win.document.documentElement.getButton("accept").disabled,
|
||||
password1Textbox.value != password2Textbox.value,
|
||||
"Actual and expected accept button disable state should " +
|
||||
`match for ${testCase.name}`
|
||||
);
|
||||
Assert.equal(
|
||||
strengthProgressBar.value,
|
||||
testCase.strength,
|
||||
"Actual and expected strength value should match for" + `${testCase.name}`
|
||||
);
|
||||
}
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
|
@ -123,10 +137,15 @@ add_task(async function testAcceptDialogReturnValues() {
|
|||
win.document.getElementById("setp12password").acceptDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(retVals.get("confirmedPassword"),
|
||||
"Return value should signal user confirmed a password");
|
||||
Assert.equal(retVals.get("password"), password,
|
||||
"Actual and expected password should match");
|
||||
Assert.ok(
|
||||
retVals.get("confirmedPassword"),
|
||||
"Return value should signal user confirmed a password"
|
||||
);
|
||||
Assert.equal(
|
||||
retVals.get("password"),
|
||||
password,
|
||||
"Actual and expected password should match"
|
||||
);
|
||||
});
|
||||
|
||||
// Test that the right values are returned when the dialog is canceled.
|
||||
|
|
@ -136,6 +155,8 @@ add_task(async function testCancelDialogReturnValues() {
|
|||
win.document.getElementById("setp12password").cancelDialog();
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.ok(!retVals.get("confirmedPassword"),
|
||||
"Return value should signal user didn't confirm a password");
|
||||
Assert.ok(
|
||||
!retVals.get("confirmedPassword"),
|
||||
"Return value should signal user didn't confirm a password"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
// Tests the dialog used for loading PKCS #11 modules.
|
||||
|
||||
const { MockRegistrar } =
|
||||
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
|
||||
const { MockRegistrar } = ChromeUtils.import(
|
||||
"resource://testing-common/MockRegistrar.jsm"
|
||||
);
|
||||
|
||||
const gMockPKCS11ModuleDB = {
|
||||
addModuleCallCount: 0,
|
||||
|
|
@ -15,14 +16,22 @@ const gMockPKCS11ModuleDB = {
|
|||
|
||||
addModule(moduleName, libraryFullPath, cryptoMechanismFlags, cipherFlags) {
|
||||
this.addModuleCallCount++;
|
||||
Assert.equal(moduleName, this.expectedModuleName,
|
||||
"addModule: Name given should be what's in the name textbox");
|
||||
Assert.equal(libraryFullPath, this.expectedLibPath,
|
||||
"addModule: Path given should be what's in the path textbox");
|
||||
Assert.equal(cryptoMechanismFlags, 0,
|
||||
"addModule: No crypto mechanism flags should be passed");
|
||||
Assert.equal(cipherFlags, 0,
|
||||
"addModule: No cipher flags should be passed");
|
||||
Assert.equal(
|
||||
moduleName,
|
||||
this.expectedModuleName,
|
||||
"addModule: Name given should be what's in the name textbox"
|
||||
);
|
||||
Assert.equal(
|
||||
libraryFullPath,
|
||||
this.expectedLibPath,
|
||||
"addModule: Path given should be what's in the path textbox"
|
||||
);
|
||||
Assert.equal(
|
||||
cryptoMechanismFlags,
|
||||
0,
|
||||
"addModule: No crypto mechanism flags should be passed"
|
||||
);
|
||||
Assert.equal(cipherFlags, 0, "addModule: No cipher flags should be passed");
|
||||
|
||||
if (this.throwOnAddModule) {
|
||||
throw new Error(`addModule: Throwing exception`);
|
||||
|
|
@ -67,22 +76,30 @@ const gMockPromptService = {
|
|||
|
||||
alert(parent, dialogTitle, text) {
|
||||
this.alertCallCount++;
|
||||
Assert.equal(parent, this.expectedWindow,
|
||||
"alert: Parent should be expected window");
|
||||
Assert.equal(
|
||||
parent,
|
||||
this.expectedWindow,
|
||||
"alert: Parent should be expected window"
|
||||
);
|
||||
Assert.equal(dialogTitle, null, "alert: Title should be null");
|
||||
Assert.equal(text, this.expectedText,
|
||||
"alert: Actual and expected text should match");
|
||||
Assert.equal(
|
||||
text,
|
||||
this.expectedText,
|
||||
"alert: Actual and expected text should match"
|
||||
);
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIPromptService]),
|
||||
};
|
||||
|
||||
var gMockPKCS11CID =
|
||||
MockRegistrar.register("@mozilla.org/security/pkcs11moduledb;1",
|
||||
gMockPKCS11ModuleDB);
|
||||
var gMockPromptServiceCID =
|
||||
MockRegistrar.register("@mozilla.org/embedcomp/prompt-service;1",
|
||||
gMockPromptService);
|
||||
var gMockPKCS11CID = MockRegistrar.register(
|
||||
"@mozilla.org/security/pkcs11moduledb;1",
|
||||
gMockPKCS11ModuleDB
|
||||
);
|
||||
var gMockPromptServiceCID = MockRegistrar.register(
|
||||
"@mozilla.org/embedcomp/prompt-service;1",
|
||||
gMockPromptService
|
||||
);
|
||||
|
||||
var gMockFilePicker = SpecialPowers.MockFilePicker;
|
||||
gMockFilePicker.init(window);
|
||||
|
|
@ -109,11 +126,19 @@ function resetCallCounts() {
|
|||
* the window of the opened dialog.
|
||||
*/
|
||||
function openLoadModuleDialog() {
|
||||
let win = window.openDialog("chrome://pippki/content/load_device.xul", "", "");
|
||||
let win = window.openDialog(
|
||||
"chrome://pippki/content/load_device.xul",
|
||||
"",
|
||||
""
|
||||
);
|
||||
return new Promise(resolve => {
|
||||
win.addEventListener("load", function() {
|
||||
executeSoon(() => resolve(win));
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
executeSoon(() => resolve(win));
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -153,13 +178,19 @@ add_task(async function testBrowseButton() {
|
|||
|
||||
// Test what happens if the file picker is canceled.
|
||||
await browseToTempFile(win, true);
|
||||
Assert.equal(pathBox.value, originalPathBoxValue,
|
||||
"Path shown should be unchanged due to canceled picker");
|
||||
Assert.equal(
|
||||
pathBox.value,
|
||||
originalPathBoxValue,
|
||||
"Path shown should be unchanged due to canceled picker"
|
||||
);
|
||||
|
||||
// Test what happens if the file picker is not canceled.
|
||||
await browseToTempFile(win, false);
|
||||
Assert.equal(pathBox.value, gTempFile.path,
|
||||
"Path shown should be same as the one chosen in the file picker");
|
||||
Assert.equal(
|
||||
pathBox.value,
|
||||
gTempFile.path,
|
||||
"Path shown should be same as the one chosen in the file picker"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -185,10 +216,16 @@ add_task(async function testAddModuleSuccess() {
|
|||
testAddModuleHelper(win, false);
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
|
||||
Assert.equal(gMockPKCS11ModuleDB.addModuleCallCount, 1,
|
||||
"addModule() should have been called once");
|
||||
Assert.equal(gMockPromptService.alertCallCount, 0,
|
||||
"alert() should never have been called");
|
||||
Assert.equal(
|
||||
gMockPKCS11ModuleDB.addModuleCallCount,
|
||||
1,
|
||||
"addModule() should have been called once"
|
||||
);
|
||||
Assert.equal(
|
||||
gMockPromptService.alertCallCount,
|
||||
0,
|
||||
"alert() should never have been called"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function testAddModuleFailure() {
|
||||
|
|
@ -207,10 +244,16 @@ add_task(async function testAddModuleFailure() {
|
|||
// close the window ourselves.
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
Assert.equal(gMockPKCS11ModuleDB.addModuleCallCount, 1,
|
||||
"addModule() should have been called once");
|
||||
Assert.equal(gMockPromptService.alertCallCount, 1,
|
||||
"alert() should have been called once");
|
||||
Assert.equal(
|
||||
gMockPKCS11ModuleDB.addModuleCallCount,
|
||||
1,
|
||||
"addModule() should have been called once"
|
||||
);
|
||||
Assert.equal(
|
||||
gMockPromptService.alertCallCount,
|
||||
1,
|
||||
"alert() should have been called once"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function testCancel() {
|
||||
|
|
@ -220,10 +263,16 @@ add_task(async function testCancel() {
|
|||
info("Canceling dialog");
|
||||
win.document.getElementById("loaddevice").cancelDialog();
|
||||
|
||||
Assert.equal(gMockPKCS11ModuleDB.addModuleCallCount, 0,
|
||||
"addModule() should never have been called");
|
||||
Assert.equal(gMockPromptService.alertCallCount, 0,
|
||||
"alert() should never have been called");
|
||||
Assert.equal(
|
||||
gMockPKCS11ModuleDB.addModuleCallCount,
|
||||
0,
|
||||
"addModule() should never have been called"
|
||||
);
|
||||
Assert.equal(
|
||||
gMockPromptService.alertCallCount,
|
||||
0,
|
||||
"alert() should never have been called"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.windowClosed(win);
|
||||
});
|
||||
|
|
@ -239,9 +288,13 @@ async function testModuleNameHelper(moduleName, acceptButtonShouldBeDisabled) {
|
|||
moduleNameBox.onchange();
|
||||
|
||||
let dialogNode = win.document.querySelector("dialog");
|
||||
Assert.equal(dialogNode.getAttribute("buttondisabledaccept"),
|
||||
acceptButtonShouldBeDisabled ? "true" : "", // it's a string
|
||||
`dialog accept button should ${acceptButtonShouldBeDisabled ? "" : "not "}be disabled`);
|
||||
Assert.equal(
|
||||
dialogNode.getAttribute("buttondisabledaccept"),
|
||||
acceptButtonShouldBeDisabled ? "true" : "", // it's a string
|
||||
`dialog accept button should ${
|
||||
acceptButtonShouldBeDisabled ? "" : "not "
|
||||
}be disabled`
|
||||
);
|
||||
|
||||
return BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
/**
|
||||
* List of certs imported via readCertificate(). Certs in this list are
|
||||
|
|
@ -21,9 +22,10 @@ registerCleanupFunction(() => {
|
|||
|
||||
// This function serves the same purpose as the one defined in head_psm.js.
|
||||
function pemToBase64(pem) {
|
||||
return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
|
||||
.replace(/-----END CERTIFICATE-----/, "")
|
||||
.replace(/[\r\n]/g, "");
|
||||
return pem
|
||||
.replace(/-----BEGIN CERTIFICATE-----/, "")
|
||||
.replace(/-----END CERTIFICATE-----/, "")
|
||||
.replace(/[\r\n]/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -43,15 +45,21 @@ function pemToBase64(pem) {
|
|||
* A promise that will resolve with a handle to the certificate.
|
||||
*/
|
||||
function readCertificate(filename, trustString) {
|
||||
return OS.File.read(getTestFilePath(filename)).then(data => {
|
||||
let decoder = new TextDecoder();
|
||||
let pem = decoder.decode(data);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let base64 = pemToBase64(pem);
|
||||
certdb.addCertFromBase64(base64, trustString);
|
||||
let cert = certdb.constructX509FromBase64(base64);
|
||||
gImportedCerts.push(cert);
|
||||
return cert;
|
||||
}, error => { throw error; });
|
||||
return OS.File.read(getTestFilePath(filename)).then(
|
||||
data => {
|
||||
let decoder = new TextDecoder();
|
||||
let pem = decoder.decode(data);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
let base64 = pemToBase64(pem);
|
||||
certdb.addCertFromBase64(base64, trustString);
|
||||
let cert = certdb.constructX509FromBase64(base64);
|
||||
gImportedCerts.push(cert);
|
||||
return cert;
|
||||
},
|
||||
error => {
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,8 @@
|
|||
document.open();
|
||||
// eslint-disable-next-line no-unsanitized/method
|
||||
document.write("This is insecure XSS script " + document.cookie);
|
||||
isSecurityState("broken", "security broken after document write from unsecure script");
|
||||
isSecurityState(
|
||||
"broken",
|
||||
"security broken after document write from unsecure script"
|
||||
);
|
||||
finish();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ var testCleanUp = null;
|
|||
// Contains mixed active content that needs to load to run the test
|
||||
var hasMixedActiveContent = false;
|
||||
|
||||
|
||||
// Internal variables
|
||||
var _windowCount = 0;
|
||||
|
||||
|
|
@ -51,8 +50,9 @@ window.onload = function onLoad() {
|
|||
} else {
|
||||
window.addEventListener("message", onMessageReceived);
|
||||
|
||||
let secureTestLocation = loadAsInsecure ? "http://example.com"
|
||||
: "https://example.com";
|
||||
let secureTestLocation = loadAsInsecure
|
||||
? "http://example.com"
|
||||
: "https://example.com";
|
||||
secureTestLocation += location.pathname;
|
||||
if (testPage != "") {
|
||||
let array = secureTestLocation.split("/");
|
||||
|
|
@ -64,8 +64,9 @@ window.onload = function onLoad() {
|
|||
|
||||
if (hasMixedActiveContent) {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set": [["security.mixed_content.block_active_content", false]]},
|
||||
null);
|
||||
{ set: [["security.mixed_content.block_active_content", false]] },
|
||||
null
|
||||
);
|
||||
}
|
||||
if (openTwoWindows) {
|
||||
_windowCount = 2;
|
||||
|
|
@ -108,9 +109,11 @@ function postMsg(message) {
|
|||
function finish() {
|
||||
if (history.length == 1 && !bypassNavigationTest) {
|
||||
window.setTimeout(() => {
|
||||
window.location.assign(navigateToInsecure ?
|
||||
"http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html" :
|
||||
"https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html");
|
||||
window.location.assign(
|
||||
navigateToInsecure
|
||||
? "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html"
|
||||
: "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html"
|
||||
);
|
||||
}, 0);
|
||||
} else {
|
||||
postMsg("done");
|
||||
|
|
@ -141,12 +144,14 @@ function isSecurityState(expectedState, message, test) {
|
|||
|
||||
let ui = SpecialPowers.wrap(window).docShell.securityUI;
|
||||
|
||||
let isInsecure = !ui ||
|
||||
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_INSECURE);
|
||||
let isBroken = ui &&
|
||||
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_BROKEN);
|
||||
let isEV = ui &&
|
||||
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
|
||||
let isInsecure =
|
||||
!ui || ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_INSECURE;
|
||||
let isBroken =
|
||||
ui && ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_BROKEN;
|
||||
let isEV =
|
||||
ui &&
|
||||
ui.state &
|
||||
SpecialPowers.Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
|
||||
|
||||
let gotState = "secure";
|
||||
if (isInsecure) {
|
||||
|
|
@ -157,20 +162,35 @@ function isSecurityState(expectedState, message, test) {
|
|||
gotState = "EV";
|
||||
}
|
||||
|
||||
test(gotState == expectedState, (message || "") + ", expected " + expectedState + " got " + gotState);
|
||||
test(
|
||||
gotState == expectedState,
|
||||
(message || "") + ", expected " + expectedState + " got " + gotState
|
||||
);
|
||||
|
||||
switch (expectedState) {
|
||||
case "insecure":
|
||||
test(isInsecure && !isBroken && !isEV, "for 'insecure' excpected flags [1,0,0], " + (message || ""));
|
||||
test(
|
||||
isInsecure && !isBroken && !isEV,
|
||||
"for 'insecure' excpected flags [1,0,0], " + (message || "")
|
||||
);
|
||||
break;
|
||||
case "broken":
|
||||
test(ui && !isInsecure && isBroken && !isEV, "for 'broken' expected flags [0,1,0], " + (message || ""));
|
||||
test(
|
||||
ui && !isInsecure && isBroken && !isEV,
|
||||
"for 'broken' expected flags [0,1,0], " + (message || "")
|
||||
);
|
||||
break;
|
||||
case "secure":
|
||||
test(ui && !isInsecure && !isBroken && !isEV, "for 'secure' expected flags [0,0,0], " + (message || ""));
|
||||
test(
|
||||
ui && !isInsecure && !isBroken && !isEV,
|
||||
"for 'secure' expected flags [0,0,0], " + (message || "")
|
||||
);
|
||||
break;
|
||||
case "EV":
|
||||
test(ui && !isInsecure && !isBroken && isEV, "for 'EV' expected flags [0,0,1], " + (message || ""));
|
||||
test(
|
||||
ui && !isInsecure && !isBroken && isEV,
|
||||
"for 'EV' expected flags [0,0,1], " + (message || "")
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid isSecurityState state");
|
||||
|
|
|
|||
|
|
@ -4,20 +4,26 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
const { AppConstants } =
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
|
||||
const { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
const { FileUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/FileUtils.jsm"
|
||||
);
|
||||
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
const { MockRegistrar } =
|
||||
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
|
||||
const { MockRegistrar } = ChromeUtils.import(
|
||||
"resource://testing-common/MockRegistrar.jsm"
|
||||
);
|
||||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const { Promise } = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"]
|
||||
.getService(Ci.nsIDebug2).isDebugBuild;
|
||||
const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2)
|
||||
.isDebugBuild;
|
||||
|
||||
// The test EV roots are only enabled in debug builds as a security measure.
|
||||
const gEVExpected = isDebugBuild;
|
||||
|
|
@ -34,61 +40,67 @@ const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
|
|||
const PRErrorCodeSuccess = 0;
|
||||
|
||||
// Sort in numerical order
|
||||
const SEC_ERROR_INVALID_TIME = SEC_ERROR_BASE + 8;
|
||||
const SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9;
|
||||
const SEC_ERROR_BAD_SIGNATURE = SEC_ERROR_BASE + 10;
|
||||
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
|
||||
const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12;
|
||||
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
|
||||
const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
|
||||
const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21;
|
||||
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
|
||||
const SEC_ERROR_CA_CERT_INVALID = SEC_ERROR_BASE + 36;
|
||||
const SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION = SEC_ERROR_BASE + 41;
|
||||
const SEC_ERROR_PKCS7_BAD_SIGNATURE = SEC_ERROR_BASE + 47;
|
||||
const SEC_ERROR_INADEQUATE_KEY_USAGE = SEC_ERROR_BASE + 90;
|
||||
const SEC_ERROR_INADEQUATE_CERT_TYPE = SEC_ERROR_BASE + 91;
|
||||
const SEC_ERROR_CERT_NOT_IN_NAME_SPACE = SEC_ERROR_BASE + 112;
|
||||
const SEC_ERROR_CERT_BAD_ACCESS_LOCATION = SEC_ERROR_BASE + 117;
|
||||
const SEC_ERROR_OCSP_MALFORMED_REQUEST = SEC_ERROR_BASE + 120;
|
||||
const SEC_ERROR_OCSP_SERVER_ERROR = SEC_ERROR_BASE + 121;
|
||||
const SEC_ERROR_OCSP_TRY_SERVER_LATER = SEC_ERROR_BASE + 122;
|
||||
const SEC_ERROR_OCSP_REQUEST_NEEDS_SIG = SEC_ERROR_BASE + 123;
|
||||
const SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST = SEC_ERROR_BASE + 124;
|
||||
const SEC_ERROR_OCSP_UNKNOWN_CERT = SEC_ERROR_BASE + 126;
|
||||
const SEC_ERROR_OCSP_MALFORMED_RESPONSE = SEC_ERROR_BASE + 129;
|
||||
const SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE = SEC_ERROR_BASE + 130;
|
||||
const SEC_ERROR_OCSP_OLD_RESPONSE = SEC_ERROR_BASE + 132;
|
||||
const SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE = SEC_ERROR_BASE + 141;
|
||||
const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
|
||||
const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160;
|
||||
const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157;
|
||||
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
||||
const SEC_ERROR_INVALID_TIME = SEC_ERROR_BASE + 8;
|
||||
const SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9;
|
||||
const SEC_ERROR_BAD_SIGNATURE = SEC_ERROR_BASE + 10;
|
||||
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
|
||||
const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12;
|
||||
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
|
||||
const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
|
||||
const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21;
|
||||
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
|
||||
const SEC_ERROR_CA_CERT_INVALID = SEC_ERROR_BASE + 36;
|
||||
const SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION = SEC_ERROR_BASE + 41;
|
||||
const SEC_ERROR_PKCS7_BAD_SIGNATURE = SEC_ERROR_BASE + 47;
|
||||
const SEC_ERROR_INADEQUATE_KEY_USAGE = SEC_ERROR_BASE + 90;
|
||||
const SEC_ERROR_INADEQUATE_CERT_TYPE = SEC_ERROR_BASE + 91;
|
||||
const SEC_ERROR_CERT_NOT_IN_NAME_SPACE = SEC_ERROR_BASE + 112;
|
||||
const SEC_ERROR_CERT_BAD_ACCESS_LOCATION = SEC_ERROR_BASE + 117;
|
||||
const SEC_ERROR_OCSP_MALFORMED_REQUEST = SEC_ERROR_BASE + 120;
|
||||
const SEC_ERROR_OCSP_SERVER_ERROR = SEC_ERROR_BASE + 121;
|
||||
const SEC_ERROR_OCSP_TRY_SERVER_LATER = SEC_ERROR_BASE + 122;
|
||||
const SEC_ERROR_OCSP_REQUEST_NEEDS_SIG = SEC_ERROR_BASE + 123;
|
||||
const SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST = SEC_ERROR_BASE + 124;
|
||||
const SEC_ERROR_OCSP_UNKNOWN_CERT = SEC_ERROR_BASE + 126;
|
||||
const SEC_ERROR_OCSP_MALFORMED_RESPONSE = SEC_ERROR_BASE + 129;
|
||||
const SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE = SEC_ERROR_BASE + 130;
|
||||
const SEC_ERROR_OCSP_OLD_RESPONSE = SEC_ERROR_BASE + 132;
|
||||
const SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE = SEC_ERROR_BASE + 141;
|
||||
const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
|
||||
const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160;
|
||||
const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157;
|
||||
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
|
||||
|
||||
const SSL_ERROR_NO_CYPHER_OVERLAP = SSL_ERROR_BASE + 2;
|
||||
const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;
|
||||
const SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17;
|
||||
const SSL_ERROR_WEAK_SERVER_CERT_KEY = SSL_ERROR_BASE + 132;
|
||||
const SSL_ERROR_NO_CYPHER_OVERLAP = SSL_ERROR_BASE + 2;
|
||||
const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;
|
||||
const SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17;
|
||||
const SSL_ERROR_WEAK_SERVER_CERT_KEY = SSL_ERROR_BASE + 132;
|
||||
|
||||
const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = MOZILLA_PKIX_ERROR_BASE + 0;
|
||||
const MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = MOZILLA_PKIX_ERROR_BASE + 1;
|
||||
const MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = MOZILLA_PKIX_ERROR_BASE + 2;
|
||||
const MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = MOZILLA_PKIX_ERROR_BASE + 3;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 5;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 6;
|
||||
const MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING = MOZILLA_PKIX_ERROR_BASE + 8;
|
||||
const MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING = MOZILLA_PKIX_ERROR_BASE + 10;
|
||||
const MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = MOZILLA_PKIX_ERROR_BASE + 12;
|
||||
const MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED = MOZILLA_PKIX_ERROR_BASE + 13;
|
||||
const MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = MOZILLA_PKIX_ERROR_BASE + 14;
|
||||
const MOZILLA_PKIX_ERROR_MITM_DETECTED = MOZILLA_PKIX_ERROR_BASE + 15;
|
||||
const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = MOZILLA_PKIX_ERROR_BASE + 0;
|
||||
const MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY =
|
||||
MOZILLA_PKIX_ERROR_BASE + 1;
|
||||
const MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = MOZILLA_PKIX_ERROR_BASE + 2;
|
||||
const MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = MOZILLA_PKIX_ERROR_BASE + 3;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE =
|
||||
MOZILLA_PKIX_ERROR_BASE + 5;
|
||||
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE =
|
||||
MOZILLA_PKIX_ERROR_BASE + 6;
|
||||
const MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING =
|
||||
MOZILLA_PKIX_ERROR_BASE + 8;
|
||||
const MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING =
|
||||
MOZILLA_PKIX_ERROR_BASE + 10;
|
||||
const MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = MOZILLA_PKIX_ERROR_BASE + 12;
|
||||
const MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED =
|
||||
MOZILLA_PKIX_ERROR_BASE + 13;
|
||||
const MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = MOZILLA_PKIX_ERROR_BASE + 14;
|
||||
const MOZILLA_PKIX_ERROR_MITM_DETECTED = MOZILLA_PKIX_ERROR_BASE + 15;
|
||||
|
||||
// Supported Certificate Usages
|
||||
const certificateUsageSSLClient = 0x0001;
|
||||
const certificateUsageSSLServer = 0x0002;
|
||||
const certificateUsageSSLCA = 0x0008;
|
||||
const certificateUsageEmailSigner = 0x0010;
|
||||
const certificateUsageEmailRecipient = 0x0020;
|
||||
const certificateUsageSSLClient = 0x0001;
|
||||
const certificateUsageSSLServer = 0x0002;
|
||||
const certificateUsageSSLCA = 0x0008;
|
||||
const certificateUsageEmailSigner = 0x0010;
|
||||
const certificateUsageEmailRecipient = 0x0020;
|
||||
|
||||
// A map from the name of a certificate usage to the value of the usage.
|
||||
// Useful for printing debugging information and for enumerating all supported
|
||||
|
|
@ -122,8 +134,6 @@ function arrayToString(a) {
|
|||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Commonly certificates are represented as PEM. The format is roughly as
|
||||
// follows:
|
||||
//
|
||||
|
|
@ -136,14 +146,16 @@ function arrayToString(a) {
|
|||
// with no newlines or BEGIN/END headers. This is a helper function to convert
|
||||
// PEM to the format that nsIX509CertDB requires.
|
||||
function pemToBase64(pem) {
|
||||
return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
|
||||
.replace(/-----END CERTIFICATE-----/, "")
|
||||
.replace(/[\r\n]/g, "");
|
||||
return pem
|
||||
.replace(/-----BEGIN CERTIFICATE-----/, "")
|
||||
.replace(/-----END CERTIFICATE-----/, "")
|
||||
.replace(/[\r\n]/g, "");
|
||||
}
|
||||
|
||||
function build_cert_chain(certNames, testDirectory = "bad_certs") {
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"]
|
||||
.createInstance(Ci.nsIX509CertList);
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"].createInstance(
|
||||
Ci.nsIX509CertList
|
||||
);
|
||||
certNames.forEach(function(certName) {
|
||||
let cert = constructCertFromFile(`${testDirectory}/${certName}.pem`);
|
||||
certList.addCert(cert);
|
||||
|
|
@ -152,11 +164,13 @@ function build_cert_chain(certNames, testDirectory = "bad_certs") {
|
|||
}
|
||||
|
||||
function readFile(file) {
|
||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
|
||||
Ci.nsIFileInputStream
|
||||
);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
let available = fstream.available();
|
||||
let data = available > 0 ? NetUtil.readInputStreamToString(fstream, available) : "";
|
||||
let data =
|
||||
available > 0 ? NetUtil.readInputStreamToString(fstream, available) : "";
|
||||
fstream.close();
|
||||
return data;
|
||||
}
|
||||
|
|
@ -174,8 +188,9 @@ function addCertFromFile(certdb, filename, trustString) {
|
|||
function constructCertFromFile(filename) {
|
||||
let certFile = do_get_file(filename, false);
|
||||
let certBytes = readFile(certFile);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
try {
|
||||
return certdb.constructX509(certBytes);
|
||||
} catch (e) {}
|
||||
|
|
@ -184,14 +199,16 @@ function constructCertFromFile(filename) {
|
|||
}
|
||||
|
||||
function setCertTrust(cert, trustString) {
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
certdb.setCertTrustFromString(cert, trustString);
|
||||
}
|
||||
|
||||
function getXPCOMStatusFromNSS(statusNSS) {
|
||||
let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"]
|
||||
.getService(Ci.nsINSSErrorsService);
|
||||
let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"].getService(
|
||||
Ci.nsINSSErrorsService
|
||||
);
|
||||
return nssErrorsService.getXPCOMFromNSSError(statusNSS);
|
||||
}
|
||||
|
||||
|
|
@ -205,12 +222,18 @@ class CertVerificationExpectedErrorResult {
|
|||
}
|
||||
|
||||
verifyCertFinished(aPRErrorCode, aVerifiedChain, aHasEVPolicy) {
|
||||
equal(aPRErrorCode, this.expectedError,
|
||||
`verifying ${this.certName}: should get error ${this.expectedError}`);
|
||||
equal(
|
||||
aPRErrorCode,
|
||||
this.expectedError,
|
||||
`verifying ${this.certName}: should get error ${this.expectedError}`
|
||||
);
|
||||
if (this.expectedEVStatus != undefined) {
|
||||
equal(aHasEVPolicy, this.expectedEVStatus,
|
||||
`verifying ${this.certName}: ` +
|
||||
`should ${this.expectedEVStatus ? "be" : "not be"} EV`);
|
||||
equal(
|
||||
aHasEVPolicy,
|
||||
this.expectedEVStatus,
|
||||
`verifying ${this.certName}: ` +
|
||||
`should ${this.expectedEVStatus ? "be" : "not be"} EV`
|
||||
);
|
||||
}
|
||||
this.resolve();
|
||||
}
|
||||
|
|
@ -218,34 +241,63 @@ class CertVerificationExpectedErrorResult {
|
|||
|
||||
// certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation.
|
||||
// In particular, hostname is optional.
|
||||
function checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, time,
|
||||
/* optional */ isEVExpected,
|
||||
/* optional */ hostname) {
|
||||
function checkCertErrorGenericAtTime(
|
||||
certdb,
|
||||
cert,
|
||||
expectedError,
|
||||
usage,
|
||||
time,
|
||||
/* optional */ isEVExpected,
|
||||
/* optional */ hostname
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let result = new CertVerificationExpectedErrorResult(
|
||||
cert.commonName, expectedError, isEVExpected, resolve);
|
||||
certdb.asyncVerifyCertAtTime(cert, usage, NO_FLAGS, hostname, time,
|
||||
result);
|
||||
let result = new CertVerificationExpectedErrorResult(
|
||||
cert.commonName,
|
||||
expectedError,
|
||||
isEVExpected,
|
||||
resolve
|
||||
);
|
||||
certdb.asyncVerifyCertAtTime(cert, usage, NO_FLAGS, hostname, time, result);
|
||||
});
|
||||
}
|
||||
|
||||
// certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation.
|
||||
// In particular, hostname is optional.
|
||||
function checkCertErrorGeneric(certdb, cert, expectedError, usage,
|
||||
/* optional */ isEVExpected,
|
||||
/* optional */ hostname) {
|
||||
let now = (new Date()).getTime() / 1000;
|
||||
return checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, now,
|
||||
isEVExpected, hostname);
|
||||
function checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
expectedError,
|
||||
usage,
|
||||
/* optional */ isEVExpected,
|
||||
/* optional */ hostname
|
||||
) {
|
||||
let now = new Date().getTime() / 1000;
|
||||
return checkCertErrorGenericAtTime(
|
||||
certdb,
|
||||
cert,
|
||||
expectedError,
|
||||
usage,
|
||||
now,
|
||||
isEVExpected,
|
||||
hostname
|
||||
);
|
||||
}
|
||||
|
||||
function checkEVStatus(certDB, cert, usage, isEVExpected) {
|
||||
return checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage,
|
||||
isEVExpected);
|
||||
return checkCertErrorGeneric(
|
||||
certDB,
|
||||
cert,
|
||||
PRErrorCodeSuccess,
|
||||
usage,
|
||||
isEVExpected
|
||||
);
|
||||
}
|
||||
|
||||
function _getLibraryFunctionWithNoArguments(functionName, libraryName,
|
||||
returnType) {
|
||||
function _getLibraryFunctionWithNoArguments(
|
||||
functionName,
|
||||
libraryName,
|
||||
returnType
|
||||
) {
|
||||
// Open the NSS library. copied from services/crypto/modules/WeaveCrypto.js
|
||||
let path = ctypes.libraryName(libraryName);
|
||||
|
||||
|
|
@ -262,28 +314,36 @@ function _getLibraryFunctionWithNoArguments(functionName, libraryName,
|
|||
}
|
||||
|
||||
let SECStatus = ctypes.int;
|
||||
let func = nsslib.declare(functionName, ctypes.default_abi,
|
||||
returnType || SECStatus);
|
||||
let func = nsslib.declare(
|
||||
functionName,
|
||||
ctypes.default_abi,
|
||||
returnType || SECStatus
|
||||
);
|
||||
return func;
|
||||
}
|
||||
|
||||
function clearOCSPCache() {
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
certdb.clearOCSPCache();
|
||||
}
|
||||
|
||||
function clearSessionCache() {
|
||||
let SSL_ClearSessionCache = null;
|
||||
try {
|
||||
SSL_ClearSessionCache =
|
||||
_getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "ssl3",
|
||||
ctypes.void_t);
|
||||
SSL_ClearSessionCache = _getLibraryFunctionWithNoArguments(
|
||||
"SSL_ClearSessionCache",
|
||||
"ssl3",
|
||||
ctypes.void_t
|
||||
);
|
||||
} catch (e) {
|
||||
// On Windows, this is actually in the nss3 library.
|
||||
SSL_ClearSessionCache =
|
||||
_getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "nss3",
|
||||
ctypes.void_t);
|
||||
SSL_ClearSessionCache = _getLibraryFunctionWithNoArguments(
|
||||
"SSL_ClearSessionCache",
|
||||
"nss3",
|
||||
ctypes.void_t
|
||||
);
|
||||
}
|
||||
if (!SSL_ClearSessionCache) {
|
||||
throw new Error("couldn't get SSL_ClearSessionCache");
|
||||
|
|
@ -292,31 +352,36 @@ function clearSessionCache() {
|
|||
}
|
||||
|
||||
function getSSLStatistics() {
|
||||
let SSL3Statistics = new ctypes.StructType("SSL3Statistics",
|
||||
[ { "sch_sid_cache_hits": ctypes.long },
|
||||
{ "sch_sid_cache_misses": ctypes.long },
|
||||
{ "sch_sid_cache_not_ok": ctypes.long },
|
||||
{ "hsh_sid_cache_hits": ctypes.long },
|
||||
{ "hsh_sid_cache_misses": ctypes.long },
|
||||
{ "hsh_sid_cache_not_ok": ctypes.long },
|
||||
{ "hch_sid_cache_hits": ctypes.long },
|
||||
{ "hch_sid_cache_misses": ctypes.long },
|
||||
{ "hch_sid_cache_not_ok": ctypes.long },
|
||||
{ "sch_sid_stateless_resumes": ctypes.long },
|
||||
{ "hsh_sid_stateless_resumes": ctypes.long },
|
||||
{ "hch_sid_stateless_resumes": ctypes.long },
|
||||
{ "hch_sid_ticket_parse_failures": ctypes.long }]);
|
||||
let SSL3Statistics = new ctypes.StructType("SSL3Statistics", [
|
||||
{ sch_sid_cache_hits: ctypes.long },
|
||||
{ sch_sid_cache_misses: ctypes.long },
|
||||
{ sch_sid_cache_not_ok: ctypes.long },
|
||||
{ hsh_sid_cache_hits: ctypes.long },
|
||||
{ hsh_sid_cache_misses: ctypes.long },
|
||||
{ hsh_sid_cache_not_ok: ctypes.long },
|
||||
{ hch_sid_cache_hits: ctypes.long },
|
||||
{ hch_sid_cache_misses: ctypes.long },
|
||||
{ hch_sid_cache_not_ok: ctypes.long },
|
||||
{ sch_sid_stateless_resumes: ctypes.long },
|
||||
{ hsh_sid_stateless_resumes: ctypes.long },
|
||||
{ hch_sid_stateless_resumes: ctypes.long },
|
||||
{ hch_sid_ticket_parse_failures: ctypes.long },
|
||||
]);
|
||||
let SSL3StatisticsPtr = new ctypes.PointerType(SSL3Statistics);
|
||||
let SSL_GetStatistics = null;
|
||||
try {
|
||||
SSL_GetStatistics = _getLibraryFunctionWithNoArguments("SSL_GetStatistics",
|
||||
"ssl3",
|
||||
SSL3StatisticsPtr);
|
||||
SSL_GetStatistics = _getLibraryFunctionWithNoArguments(
|
||||
"SSL_GetStatistics",
|
||||
"ssl3",
|
||||
SSL3StatisticsPtr
|
||||
);
|
||||
} catch (e) {
|
||||
// On Windows, this is actually in the nss3 library.
|
||||
SSL_GetStatistics = _getLibraryFunctionWithNoArguments("SSL_GetStatistics",
|
||||
"nss3",
|
||||
SSL3StatisticsPtr);
|
||||
SSL_GetStatistics = _getLibraryFunctionWithNoArguments(
|
||||
"SSL_GetStatistics",
|
||||
"nss3",
|
||||
SSL3StatisticsPtr
|
||||
);
|
||||
}
|
||||
if (!SSL_GetStatistics) {
|
||||
throw new Error("Failed to get SSL statistics");
|
||||
|
|
@ -402,18 +467,23 @@ function add_tls_server_setup(serverBinName, certsPath, addDefaultRoot = true) {
|
|||
* affects OCSP because OCSP cache is double-keyed by origin attributes' first
|
||||
* party domain.
|
||||
*/
|
||||
function add_connection_test(aHost, aExpectedResult,
|
||||
aBeforeConnect, aWithSecurityInfo,
|
||||
aAfterStreamOpen,
|
||||
/* optional */ aOriginAttributes) {
|
||||
function add_connection_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
aBeforeConnect,
|
||||
aWithSecurityInfo,
|
||||
aAfterStreamOpen,
|
||||
/* optional */ aOriginAttributes
|
||||
) {
|
||||
const REMOTE_PORT = 8443;
|
||||
|
||||
function Connection(host) {
|
||||
this.host = host;
|
||||
this.thread = Services.tm.currentThread;
|
||||
this.defer = Promise.defer();
|
||||
let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
|
||||
.getService(Ci.nsISocketTransportService);
|
||||
let sts = Cc["@mozilla.org/network/socket-transport-service;1"].getService(
|
||||
Ci.nsISocketTransportService
|
||||
);
|
||||
this.transport = sts.createTransport(["ssl"], host, REMOTE_PORT, null);
|
||||
// See bug 1129771 - attempting to connect to [::1] when the server is
|
||||
// listening on 127.0.0.1 causes frequent failures on OS X 10.10.
|
||||
|
|
@ -430,7 +500,10 @@ function add_connection_test(aHost, aExpectedResult,
|
|||
Connection.prototype = {
|
||||
// nsITransportEventSink
|
||||
onTransportStatus(aTransport, aStatus, aProgress, aProgressMax) {
|
||||
if (!this.connected && aStatus == Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
|
||||
if (
|
||||
!this.connected &&
|
||||
aStatus == Ci.nsISocketTransport.STATUS_CONNECTED_TO
|
||||
) {
|
||||
this.connected = true;
|
||||
this.outputStream.asyncWait(this, 0, 0, this.thread);
|
||||
}
|
||||
|
|
@ -441,8 +514,7 @@ function add_connection_test(aHost, aExpectedResult,
|
|||
try {
|
||||
// this will throw if the stream has been closed by an error
|
||||
let str = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
Assert.equal(str, "0",
|
||||
"Should have received ASCII '0' from server");
|
||||
Assert.equal(str, "0", "Should have received ASCII '0' from server");
|
||||
this.inputStream.close();
|
||||
this.outputStream.close();
|
||||
this.result = Cr.NS_OK;
|
||||
|
|
@ -457,19 +529,22 @@ function add_connection_test(aHost, aExpectedResult,
|
|||
if (aAfterStreamOpen) {
|
||||
aAfterStreamOpen(this.transport);
|
||||
}
|
||||
let sslSocketControl = this.transport.securityInfo
|
||||
.QueryInterface(Ci.nsISSLSocketControl);
|
||||
let sslSocketControl = this.transport.securityInfo.QueryInterface(
|
||||
Ci.nsISSLSocketControl
|
||||
);
|
||||
sslSocketControl.proxyStartSSL();
|
||||
this.outputStream.write("0", 1);
|
||||
let inStream = this.transport.openInputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncInputStream);
|
||||
let inStream = this.transport
|
||||
.openInputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncInputStream);
|
||||
this.inputStream = inStream;
|
||||
this.inputStream.asyncWait(this, 0, 0, this.thread);
|
||||
},
|
||||
|
||||
go() {
|
||||
this.outputStream = this.transport.openOutputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncOutputStream);
|
||||
this.outputStream = this.transport
|
||||
.openOutputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncOutputStream);
|
||||
return this.defer.promise;
|
||||
},
|
||||
};
|
||||
|
|
@ -488,14 +563,21 @@ function add_connection_test(aHost, aExpectedResult,
|
|||
}
|
||||
connectTo(aHost).then(function(conn) {
|
||||
info("handling " + aHost);
|
||||
let expectedNSResult = aExpectedResult == PRErrorCodeSuccess
|
||||
? Cr.NS_OK
|
||||
: getXPCOMStatusFromNSS(aExpectedResult);
|
||||
Assert.equal(conn.result, expectedNSResult,
|
||||
"Actual and expected connection result should match");
|
||||
let expectedNSResult =
|
||||
aExpectedResult == PRErrorCodeSuccess
|
||||
? Cr.NS_OK
|
||||
: getXPCOMStatusFromNSS(aExpectedResult);
|
||||
Assert.equal(
|
||||
conn.result,
|
||||
expectedNSResult,
|
||||
"Actual and expected connection result should match"
|
||||
);
|
||||
if (aWithSecurityInfo) {
|
||||
aWithSecurityInfo(conn.transport.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo));
|
||||
aWithSecurityInfo(
|
||||
conn.transport.securityInfo.QueryInterface(
|
||||
Ci.nsITransportSecurityInfo
|
||||
)
|
||||
);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
|
|
@ -532,8 +614,9 @@ function _getBinaryUtil(binaryUtilName) {
|
|||
|
||||
// Do not call this directly; use add_tls_server_setup
|
||||
function _setupTLSServerTest(serverBinName, certsPath, addDefaultRoot) {
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
// The trusted CA that is typically used for "good" certificates.
|
||||
if (addDefaultRoot) {
|
||||
addCertFromFile(certdb, `${certsPath}/test-ca.pem`, "CTu,u,u");
|
||||
|
|
@ -541,8 +624,9 @@ function _setupTLSServerTest(serverBinName, certsPath, addDefaultRoot) {
|
|||
|
||||
const CALLBACK_PORT = 8444;
|
||||
|
||||
let envSvc = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let envSvc = Cc["@mozilla.org/process/environment;1"].getService(
|
||||
Ci.nsIEnvironment
|
||||
);
|
||||
let greBinDir = Services.dirsvc.get("GreBinD", Ci.nsIFile);
|
||||
envSvc.set("DYLD_LIBRARY_PATH", greBinDir.path);
|
||||
// TODO(bug 1107794): Android libraries are in /data/local/xpcb, but "GreBinD"
|
||||
|
|
@ -552,16 +636,18 @@ function _setupTLSServerTest(serverBinName, certsPath, addDefaultRoot) {
|
|||
envSvc.set("MOZ_TLS_SERVER_CALLBACK_PORT", CALLBACK_PORT);
|
||||
|
||||
let httpServer = new HttpServer();
|
||||
httpServer.registerPathHandler("/",
|
||||
function handleServerCallback(aRequest, aResponse) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
|
||||
aResponse.setHeader("Content-Type", "text/plain");
|
||||
let responseBody = "OK!";
|
||||
aResponse.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
executeSoon(function() {
|
||||
httpServer.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
httpServer.registerPathHandler("/", function handleServerCallback(
|
||||
aRequest,
|
||||
aResponse
|
||||
) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
|
||||
aResponse.setHeader("Content-Type", "text/plain");
|
||||
let responseBody = "OK!";
|
||||
aResponse.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
executeSoon(function() {
|
||||
httpServer.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
httpServer.start(CALLBACK_PORT);
|
||||
|
||||
let serverBin = _getBinaryUtil(serverBinName);
|
||||
|
|
@ -571,7 +657,7 @@ function _setupTLSServerTest(serverBinName, certsPath, addDefaultRoot) {
|
|||
certDir.append(`${certsPath}`);
|
||||
Assert.ok(certDir.exists(), `certificate folder (${certsPath}) should exist`);
|
||||
// Using "sql:" causes the SQL DB to be used so we can run tests on Android.
|
||||
process.run(false, [ "sql:" + certDir.path, Services.appinfo.processID ], 2);
|
||||
process.run(false, ["sql:" + certDir.path, Services.appinfo.processID], 2);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
process.kill();
|
||||
|
|
@ -600,8 +686,9 @@ function generateOCSPResponses(ocspRespArray, nssDBlocation) {
|
|||
argArray.push(filename);
|
||||
info("argArray = " + argArray);
|
||||
|
||||
let process = Cc["@mozilla.org/process/util;1"]
|
||||
.createInstance(Ci.nsIProcess);
|
||||
let process = Cc["@mozilla.org/process/util;1"].createInstance(
|
||||
Ci.nsIProcess
|
||||
);
|
||||
process.init(ocspGenBin);
|
||||
process.run(true, argArray, argArray.length);
|
||||
Assert.equal(0, process.exitValue, "Process exit value should be 0");
|
||||
|
|
@ -651,61 +738,91 @@ function getFailingHttpServer(serverPort, serverIdentities) {
|
|||
// GenerateOCSPResponse.cpp).
|
||||
// responseHeaderPairs is an optional array of HTTP header (name, value) pairs
|
||||
// to set in each response.
|
||||
function startOCSPResponder(serverPort, identity, nssDBLocation,
|
||||
expectedCertNames, expectedBasePaths,
|
||||
expectedMethods, expectedResponseTypes,
|
||||
responseHeaderPairs = []) {
|
||||
let ocspResponseGenerationArgs = expectedCertNames.map(
|
||||
function(expectedNick) {
|
||||
let responseType = "good";
|
||||
if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
|
||||
responseType = expectedResponseTypes.shift();
|
||||
}
|
||||
return [responseType, expectedNick, "unused", 0];
|
||||
function startOCSPResponder(
|
||||
serverPort,
|
||||
identity,
|
||||
nssDBLocation,
|
||||
expectedCertNames,
|
||||
expectedBasePaths,
|
||||
expectedMethods,
|
||||
expectedResponseTypes,
|
||||
responseHeaderPairs = []
|
||||
) {
|
||||
let ocspResponseGenerationArgs = expectedCertNames.map(function(
|
||||
expectedNick
|
||||
) {
|
||||
let responseType = "good";
|
||||
if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
|
||||
responseType = expectedResponseTypes.shift();
|
||||
}
|
||||
return [responseType, expectedNick, "unused", 0];
|
||||
});
|
||||
let ocspResponses = generateOCSPResponses(
|
||||
ocspResponseGenerationArgs,
|
||||
nssDBLocation
|
||||
);
|
||||
let ocspResponses = generateOCSPResponses(ocspResponseGenerationArgs,
|
||||
nssDBLocation);
|
||||
let httpServer = new HttpServer();
|
||||
httpServer.registerPrefixHandler("/",
|
||||
function handleServerCallback(aRequest, aResponse) {
|
||||
info("got request for: " + aRequest.path);
|
||||
let basePath = aRequest.path.slice(1).split("/")[0];
|
||||
if (expectedBasePaths.length >= 1) {
|
||||
Assert.equal(basePath, expectedBasePaths.shift(),
|
||||
"Actual and expected base path should match");
|
||||
}
|
||||
Assert.ok(expectedCertNames.length >= 1,
|
||||
"expectedCertNames should contain >= 1 entries");
|
||||
if (expectedMethods && expectedMethods.length >= 1) {
|
||||
Assert.equal(aRequest.method, expectedMethods.shift(),
|
||||
"Actual and expected fetch method should match");
|
||||
}
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
|
||||
aResponse.setHeader("Content-Type", "application/ocsp-response");
|
||||
for (let headerPair of responseHeaderPairs) {
|
||||
aResponse.setHeader(headerPair[0], headerPair[1]);
|
||||
}
|
||||
aResponse.write(ocspResponses.shift());
|
||||
});
|
||||
httpServer.registerPrefixHandler("/", function handleServerCallback(
|
||||
aRequest,
|
||||
aResponse
|
||||
) {
|
||||
info("got request for: " + aRequest.path);
|
||||
let basePath = aRequest.path.slice(1).split("/")[0];
|
||||
if (expectedBasePaths.length >= 1) {
|
||||
Assert.equal(
|
||||
basePath,
|
||||
expectedBasePaths.shift(),
|
||||
"Actual and expected base path should match"
|
||||
);
|
||||
}
|
||||
Assert.ok(
|
||||
expectedCertNames.length >= 1,
|
||||
"expectedCertNames should contain >= 1 entries"
|
||||
);
|
||||
if (expectedMethods && expectedMethods.length >= 1) {
|
||||
Assert.equal(
|
||||
aRequest.method,
|
||||
expectedMethods.shift(),
|
||||
"Actual and expected fetch method should match"
|
||||
);
|
||||
}
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
|
||||
aResponse.setHeader("Content-Type", "application/ocsp-response");
|
||||
for (let headerPair of responseHeaderPairs) {
|
||||
aResponse.setHeader(headerPair[0], headerPair[1]);
|
||||
}
|
||||
aResponse.write(ocspResponses.shift());
|
||||
});
|
||||
httpServer.identity.setPrimary("http", identity, serverPort);
|
||||
httpServer.start(serverPort);
|
||||
return {
|
||||
stop(callback) {
|
||||
// make sure we consumed each expected response
|
||||
Assert.equal(ocspResponses.length, 0,
|
||||
"Should have 0 remaining expected OCSP responses");
|
||||
Assert.equal(
|
||||
ocspResponses.length,
|
||||
0,
|
||||
"Should have 0 remaining expected OCSP responses"
|
||||
);
|
||||
if (expectedMethods) {
|
||||
Assert.equal(expectedMethods.length, 0,
|
||||
"Should have 0 remaining expected fetch methods");
|
||||
Assert.equal(
|
||||
expectedMethods.length,
|
||||
0,
|
||||
"Should have 0 remaining expected fetch methods"
|
||||
);
|
||||
}
|
||||
if (expectedBasePaths) {
|
||||
Assert.equal(expectedBasePaths.length, 0,
|
||||
"Should have 0 remaining expected base paths");
|
||||
Assert.equal(
|
||||
expectedBasePaths.length,
|
||||
0,
|
||||
"Should have 0 remaining expected base paths"
|
||||
);
|
||||
}
|
||||
if (expectedResponseTypes) {
|
||||
Assert.equal(expectedResponseTypes.length, 0,
|
||||
"Should have 0 remaining expected response types");
|
||||
Assert.equal(
|
||||
expectedResponseTypes.length,
|
||||
0,
|
||||
"Should have 0 remaining expected response types"
|
||||
);
|
||||
}
|
||||
httpServer.stop(callback);
|
||||
},
|
||||
|
|
@ -720,7 +837,6 @@ function stopOCSPResponder(responder) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
// A prototype for a fake, error-free secInfo
|
||||
var FakeTransportSecurityInfo = function(certificate) {
|
||||
this.serverCert = certificate;
|
||||
|
|
@ -746,34 +862,61 @@ FakeTransportSecurityInfo.prototype = {
|
|||
// called directly.
|
||||
function add_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
||||
let bits =
|
||||
(aSecurityInfo.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) |
|
||||
(aSecurityInfo.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) |
|
||||
(aSecurityInfo.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0);
|
||||
(aSecurityInfo.isUntrusted
|
||||
? Ci.nsICertOverrideService.ERROR_UNTRUSTED
|
||||
: 0) |
|
||||
(aSecurityInfo.isDomainMismatch
|
||||
? Ci.nsICertOverrideService.ERROR_MISMATCH
|
||||
: 0) |
|
||||
(aSecurityInfo.isNotValidAtThisTime
|
||||
? Ci.nsICertOverrideService.ERROR_TIME
|
||||
: 0);
|
||||
|
||||
Assert.equal(bits, aExpectedBits,
|
||||
"Actual and expected override bits should match");
|
||||
Assert.equal(
|
||||
bits,
|
||||
aExpectedBits,
|
||||
"Actual and expected override bits should match"
|
||||
);
|
||||
let cert = aSecurityInfo.serverCert;
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits,
|
||||
true);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
aHost,
|
||||
8443,
|
||||
cert,
|
||||
aExpectedBits,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// Given a host, expected error bits (see nsICertOverrideService.idl), and an
|
||||
// expected error code, tests that an initial connection to the host fails
|
||||
// with the expected errors and that adding an override results in a subsequent
|
||||
// connection succeeding.
|
||||
function add_cert_override_test(aHost, aExpectedBits, aExpectedError,
|
||||
aExpectedSecInfo = undefined) {
|
||||
add_connection_test(aHost, aExpectedError, null,
|
||||
add_cert_override.bind(this, aHost, aExpectedBits));
|
||||
function add_cert_override_test(
|
||||
aHost,
|
||||
aExpectedBits,
|
||||
aExpectedError,
|
||||
aExpectedSecInfo = undefined
|
||||
) {
|
||||
add_connection_test(
|
||||
aHost,
|
||||
aExpectedError,
|
||||
null,
|
||||
add_cert_override.bind(this, aHost, aExpectedBits)
|
||||
);
|
||||
add_connection_test(aHost, PRErrorCodeSuccess, null, aSecurityInfo => {
|
||||
Assert.ok(aSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
|
||||
"Cert override flag should be set on the security state");
|
||||
Assert.ok(
|
||||
aSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
|
||||
"Cert override flag should be set on the security state"
|
||||
);
|
||||
if (aExpectedSecInfo) {
|
||||
if (aExpectedSecInfo.failedCertChain) {
|
||||
ok(aExpectedSecInfo.failedCertChain.equals(aSecurityInfo.failedCertChain));
|
||||
ok(
|
||||
aExpectedSecInfo.failedCertChain.equals(aSecurityInfo.failedCertChain)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -786,16 +929,31 @@ function add_cert_override_test(aHost, aExpectedBits, aExpectedError,
|
|||
function attempt_adding_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
||||
if (aSecurityInfo.serverCert) {
|
||||
let bits =
|
||||
(aSecurityInfo.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) |
|
||||
(aSecurityInfo.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) |
|
||||
(aSecurityInfo.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0);
|
||||
Assert.equal(bits, aExpectedBits,
|
||||
"Actual and expected override bits should match");
|
||||
(aSecurityInfo.isUntrusted
|
||||
? Ci.nsICertOverrideService.ERROR_UNTRUSTED
|
||||
: 0) |
|
||||
(aSecurityInfo.isDomainMismatch
|
||||
? Ci.nsICertOverrideService.ERROR_MISMATCH
|
||||
: 0) |
|
||||
(aSecurityInfo.isNotValidAtThisTime
|
||||
? Ci.nsICertOverrideService.ERROR_TIME
|
||||
: 0);
|
||||
Assert.equal(
|
||||
bits,
|
||||
aExpectedBits,
|
||||
"Actual and expected override bits should match"
|
||||
);
|
||||
let cert = aSecurityInfo.serverCert;
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits,
|
||||
true);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
aHost,
|
||||
8443,
|
||||
cert,
|
||||
aExpectedBits,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -805,9 +963,17 @@ function attempt_adding_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
|||
// subsequent connection succeeding (i.e. the same error code is encountered).
|
||||
// The idea here is that for HSTS hosts or hosts with key pins, no error is
|
||||
// overridable, even if an entry is added to the override service.
|
||||
function add_prevented_cert_override_test(aHost, aExpectedBits, aExpectedError) {
|
||||
add_connection_test(aHost, aExpectedError, null,
|
||||
attempt_adding_cert_override.bind(this, aHost, aExpectedBits));
|
||||
function add_prevented_cert_override_test(
|
||||
aHost,
|
||||
aExpectedBits,
|
||||
aExpectedError
|
||||
) {
|
||||
add_connection_test(
|
||||
aHost,
|
||||
aExpectedError,
|
||||
null,
|
||||
attempt_adding_cert_override.bind(this, aHost, aExpectedBits)
|
||||
);
|
||||
add_connection_test(aHost, aExpectedError);
|
||||
}
|
||||
|
||||
|
|
@ -822,11 +988,17 @@ class CertVerificationResult {
|
|||
|
||||
verifyCertFinished(aPRErrorCode, aVerifiedChain, aHasEVPolicy) {
|
||||
if (this.successExpected) {
|
||||
equal(aPRErrorCode, PRErrorCodeSuccess,
|
||||
`verifying ${this.certName} for ${this.usageString} should succeed`);
|
||||
equal(
|
||||
aPRErrorCode,
|
||||
PRErrorCodeSuccess,
|
||||
`verifying ${this.certName} for ${this.usageString} should succeed`
|
||||
);
|
||||
} else {
|
||||
notEqual(aPRErrorCode, PRErrorCodeSuccess,
|
||||
`verifying ${this.certName} for ${this.usageString} should fail`);
|
||||
notEqual(
|
||||
aPRErrorCode,
|
||||
PRErrorCodeSuccess,
|
||||
`verifying ${this.certName} for ${this.usageString} should fail`
|
||||
);
|
||||
}
|
||||
this.resolve();
|
||||
}
|
||||
|
|
@ -851,14 +1023,18 @@ class CertVerificationResult {
|
|||
* have completed.
|
||||
*/
|
||||
function asyncTestCertificateUsages(certdb, cert, expectedUsages) {
|
||||
let now = (new Date()).getTime() / 1000;
|
||||
let now = new Date().getTime() / 1000;
|
||||
let promises = [];
|
||||
Object.keys(allCertificateUsages).forEach(usageString => {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
let usage = allCertificateUsages[usageString];
|
||||
let successExpected = expectedUsages.includes(usage);
|
||||
let result = new CertVerificationResult(cert.commonName, usageString,
|
||||
successExpected, resolve);
|
||||
let result = new CertVerificationResult(
|
||||
cert.commonName,
|
||||
usageString,
|
||||
successExpected,
|
||||
resolve
|
||||
);
|
||||
let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY;
|
||||
certdb.asyncVerifyCertAtTime(cert, usage, flags, null, now, result);
|
||||
});
|
||||
|
|
@ -884,14 +1060,17 @@ function loadPKCS11TestModule(expectModuleUnloadToFail) {
|
|||
libraryFile.append(ctypes.libraryName("pkcs11testmodule"));
|
||||
ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
|
||||
|
||||
let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
|
||||
.getService(Ci.nsIPKCS11ModuleDB);
|
||||
let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
|
||||
Ci.nsIPKCS11ModuleDB
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
try {
|
||||
pkcs11ModuleDB.deleteModule("PKCS11 Test Module");
|
||||
} catch (e) {
|
||||
Assert.ok(expectModuleUnloadToFail,
|
||||
`Module unload should suceed only when expected: ${e}`);
|
||||
Assert.ok(
|
||||
expectModuleUnloadToFail,
|
||||
`Module unload should suceed only when expected: ${e}`
|
||||
);
|
||||
}
|
||||
});
|
||||
pkcs11ModuleDB.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
|
||||
|
|
@ -906,7 +1085,9 @@ function hexify(data) {
|
|||
// Therefore, if the Unicode value is < 0x10, we have a single-character hex
|
||||
// string when we want one that's two characters, and unconditionally
|
||||
// prepending a "0" solves the problem.
|
||||
return Array.from(data, (c, i) => ("0" + data.charCodeAt(i).toString(16)).slice(-2)).join("");
|
||||
return Array.from(data, (c, i) =>
|
||||
("0" + data.charCodeAt(i).toString(16)).slice(-2)
|
||||
).join("");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,32 +2,65 @@
|
|||
"use strict";
|
||||
|
||||
function run_test() {
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://expired.example.com"),
|
||||
0));
|
||||
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://notexpired.example.com"),
|
||||
0));
|
||||
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://includesubdomains.preloaded.test"),
|
||||
0));
|
||||
ok(!SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://sub.includesubdomains.preloaded.test"), 0));
|
||||
ok(SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://incsubdomain.example.com"), 0));
|
||||
ok(SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://sub.incsubdomain.example.com"), 0));
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://includesubdomains2.preloaded.test"),
|
||||
0));
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://sub.includesubdomains2.preloaded.test"),
|
||||
0));
|
||||
ok(
|
||||
!SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://expired.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://notexpired.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://includesubdomains.preloaded.test"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://sub.includesubdomains.preloaded.test"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://incsubdomain.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://sub.incsubdomain.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://includesubdomains2.preloaded.test"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!SSService.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://sub.includesubdomains2.preloaded.test"),
|
||||
0
|
||||
)
|
||||
);
|
||||
do_test_finished();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@
|
|||
// in the new trust bits being ignored.
|
||||
|
||||
do_get_profile();
|
||||
var certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function load_cert(cert, trust) {
|
||||
let file = "test_intermediate_basic_usage_constraints/" + cert + ".pem";
|
||||
|
|
@ -28,17 +29,26 @@ function getDERString(cert) {
|
|||
add_task(async function() {
|
||||
load_cert("ca", "CTu,CTu,CTu");
|
||||
let int_cert = load_cert("int-limited-depth", "CTu,CTu,CTu");
|
||||
let file = "test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem";
|
||||
let file =
|
||||
"test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem";
|
||||
let cert_pem = readFile(do_get_file(file));
|
||||
let ee = certDB.constructX509FromBase64(pemToBase64(cert_pem));
|
||||
await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
// Change the already existing intermediate certificate's trust using
|
||||
// addCertFromBase64().
|
||||
notEqual(int_cert, null, "Intermediate cert should be in the cert DB");
|
||||
let base64_cert = btoa(getDERString(int_cert));
|
||||
let returnedEE = certDB.addCertFromBase64(base64_cert, "p,p,p");
|
||||
notEqual(returnedEE, null, "addCertFromBase64 should return a certificate");
|
||||
await checkCertErrorGeneric(certDB, ee, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,24 +16,34 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function certFromFile(certName) {
|
||||
return constructCertFromFile(`test_baseline_requirements/${certName}.pem`);
|
||||
}
|
||||
|
||||
function loadCertWithTrust(certName, trustString) {
|
||||
addCertFromFile(gCertDB, `test_baseline_requirements/${certName}.pem`,
|
||||
trustString);
|
||||
addCertFromFile(
|
||||
gCertDB,
|
||||
`test_baseline_requirements/${certName}.pem`,
|
||||
trustString
|
||||
);
|
||||
}
|
||||
|
||||
function checkCertOn25August2016(cert, expectedResult) {
|
||||
// (new Date("2016-08-25T00:00:00Z")).getTime() / 1000
|
||||
const VALIDATION_TIME = 1472083200;
|
||||
return checkCertErrorGenericAtTime(gCertDB, cert, expectedResult,
|
||||
certificateUsageSSLServer, VALIDATION_TIME,
|
||||
false, "example.com");
|
||||
return checkCertErrorGenericAtTime(
|
||||
gCertDB,
|
||||
cert,
|
||||
expectedResult,
|
||||
certificateUsageSSLServer,
|
||||
VALIDATION_TIME,
|
||||
false,
|
||||
"example.com"
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
@ -55,137 +65,231 @@ add_task(async function() {
|
|||
// regardless of the value of the pref.
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
|
||||
info("current mode: always fall back, root not built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"), PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
|
||||
info("current mode: fall back for notBefore < August 23, 2016, root " +
|
||||
"not built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
info(
|
||||
"current mode: fall back for notBefore < August 23, 2016, root " +
|
||||
"not built-in"
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"), PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
|
||||
info("current mode: fall back for notBefore < August 23, 2015, root " +
|
||||
"not built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
info(
|
||||
"current mode: fall back for notBefore < August 23, 2015, root " +
|
||||
"not built-in"
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"), PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
|
||||
info("current mode: never fall back, root not built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"), PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
// In debug builds, we can treat an imported root as a built-in, and thus we
|
||||
// can actually test the different values of the pref.
|
||||
if (isDebugBuild) {
|
||||
let root = certFromFile("ca");
|
||||
Services.prefs.setCharPref("security.test.built_in_root_hash",
|
||||
root.sha256Fingerprint);
|
||||
Services.prefs.setCharPref(
|
||||
"security.test.built_in_root_hash",
|
||||
root.sha256Fingerprint
|
||||
);
|
||||
|
||||
// Always fall back if necessary.
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
|
||||
info("current mode: always fall back, root built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
// Only fall back if notBefore < 23 August 2016
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
|
||||
info("current mode: fall back for notBefore < August 23, 2016, root " +
|
||||
"built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
info(
|
||||
"current mode: fall back for notBefore < August 23, 2016, root " +
|
||||
"built-in"
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
// Only fall back if notBefore < 23 August 2015
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
|
||||
info("current mode: fall back for notBefore < August 23, 2015, root " +
|
||||
"built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess);
|
||||
info(
|
||||
"current mode: fall back for notBefore < August 23, 2015, root " +
|
||||
"built-in"
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
// Never fall back.
|
||||
Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
|
||||
info("current mode: never fall back, root built-in");
|
||||
await checkCertOn25August2016(certFromFile("no-san-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("no-san-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("no-san-older"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("no-san-older"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-recent"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-old"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("san-contains-no-hostnames-older"),
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,74 +3,110 @@
|
|||
do_get_profile();
|
||||
|
||||
const { Utils } = ChromeUtils.import("resource://services-settings/Utils.jsm");
|
||||
const { RemoteSettings } = ChromeUtils.import("resource://services-settings/remote-settings.js");
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import("resource://gre/modules/psm/RemoteSecuritySettings.jsm");
|
||||
const { RemoteSettings } = ChromeUtils.import(
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import(
|
||||
"resource://gre/modules/psm/RemoteSecuritySettings.jsm"
|
||||
);
|
||||
const { OneCRLBlocklistClient } = RemoteSecuritySettings.init();
|
||||
|
||||
const global = this;
|
||||
|
||||
add_task(async function test_uses_a_custom_signer() {
|
||||
Assert.notEqual(OneCRLBlocklistClient.signerName, RemoteSettings("not-specified").signerName);
|
||||
Assert.notEqual(
|
||||
OneCRLBlocklistClient.signerName,
|
||||
RemoteSettings("not-specified").signerName
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_has_initial_dump() {
|
||||
Assert.ok(await Utils.hasLocalDump(OneCRLBlocklistClient.bucketName, OneCRLBlocklistClient.collectionName));
|
||||
Assert.ok(
|
||||
await Utils.hasLocalDump(
|
||||
OneCRLBlocklistClient.bucketName,
|
||||
OneCRLBlocklistClient.collectionName
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_default_jexl_filter_is_used() {
|
||||
Assert.deepEqual(OneCRLBlocklistClient.filterFunc, RemoteSettings("not-specified").filterFunc);
|
||||
Assert.deepEqual(
|
||||
OneCRLBlocklistClient.filterFunc,
|
||||
RemoteSettings("not-specified").filterFunc
|
||||
);
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_revocations_are_updated_on_sync_with_cert_storage() {
|
||||
const certList = Cc["@mozilla.org/security/certstorage;1"]
|
||||
.getService(Ci.nsICertStorage);
|
||||
const has_revocations = () => new Promise((resolve) => {
|
||||
certList.hasPriorData(Ci.nsICertStorage.DATA_TYPE_REVOCATION, (rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
return resolve(hasPriorData);
|
||||
}
|
||||
return resolve(false);
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_revocations_are_updated_on_sync_with_cert_storage() {
|
||||
const certList = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
const has_revocations = () =>
|
||||
new Promise(resolve => {
|
||||
certList.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_REVOCATION,
|
||||
(rv, hasPriorData) => {
|
||||
if (rv == Cr.NS_OK) {
|
||||
return resolve(hasPriorData);
|
||||
}
|
||||
return resolve(false);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Assert.ok(!(await has_revocations()));
|
||||
|
||||
await OneCRLBlocklistClient.emit("sync", {
|
||||
data: {
|
||||
current: [],
|
||||
created: [
|
||||
{
|
||||
issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
|
||||
serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
|
||||
},
|
||||
],
|
||||
updated: [],
|
||||
deleted: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Assert.ok(!(await has_revocations()));
|
||||
Assert.ok(await has_revocations());
|
||||
}
|
||||
);
|
||||
|
||||
await OneCRLBlocklistClient.emit("sync", { data: {
|
||||
current: [],
|
||||
created: [{
|
||||
issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
|
||||
serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
|
||||
}],
|
||||
updated: [],
|
||||
deleted: [],
|
||||
}});
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_revocations_are_updated_on_sync() {
|
||||
const profile = do_get_profile();
|
||||
const revocations = profile.clone();
|
||||
revocations.append("revocations.txt");
|
||||
const before = revocations.exists() ? revocations.lastModifiedTime : null;
|
||||
|
||||
Assert.ok(await has_revocations());
|
||||
});
|
||||
await OneCRLBlocklistClient.emit("sync", {
|
||||
data: {
|
||||
current: [
|
||||
{
|
||||
issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
|
||||
serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
|
||||
},
|
||||
],
|
||||
deleted: [],
|
||||
updated: [],
|
||||
created: [
|
||||
{
|
||||
issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
|
||||
serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_revocations_are_updated_on_sync() {
|
||||
const profile = do_get_profile();
|
||||
const revocations = profile.clone();
|
||||
revocations.append("revocations.txt");
|
||||
const before = revocations.exists() ? revocations.lastModifiedTime : null;
|
||||
|
||||
await OneCRLBlocklistClient.emit("sync", { data: {
|
||||
current: [{
|
||||
issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
|
||||
serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
|
||||
}],
|
||||
deleted: [],
|
||||
updated: [],
|
||||
created: [{
|
||||
issuerName: "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=",
|
||||
serialNumber: "a0X7/7DlTaedpgrIJg25iBPOkIM=",
|
||||
}],
|
||||
}});
|
||||
|
||||
const after = revocations.lastModifiedTime;
|
||||
Assert.notEqual(before, after, "revocation file was modified.");
|
||||
});
|
||||
const after = revocations.lastModifiedTime;
|
||||
Assert.notEqual(before, after, "revocation file was modified.");
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
"use strict";
|
||||
|
||||
const { Utils } = ChromeUtils.import("resource://services-settings/Utils.jsm");
|
||||
const { RemoteSettings } = ChromeUtils.import("resource://services-settings/remote-settings.js");
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import("resource://gre/modules/psm/RemoteSecuritySettings.jsm");
|
||||
const { RemoteSettings } = ChromeUtils.import(
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import(
|
||||
"resource://gre/modules/psm/RemoteSecuritySettings.jsm"
|
||||
);
|
||||
|
||||
const sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
const sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
|
||||
const { PinningBlocklistClient } = RemoteSecuritySettings.init();
|
||||
|
||||
|
||||
add_task(async function test_uses_a_custom_signer() {
|
||||
Assert.notEqual(PinningBlocklistClient.signerName, RemoteSettings("not-specified").signerName);
|
||||
Assert.notEqual(
|
||||
PinningBlocklistClient.signerName,
|
||||
RemoteSettings("not-specified").signerName
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_pinning_has_initial_dump() {
|
||||
|
|
@ -19,42 +26,84 @@ add_task(async function test_pinning_has_initial_dump() {
|
|||
// Skip test: we don't ship pinning dumps on Android (see package-manifest).
|
||||
return;
|
||||
}
|
||||
Assert.ok(await Utils.hasLocalDump(PinningBlocklistClient.bucketName, PinningBlocklistClient.collectionName));
|
||||
Assert.ok(
|
||||
await Utils.hasLocalDump(
|
||||
PinningBlocklistClient.bucketName,
|
||||
PinningBlocklistClient.collectionName
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_default_jexl_filter_is_used() {
|
||||
Assert.deepEqual(PinningBlocklistClient.filterFunc, RemoteSettings("not-specified").filterFunc);
|
||||
Assert.deepEqual(
|
||||
PinningBlocklistClient.filterFunc,
|
||||
RemoteSettings("not-specified").filterFunc
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_no_pins_by_default() {
|
||||
// ensure our pins are all missing before we start
|
||||
ok(!sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://one.example.com"), 0));
|
||||
ok(!sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://two.example.com"), 0));
|
||||
ok(!sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://three.example.com"), 0));
|
||||
ok(!sss.isSecureURI(sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://four.example.com"), 0));
|
||||
ok(!sss.isSecureURI(sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://five.example.com"), 0));
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://one.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://two.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://three.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://four.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://five.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_simple_pin_domain() {
|
||||
const current = [{
|
||||
"pinType": "KeyPin",
|
||||
"hostName": "one.example.com",
|
||||
"includeSubdomains": false,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
"pins": ["cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="],
|
||||
"versions": [Services.appinfo.version],
|
||||
}];
|
||||
await PinningBlocklistClient.emit("sync", { data: { current }});
|
||||
const current = [
|
||||
{
|
||||
pinType: "KeyPin",
|
||||
hostName: "one.example.com",
|
||||
includeSubdomains: false,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
pins: [
|
||||
"cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=",
|
||||
],
|
||||
versions: [Services.appinfo.version],
|
||||
},
|
||||
];
|
||||
await PinningBlocklistClient.emit("sync", { data: { current } });
|
||||
|
||||
// check that a pin exists for one.example.com
|
||||
ok(sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://one.example.com"), 0));
|
||||
ok(
|
||||
sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://one.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_existing_entries_are_erased() {
|
||||
|
|
@ -62,106 +111,166 @@ add_task(async function test_existing_entries_are_erased() {
|
|||
await PinningBlocklistClient.emit("sync", { data: { current } });
|
||||
|
||||
// check that no pin exists for one.example.com
|
||||
ok(!sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://one.example.com"), 0));
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://one.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_multiple_entries() {
|
||||
const current = [{
|
||||
"pinType": "KeyPin",
|
||||
"hostName": "two.example.com",
|
||||
"includeSubdomains": false,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
"pins": ["cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="],
|
||||
"versions": [Services.appinfo.version],
|
||||
}, {
|
||||
"pinType": "KeyPin",
|
||||
"hostName": "three.example.com",
|
||||
"includeSubdomains": false,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
"pins": ["cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="],
|
||||
"versions": [Services.appinfo.version, "some other version that won't match"],
|
||||
}, {
|
||||
"pinType": "KeyPin",
|
||||
"hostName": "four.example.com",
|
||||
"includeSubdomains": false,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
"pins": ["cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="],
|
||||
"versions": ["some version that won't match"],
|
||||
}, {
|
||||
"pinType": "STSPin",
|
||||
"hostName": "five.example.com",
|
||||
"includeSubdomains": false,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
"versions": [Services.appinfo.version, "some version that won't match"],
|
||||
const current = [
|
||||
{
|
||||
pinType: "KeyPin",
|
||||
hostName: "two.example.com",
|
||||
includeSubdomains: false,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
pins: [
|
||||
"cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=",
|
||||
],
|
||||
versions: [Services.appinfo.version],
|
||||
},
|
||||
{
|
||||
pinType: "KeyPin",
|
||||
hostName: "three.example.com",
|
||||
includeSubdomains: false,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
pins: [
|
||||
"cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=",
|
||||
],
|
||||
versions: [
|
||||
Services.appinfo.version,
|
||||
"some other version that won't match",
|
||||
],
|
||||
},
|
||||
{
|
||||
pinType: "KeyPin",
|
||||
hostName: "four.example.com",
|
||||
includeSubdomains: false,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
pins: [
|
||||
"cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
|
||||
"M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=",
|
||||
],
|
||||
versions: ["some version that won't match"],
|
||||
},
|
||||
{
|
||||
pinType: "STSPin",
|
||||
hostName: "five.example.com",
|
||||
includeSubdomains: false,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
versions: [Services.appinfo.version, "some version that won't match"],
|
||||
},
|
||||
];
|
||||
await PinningBlocklistClient.emit("sync", { data: { current }});
|
||||
await PinningBlocklistClient.emit("sync", { data: { current } });
|
||||
|
||||
// check that a pin exists for two.example.com and three.example.com
|
||||
ok(sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://two.example.com"), 0));
|
||||
ok(sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://three.example.com"), 0));
|
||||
ok(
|
||||
sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://two.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
ok(
|
||||
sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://three.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
// check that a pin does not exist for four.example.com - it's in the
|
||||
// collection but the version should not match
|
||||
ok(!sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://four.example.com"), 0));
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://four.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
// Check that the HSTS preload added to the collection works...
|
||||
ok(sss.isSecureURI(sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://five.example.com"), 0));
|
||||
ok(
|
||||
sss.isSecureURI(
|
||||
sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://five.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
// // ...and that includeSubdomains is honored
|
||||
ok(!sss.isSecureURI(sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://subdomain.five.example.com"),
|
||||
0));
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://subdomain.five.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
|
||||
// Overwrite existing entries.
|
||||
current[current.length - 1].includeSubdomains = true;
|
||||
await PinningBlocklistClient.emit("sync", { data: { current } });
|
||||
// The STS entry for five.example.com now has includeSubdomains set;
|
||||
// ensure that the new includeSubdomains value is honored.
|
||||
ok(sss.isSecureURI(sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://subdomain.five.example.com"),
|
||||
0));
|
||||
ok(
|
||||
sss.isSecureURI(
|
||||
sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://subdomain.five.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_bad_entries() {
|
||||
const current = [{
|
||||
"irrelevant": "this entry looks nothing whatsoever like a pin preload",
|
||||
"pinType": "KeyPin",
|
||||
}, {
|
||||
"irrelevant": "this entry has data of the wrong type",
|
||||
"pinType": "KeyPin",
|
||||
"hostName": 3,
|
||||
"includeSubdomains": "nonsense",
|
||||
"expires": "more nonsense",
|
||||
"pins": [1, 2, 3, 4],
|
||||
}, {
|
||||
"irrelevant": "this entry is missing the actual pins",
|
||||
"pinType": "KeyPin",
|
||||
"hostName": "missingpins.example.com",
|
||||
"includeSubdomains": false,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
"versions": [Services.appinfo.version],
|
||||
}, {
|
||||
"pinType": "STSPin",
|
||||
"hostName": "five.example.com",
|
||||
"includeSubdomains": true,
|
||||
"expires": new Date().getTime() + 1000000,
|
||||
const current = [
|
||||
{
|
||||
irrelevant: "this entry looks nothing whatsoever like a pin preload",
|
||||
pinType: "KeyPin",
|
||||
},
|
||||
{
|
||||
irrelevant: "this entry has data of the wrong type",
|
||||
pinType: "KeyPin",
|
||||
hostName: 3,
|
||||
includeSubdomains: "nonsense",
|
||||
expires: "more nonsense",
|
||||
pins: [1, 2, 3, 4],
|
||||
},
|
||||
{
|
||||
irrelevant: "this entry is missing the actual pins",
|
||||
pinType: "KeyPin",
|
||||
hostName: "missingpins.example.com",
|
||||
includeSubdomains: false,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
versions: [Services.appinfo.version],
|
||||
},
|
||||
{
|
||||
pinType: "STSPin",
|
||||
hostName: "five.example.com",
|
||||
includeSubdomains: true,
|
||||
expires: new Date().getTime() + 1000000,
|
||||
}, // missing versions.
|
||||
];
|
||||
// The event listener will catch any error, and won't throw.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1554939
|
||||
await PinningBlocklistClient.emit("sync", { data: { current }});
|
||||
await PinningBlocklistClient.emit("sync", { data: { current } });
|
||||
|
||||
ok(!sss.isSecureURI(sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://missingpins.example.com"), 0));
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HPKP,
|
||||
Services.io.newURI("https://missingpins.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
|
||||
// Check that the HSTS preload overwrites existing entries...
|
||||
// Version field is missing.
|
||||
ok(!sss.isSecureURI(sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://five.example.com"), 0));
|
||||
ok(
|
||||
!sss.isSecureURI(
|
||||
sss.HEADER_HSTS,
|
||||
Services.io.newURI("https://five.example.com"),
|
||||
0
|
||||
)
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,18 +22,24 @@ function run_test() {
|
|||
let secmodDBFile = do_get_file(`test_broken_fips/${secmodDBName}`);
|
||||
secmodDBFile.copyTo(profile, secmodDBName);
|
||||
|
||||
let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
|
||||
.getService(Ci.nsIPKCS11ModuleDB);
|
||||
let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
|
||||
Ci.nsIPKCS11ModuleDB
|
||||
);
|
||||
ok(!moduleDB.isFIPSEnabled, "FIPS should not be enabled");
|
||||
|
||||
let sdr = Cc["@mozilla.org/security/sdr;1"]
|
||||
.getService(Ci.nsISecretDecoderRing);
|
||||
let sdr = Cc["@mozilla.org/security/sdr;1"].getService(
|
||||
Ci.nsISecretDecoderRing
|
||||
);
|
||||
|
||||
const encrypted = "MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECGeDHwVfyFqzBBAYvqMq/kDMsrARVNdC1C8d";
|
||||
const encrypted =
|
||||
"MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECGeDHwVfyFqzBBAYvqMq/kDMsrARVNdC1C8d";
|
||||
const expectedResult = "password";
|
||||
let decrypted = sdr.decryptString(encrypted);
|
||||
equal(decrypted, expectedResult,
|
||||
"decrypted ciphertext should match expected plaintext");
|
||||
equal(
|
||||
decrypted,
|
||||
expectedResult,
|
||||
"decrypted ciphertext should match expected plaintext"
|
||||
);
|
||||
|
||||
let secmodDBFileFIPS = do_get_profile();
|
||||
secmodDBFileFIPS.append(`${secmodDBName}.fips`);
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const PKCS12_FILE = "test_certDB_import/cert_from_windows.pfx";
|
||||
const CERT_COMMON_NAME = "test_cert_from_windows";
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const PKCS12_FILE = "test_certDB_import/cert_from_windows.pfx";
|
||||
const CERT_COMMON_NAME = "test_cert_from_windows";
|
||||
|
|
@ -30,9 +31,11 @@ var gPrompt = {
|
|||
},
|
||||
|
||||
promptPassword(dialogTitle, text, password, checkMsg, checkValue) {
|
||||
equal(text,
|
||||
"Please enter your master password.",
|
||||
"password prompt text should be as expected");
|
||||
equal(
|
||||
text,
|
||||
"Please enter your master password.",
|
||||
"password prompt text should be as expected"
|
||||
);
|
||||
equal(checkMsg, null, "checkMsg should be null");
|
||||
password.value = this.password;
|
||||
return this.clickOk;
|
||||
|
|
@ -54,16 +57,19 @@ function findCertByCommonName(commonName) {
|
|||
}
|
||||
|
||||
function run_test() {
|
||||
let promptFactoryCID =
|
||||
MockRegistrar.register("@mozilla.org/prompter;1", gPromptFactory);
|
||||
let promptFactoryCID = MockRegistrar.register(
|
||||
"@mozilla.org/prompter;1",
|
||||
gPromptFactory
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(promptFactoryCID);
|
||||
});
|
||||
|
||||
// Set a master password.
|
||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
|
||||
.getService(Ci.nsIPK11TokenDB);
|
||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(
|
||||
Ci.nsIPK11TokenDB
|
||||
);
|
||||
let token = tokenDB.getInternalKeyToken();
|
||||
token.initPassword("password");
|
||||
token.logoutSimple();
|
||||
|
|
@ -101,7 +107,11 @@ function run_test() {
|
|||
output2.append("output2.p12");
|
||||
ok(!output2.exists(), "output2 shouldn't exist before exporting PKCS12 file");
|
||||
errorCode = gCertDB.exportPKCS12File(output, [cert], TEST_CERT_PASSWORD);
|
||||
equal(errorCode, Ci.nsIX509CertDB.ERROR_PKCS12_BACKUP_FAILED, "cert should not export");
|
||||
equal(
|
||||
errorCode,
|
||||
Ci.nsIX509CertDB.ERROR_PKCS12_BACKUP_FAILED,
|
||||
"cert should not export"
|
||||
);
|
||||
|
||||
ok(!output2.exists(), "output2 shouldn't exist after failing to export");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const CA_CERT_COMMON_NAME = "importedCA";
|
||||
const TEST_EMAIL_ADDRESS = "test@example.com";
|
||||
|
|
@ -19,8 +20,11 @@ let gCACertImportDialogCount = 0;
|
|||
const gCertificateDialogs = {
|
||||
confirmDownloadCACert: (ctx, cert, trust) => {
|
||||
gCACertImportDialogCount++;
|
||||
equal(cert.commonName, CA_CERT_COMMON_NAME,
|
||||
"CA cert to import should have the correct CN");
|
||||
equal(
|
||||
cert.commonName,
|
||||
CA_CERT_COMMON_NAME,
|
||||
"CA cert to import should have the correct CN"
|
||||
);
|
||||
trust.value = Ci.nsIX509CertDB.TRUSTED_EMAIL;
|
||||
return true;
|
||||
},
|
||||
|
|
@ -83,41 +87,82 @@ function findCertByEmailAddress(emailAddress) {
|
|||
|
||||
function testImportCACert() {
|
||||
// Sanity check the CA cert is missing.
|
||||
equal(findCertByCommonName(CA_CERT_COMMON_NAME), null,
|
||||
"CA cert should not be in the database before import");
|
||||
equal(
|
||||
findCertByCommonName(CA_CERT_COMMON_NAME),
|
||||
null,
|
||||
"CA cert should not be in the database before import"
|
||||
);
|
||||
|
||||
// Import and check for success.
|
||||
let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem");
|
||||
gCertDB.importCertificates(caArray, caArray.length, Ci.nsIX509Cert.CA_CERT,
|
||||
gInterfaceRequestor);
|
||||
equal(gCACertImportDialogCount, 1,
|
||||
"Confirmation dialog for the CA cert should only be shown once");
|
||||
gCertDB.importCertificates(
|
||||
caArray,
|
||||
caArray.length,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
gInterfaceRequestor
|
||||
);
|
||||
equal(
|
||||
gCACertImportDialogCount,
|
||||
1,
|
||||
"Confirmation dialog for the CA cert should only be shown once"
|
||||
);
|
||||
|
||||
let caCert = findCertByCommonName(CA_CERT_COMMON_NAME);
|
||||
notEqual(caCert, null, "CA cert should now be found in the database");
|
||||
ok(gCertDB.isCertTrusted(caCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL),
|
||||
"CA cert should be trusted for e-mail");
|
||||
ok(
|
||||
gCertDB.isCertTrusted(
|
||||
caCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
),
|
||||
"CA cert should be trusted for e-mail"
|
||||
);
|
||||
}
|
||||
|
||||
function testImportEmptyCertPackage() {
|
||||
// Because this is an empty cert package, nothing will be imported. We know it succeeded if no errors are thrown.
|
||||
let byteArray = [ 0x30, 0x0f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, 0x05, 0xa0, 0x02, 0x30, 0x00 ];
|
||||
gCertDB.importCertificates(byteArray, byteArray.length, Ci.nsIX509Cert.CA_CERT,
|
||||
gInterfaceRequestor);
|
||||
let byteArray = [
|
||||
0x30,
|
||||
0x0f,
|
||||
0x06,
|
||||
0x09,
|
||||
0x60,
|
||||
0x86,
|
||||
0x48,
|
||||
0x01,
|
||||
0x86,
|
||||
0xf8,
|
||||
0x42,
|
||||
0x02,
|
||||
0x05,
|
||||
0xa0,
|
||||
0x02,
|
||||
0x30,
|
||||
0x00,
|
||||
];
|
||||
gCertDB.importCertificates(
|
||||
byteArray,
|
||||
byteArray.length,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
gInterfaceRequestor
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
let certificateDialogsCID =
|
||||
MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
|
||||
gCertificateDialogs);
|
||||
let certificateDialogsCID = MockRegistrar.register(
|
||||
"@mozilla.org/nsCertificateDialogs;1",
|
||||
gCertificateDialogs
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(certificateDialogsCID);
|
||||
});
|
||||
|
||||
// Sanity check the e-mail cert is missing.
|
||||
equal(findCertByEmailAddress(TEST_EMAIL_ADDRESS), null,
|
||||
"E-mail cert should not be in the database before import");
|
||||
equal(
|
||||
findCertByEmailAddress(TEST_EMAIL_ADDRESS),
|
||||
null,
|
||||
"E-mail cert should not be in the database before import"
|
||||
);
|
||||
|
||||
// Import the CA cert so that the e-mail import succeeds.
|
||||
testImportCACert();
|
||||
|
|
@ -125,13 +170,19 @@ function run_test() {
|
|||
|
||||
// Import the e-mail cert and check for success.
|
||||
let emailArray = getCertAsByteArray("test_certDB_import/emailEE.pem");
|
||||
gCertDB.importEmailCertificate(emailArray, emailArray.length,
|
||||
gInterfaceRequestor);
|
||||
gCertDB.importEmailCertificate(
|
||||
emailArray,
|
||||
emailArray.length,
|
||||
gInterfaceRequestor
|
||||
);
|
||||
let emailCert = findCertByEmailAddress(TEST_EMAIL_ADDRESS);
|
||||
notEqual(emailCert, null, "E-mail cert should now be found in the database");
|
||||
let bundle =
|
||||
Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
|
||||
equal(emailCert.tokenName,
|
||||
bundle.GetStringFromName("PrivateTokenDescription"),
|
||||
"cert's tokenName should be the expected localized value");
|
||||
let bundle = Services.strings.createBundle(
|
||||
"chrome://pipnss/locale/pipnss.properties"
|
||||
);
|
||||
equal(
|
||||
emailCert.tokenName,
|
||||
bundle.GetStringFromName("PrivateTokenDescription"),
|
||||
"cert's tokenName should be the expected localized value"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const PKCS12_FILE = "test_certDB_import/cert_from_windows.pfx";
|
||||
const PKCS12_FILE_EMPTY_PASS =
|
||||
"test_certDB_import/cert_from_windows_emptypass.pfx";
|
||||
"test_certDB_import/cert_from_windows_emptypass.pfx";
|
||||
const PKCS12_FILE_NO_PASS = "test_certDB_import/cert_from_windows_nopass.pfx";
|
||||
const CERT_COMMON_NAME = "test_cert_from_windows";
|
||||
const TEST_CERT_PASSWORD = "黒い";
|
||||
|
|
@ -89,8 +90,10 @@ function doesCertExist(commonName) {
|
|||
function runOneTestcase(testcase) {
|
||||
info(`running ${testcase.name}`);
|
||||
if (testcase.checkCertExist) {
|
||||
ok(!doesCertExist(CERT_COMMON_NAME),
|
||||
"cert should not be in the database before import");
|
||||
ok(
|
||||
!doesCertExist(CERT_COMMON_NAME),
|
||||
"cert should not be in the database before import"
|
||||
);
|
||||
}
|
||||
|
||||
// Import and check for failure.
|
||||
|
|
@ -100,8 +103,11 @@ function runOneTestcase(testcase) {
|
|||
gCurrentTestcase = testcase;
|
||||
let errorCode = gCertDB.importPKCS12File(certFile, testcase.passwordToUse);
|
||||
equal(errorCode, testcase.errorCode, `verifying error code`);
|
||||
equal(doesCertExist(CERT_COMMON_NAME), testcase.successExpected,
|
||||
`cert should${testcase.successExpected ? "" : " not"} be found now`);
|
||||
equal(
|
||||
doesCertExist(CERT_COMMON_NAME),
|
||||
testcase.successExpected,
|
||||
`cert should${testcase.successExpected ? "" : " not"} be found now`
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const CA_CERT_COMMON_NAME = "importedCA";
|
||||
|
||||
|
|
@ -19,8 +20,11 @@ let gCACertImportDialogCount = 0;
|
|||
const gCertificateDialogs = {
|
||||
confirmDownloadCACert: (ctx, cert, trust) => {
|
||||
gCACertImportDialogCount++;
|
||||
equal(cert.commonName, CA_CERT_COMMON_NAME,
|
||||
"CA cert to import should have the correct CN");
|
||||
equal(
|
||||
cert.commonName,
|
||||
CA_CERT_COMMON_NAME,
|
||||
"CA cert to import should have the correct CN"
|
||||
);
|
||||
trust.value = Ci.nsIX509CertDB.TRUSTED_EMAIL;
|
||||
return true;
|
||||
},
|
||||
|
|
@ -45,12 +49,15 @@ var gMockPrompter = {
|
|||
// how objects get wrapped when going across xpcom boundaries.
|
||||
promptPassword(dialogTitle, text, password, checkMsg, checkValue) {
|
||||
this.numPrompts++;
|
||||
if (this.numPrompts > 1) { // don't keep retrying a bad password
|
||||
if (this.numPrompts > 1) {
|
||||
// don't keep retrying a bad password
|
||||
return false;
|
||||
}
|
||||
equal(text,
|
||||
"Please enter your master password.",
|
||||
"password prompt text should be as expected");
|
||||
equal(
|
||||
text,
|
||||
"Please enter your master password.",
|
||||
"password prompt text should be as expected"
|
||||
);
|
||||
equal(checkMsg, null, "checkMsg should be null");
|
||||
ok(this.passwordToTry, "passwordToTry should be non-null");
|
||||
password.value = this.passwordToTry;
|
||||
|
|
@ -91,34 +98,51 @@ function findCertByCommonName(commonName) {
|
|||
}
|
||||
|
||||
function run_test() {
|
||||
let certificateDialogsCID =
|
||||
MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
|
||||
gCertificateDialogs);
|
||||
let certificateDialogsCID = MockRegistrar.register(
|
||||
"@mozilla.org/nsCertificateDialogs;1",
|
||||
gCertificateDialogs
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(certificateDialogsCID);
|
||||
});
|
||||
|
||||
// Set a master password.
|
||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
|
||||
.getService(Ci.nsIPK11TokenDB);
|
||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(
|
||||
Ci.nsIPK11TokenDB
|
||||
);
|
||||
let token = tokenDB.getInternalKeyToken();
|
||||
token.initPassword("password");
|
||||
token.logoutSimple();
|
||||
|
||||
// Sanity check the CA cert is missing.
|
||||
equal(findCertByCommonName(CA_CERT_COMMON_NAME), null,
|
||||
"CA cert should not be in the database before import");
|
||||
equal(
|
||||
findCertByCommonName(CA_CERT_COMMON_NAME),
|
||||
null,
|
||||
"CA cert should not be in the database before import"
|
||||
);
|
||||
|
||||
// Import and check for success.
|
||||
let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem");
|
||||
gCertDB.importCertificates(caArray, caArray.length, Ci.nsIX509Cert.CA_CERT,
|
||||
gMockPrompter);
|
||||
equal(gCACertImportDialogCount, 1,
|
||||
"Confirmation dialog for the CA cert should only be shown once");
|
||||
gCertDB.importCertificates(
|
||||
caArray,
|
||||
caArray.length,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
gMockPrompter
|
||||
);
|
||||
equal(
|
||||
gCACertImportDialogCount,
|
||||
1,
|
||||
"Confirmation dialog for the CA cert should only be shown once"
|
||||
);
|
||||
|
||||
let caCert = findCertByCommonName(CA_CERT_COMMON_NAME);
|
||||
notEqual(caCert, null, "CA cert should now be found in the database");
|
||||
ok(gCertDB.isCertTrusted(caCert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL),
|
||||
"CA cert should be trusted for e-mail");
|
||||
ok(
|
||||
gCertDB.isCertTrusted(
|
||||
caCert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
),
|
||||
"CA cert should be trusted for e-mail"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,15 +10,21 @@ function test_cert_equals() {
|
|||
let certB = constructCertFromFile("bad_certs/default-ee.pem");
|
||||
let certC = constructCertFromFile("bad_certs/expired-ee.pem");
|
||||
|
||||
ok(certA != certB,
|
||||
"Cert objects constructed from the same file should not be equal" +
|
||||
" according to the equality operators");
|
||||
ok(certA.equals(certB),
|
||||
"equals() on cert objects constructed from the same cert file should" +
|
||||
" return true");
|
||||
ok(!certA.equals(certC),
|
||||
"equals() on cert objects constructed from files for different certs" +
|
||||
" should return false");
|
||||
ok(
|
||||
certA != certB,
|
||||
"Cert objects constructed from the same file should not be equal" +
|
||||
" according to the equality operators"
|
||||
);
|
||||
ok(
|
||||
certA.equals(certB),
|
||||
"equals() on cert objects constructed from the same cert file should" +
|
||||
" return true"
|
||||
);
|
||||
ok(
|
||||
!certA.equals(certC),
|
||||
"equals() on cert objects constructed from files for different certs" +
|
||||
" should return false"
|
||||
);
|
||||
}
|
||||
|
||||
function test_bad_cert_list_serialization() {
|
||||
|
|
@ -32,30 +38,39 @@ function test_bad_cert_list_serialization() {
|
|||
const badCertListSerialization =
|
||||
"lZ+xZWUXSH+rm9iRO+UxlwAAAAAAAAAAwAAAAAAAAEYAAAABlZ+xZWUXSH+rm9iRO+UxlwAAAAAA" +
|
||||
"AAAAwAAAAAAAAEYAAAAA";
|
||||
let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
throws(() => serHelper.deserializeObject(badCertListSerialization),
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"deserializing a bogus nsIX509CertList should throw NS_ERROR_UNEXPECTED");
|
||||
let serHelper = Cc["@mozilla.org/network/serialization-helper;1"].getService(
|
||||
Ci.nsISerializationHelper
|
||||
);
|
||||
throws(
|
||||
() => serHelper.deserializeObject(badCertListSerialization),
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"deserializing a bogus nsIX509CertList should throw NS_ERROR_UNEXPECTED"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cert_list_serialization() {
|
||||
let certList = build_cert_chain(["default-ee", "expired-ee"]);
|
||||
|
||||
throws(() => certList.addCert(null), /NS_ERROR_ILLEGAL_VALUE/,
|
||||
"trying to add a null cert to an nsIX509CertList should throw");
|
||||
throws(
|
||||
() => certList.addCert(null),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"trying to add a null cert to an nsIX509CertList should throw"
|
||||
);
|
||||
|
||||
// Serialize the cert list to a string
|
||||
let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serHelper = Cc["@mozilla.org/network/serialization-helper;1"].getService(
|
||||
Ci.nsISerializationHelper
|
||||
);
|
||||
certList.QueryInterface(Ci.nsISerializable);
|
||||
let serialized = serHelper.serializeToString(certList);
|
||||
|
||||
// Deserialize from the string and compare to the original object
|
||||
let deserialized = serHelper.deserializeObject(serialized);
|
||||
deserialized.QueryInterface(Ci.nsIX509CertList);
|
||||
ok(certList.equals(deserialized),
|
||||
"Deserialized cert list should equal the original");
|
||||
ok(
|
||||
certList.equals(deserialized),
|
||||
"Deserialized cert list should equal the original"
|
||||
);
|
||||
}
|
||||
|
||||
// We hard-code the following certificates for the pkcs7 export tests so that we
|
||||
|
|
@ -170,10 +185,12 @@ rGFLvocT/kym6r8galxCJUo=
|
|||
-----END CERTIFICATE-----`;
|
||||
|
||||
function build_cert_list_from_pem_list(pemList) {
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"]
|
||||
.createInstance(Ci.nsIX509CertList);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"].createInstance(
|
||||
Ci.nsIX509CertList
|
||||
);
|
||||
for (let pem of pemList) {
|
||||
let cert = certdb.constructX509FromBase64(pemToBase64(pem));
|
||||
certList.addCert(cert);
|
||||
|
|
@ -221,10 +238,16 @@ function test_cert_pkcs7_export() {
|
|||
"3rXoimcdo6X3TK1SN2/64fGMyG/pwas+JXehbReUf4n1ewk84ADtb+ew8tRAKf/uxzKUj5t" +
|
||||
"/UgqDsnTWq5wUc5IJKwoHT41sQnNqPg12x4+WGWiAsWCpR/hKYHFGr7rb4JTGEPAJpWcv9W" +
|
||||
"tZYAvwT78a2xpHp5XNglj16IjWEukvJuU1WMQAAAAAAAAA=";
|
||||
let certListDefaultEE = build_cert_list_from_pem_list([gDefaultEEPEM, gTestCAPEM]);
|
||||
let certListDefaultEE = build_cert_list_from_pem_list([
|
||||
gDefaultEEPEM,
|
||||
gTestCAPEM,
|
||||
]);
|
||||
let pkcs7DefaultEE = certListDefaultEE.asPKCS7Blob();
|
||||
equal(btoa(pkcs7DefaultEE), expectedPKCS7ForDefaultEE,
|
||||
"PKCS7 export should work as expected for default-ee chain");
|
||||
equal(
|
||||
btoa(pkcs7DefaultEE),
|
||||
expectedPKCS7ForDefaultEE,
|
||||
"PKCS7 export should work as expected for default-ee chain"
|
||||
);
|
||||
|
||||
// This was generated by running BadCertServer locally on the bad_certs
|
||||
// directory and visiting:
|
||||
|
|
@ -251,10 +274,15 @@ function test_cert_pkcs7_export() {
|
|||
"Ztj/BxO9+7WP9+UyQYQ6lzUfK2WZH1+QIOerMV9ya/sSHdfUGJIE4h6YadQfE43CW2FITrw" +
|
||||
"gi0TmXdzzYbyhAaa97qvQ32Hu3qikiMfWSgVYxyT+nMMDTUWZZ7LgBJ2WaMTw1IkCXXOwXw" +
|
||||
"SIs5l4jWu+6txfBU53Q6WT39BPmHBOSTEAAAAAAAAA";
|
||||
let certListUnknownIssuer = build_cert_list_from_pem_list([gUnknownIssuerPEM]);
|
||||
let certListUnknownIssuer = build_cert_list_from_pem_list([
|
||||
gUnknownIssuerPEM,
|
||||
]);
|
||||
let pkcs7UnknownIssuer = certListUnknownIssuer.asPKCS7Blob();
|
||||
equal(btoa(pkcs7UnknownIssuer), expectedPKCS7ForUnknownIssuer,
|
||||
"PKCS7 export should work as expected for unknown issuer");
|
||||
equal(
|
||||
btoa(pkcs7UnknownIssuer),
|
||||
expectedPKCS7ForUnknownIssuer,
|
||||
"PKCS7 export should work as expected for unknown issuer"
|
||||
);
|
||||
|
||||
// This was generated by running OCSPStaplingServer locally on the ocsp_certs
|
||||
// directory and visiting:
|
||||
|
|
@ -307,30 +335,49 @@ function test_cert_pkcs7_export() {
|
|||
"8Rbmsxq67mI46n/ovmsEXQz1uDnJdIY0O/yCTclz6iklsENOsC4oM0uklISniuqi80WeKvO" +
|
||||
"UlYNL5JwCxYe2gtysfqCdBE+wRXVYVCdivceQBqRhCiT3GzkCKQFLqaDPj9wUG2zxtIZK5f" +
|
||||
"Fy2Q3ZKztjmXdiZNgoLE/Pqt61V+uGL+KyUfhbfP0em7dmrIAI7otsxAAAAAAAAAA==";
|
||||
let certListWithIntermediate = build_cert_list_from_pem_list(
|
||||
[gOCSPEEWithIntermediatePEM, gTestIntPEM, gTestCAPEM]);
|
||||
let certListWithIntermediate = build_cert_list_from_pem_list([
|
||||
gOCSPEEWithIntermediatePEM,
|
||||
gTestIntPEM,
|
||||
gTestCAPEM,
|
||||
]);
|
||||
let pkcs7WithIntermediate = certListWithIntermediate.asPKCS7Blob();
|
||||
equal(btoa(pkcs7WithIntermediate), expectedPKCS7WithIntermediate,
|
||||
"PKCS7 export should work as expected for chain with intermediate");
|
||||
equal(
|
||||
btoa(pkcs7WithIntermediate),
|
||||
expectedPKCS7WithIntermediate,
|
||||
"PKCS7 export should work as expected for chain with intermediate"
|
||||
);
|
||||
}
|
||||
|
||||
function test_security_info_serialization(securityInfo, expectedErrorCode) {
|
||||
// Serialize the securityInfo to a string
|
||||
let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serHelper = Cc["@mozilla.org/network/serialization-helper;1"].getService(
|
||||
Ci.nsISerializationHelper
|
||||
);
|
||||
let serialized = serHelper.serializeToString(securityInfo);
|
||||
|
||||
// Deserialize from the string and compare to the original object
|
||||
let deserialized = serHelper.deserializeObject(serialized);
|
||||
deserialized.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
equal(securityInfo.securityState, deserialized.securityState,
|
||||
"Original and deserialized security state should match");
|
||||
equal(securityInfo.errorMessage, deserialized.errorMessage,
|
||||
"Original and deserialized error message should match");
|
||||
equal(securityInfo.errorCode, expectedErrorCode,
|
||||
"Original and expected error code should match");
|
||||
equal(deserialized.errorCode, expectedErrorCode,
|
||||
"Deserialized and expected error code should match");
|
||||
equal(
|
||||
securityInfo.securityState,
|
||||
deserialized.securityState,
|
||||
"Original and deserialized security state should match"
|
||||
);
|
||||
equal(
|
||||
securityInfo.errorMessage,
|
||||
deserialized.errorMessage,
|
||||
"Original and deserialized error message should match"
|
||||
);
|
||||
equal(
|
||||
securityInfo.errorCode,
|
||||
expectedErrorCode,
|
||||
"Original and expected error code should match"
|
||||
);
|
||||
equal(
|
||||
deserialized.errorCode,
|
||||
expectedErrorCode,
|
||||
"Deserialized and expected error code should match"
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -362,12 +409,17 @@ function run_test() {
|
|||
// Test successful connection (failedCertChain should be null)
|
||||
add_connection_test(
|
||||
// re-use pinning certs (keeler)
|
||||
"good.include-subdomains.pinning.example.com", PRErrorCodeSuccess, null,
|
||||
"good.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
function withSecurityInfo(aTransportSecurityInfo) {
|
||||
aTransportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
test_security_info_serialization(aTransportSecurityInfo, 0);
|
||||
equal(aTransportSecurityInfo.failedCertChain, null,
|
||||
"failedCertChain for a successful connection should be null");
|
||||
equal(
|
||||
aTransportSecurityInfo.failedCertChain,
|
||||
null,
|
||||
"failedCertChain for a successful connection should be null"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -378,14 +430,22 @@ function run_test() {
|
|||
null,
|
||||
function withSecurityInfo(securityInfo) {
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
test_security_info_serialization(securityInfo, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
notEqual(securityInfo.failedCertChain, null,
|
||||
"failedCertChain should not be null for an overrideable" +
|
||||
" connection failure");
|
||||
test_security_info_serialization(
|
||||
securityInfo,
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE
|
||||
);
|
||||
notEqual(
|
||||
securityInfo.failedCertChain,
|
||||
null,
|
||||
"failedCertChain should not be null for an overrideable" +
|
||||
" connection failure"
|
||||
);
|
||||
let originalCertChain = build_cert_chain(["expired-ee", "test-ca"]);
|
||||
ok(originalCertChain.equals(securityInfo.failedCertChain),
|
||||
"failedCertChain should equal the original cert chain for an" +
|
||||
" overrideable connection failure");
|
||||
ok(
|
||||
originalCertChain.equals(securityInfo.failedCertChain),
|
||||
"failedCertChain should equal the original cert chain for an" +
|
||||
" overrideable connection failure"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -397,13 +457,18 @@ function run_test() {
|
|||
function withSecurityInfo(securityInfo) {
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
test_security_info_serialization(securityInfo, SEC_ERROR_UNKNOWN_ISSUER);
|
||||
notEqual(securityInfo.failedCertChain, null,
|
||||
"failedCertChain should not be null for an overrideable" +
|
||||
" connection failure");
|
||||
notEqual(
|
||||
securityInfo.failedCertChain,
|
||||
null,
|
||||
"failedCertChain should not be null for an overrideable" +
|
||||
" connection failure"
|
||||
);
|
||||
let originalCertChain = build_cert_chain(["unknownissuer"]);
|
||||
ok(originalCertChain.equals(securityInfo.failedCertChain),
|
||||
"failedCertChain should equal the original cert chain for an" +
|
||||
" overrideable connection failure");
|
||||
ok(
|
||||
originalCertChain.equals(securityInfo.failedCertChain),
|
||||
"failedCertChain should equal the original cert chain for an" +
|
||||
" overrideable connection failure"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -414,14 +479,25 @@ function run_test() {
|
|||
null,
|
||||
function withSecurityInfo(securityInfo) {
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
test_security_info_serialization(securityInfo, SEC_ERROR_INADEQUATE_KEY_USAGE);
|
||||
notEqual(securityInfo.failedCertChain, null,
|
||||
"failedCertChain should not be null for a non-overrideable" +
|
||||
" connection failure");
|
||||
let originalCertChain = build_cert_chain(["inadequatekeyusage-ee", "test-ca"]);
|
||||
ok(originalCertChain.equals(securityInfo.failedCertChain),
|
||||
"failedCertChain should equal the original cert chain for a" +
|
||||
" non-overrideable connection failure");
|
||||
test_security_info_serialization(
|
||||
securityInfo,
|
||||
SEC_ERROR_INADEQUATE_KEY_USAGE
|
||||
);
|
||||
notEqual(
|
||||
securityInfo.failedCertChain,
|
||||
null,
|
||||
"failedCertChain should not be null for a non-overrideable" +
|
||||
" connection failure"
|
||||
);
|
||||
let originalCertChain = build_cert_chain([
|
||||
"inadequatekeyusage-ee",
|
||||
"test-ca",
|
||||
]);
|
||||
ok(
|
||||
originalCertChain.equals(securityInfo.failedCertChain),
|
||||
"failedCertChain should equal the original cert chain for a" +
|
||||
" non-overrideable connection failure"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ function encodeCommonNameAsBytes(commonName) {
|
|||
// SEQUENCE must be 127. Everything not in the contents of the common name
|
||||
// will take up 11 bytes, so the value of the common name itself can be at
|
||||
// most 116 bytes.
|
||||
ok(commonName.length <= 116,
|
||||
"test assumption: common name can't be longer than 116 bytes (makes " +
|
||||
"DER encoding easier)");
|
||||
let commonNameOIDBytes = [ 0x06, 0x03, 0x55, 0x04, 0x03 ];
|
||||
let commonNameBytes = [ 0x0C, commonName.length ];
|
||||
ok(
|
||||
commonName.length <= 116,
|
||||
"test assumption: common name can't be longer than 116 bytes (makes " +
|
||||
"DER encoding easier)"
|
||||
);
|
||||
let commonNameOIDBytes = [0x06, 0x03, 0x55, 0x04, 0x03];
|
||||
let commonNameBytes = [0x0c, commonName.length];
|
||||
for (let i = 0; i < commonName.length; i++) {
|
||||
commonNameBytes.push(commonName.charCodeAt(i));
|
||||
}
|
||||
|
|
@ -53,8 +55,11 @@ function encodeCommonNameAsBytes(commonName) {
|
|||
}
|
||||
|
||||
function testInvalidDBKey(certDB, dbKey) {
|
||||
throws(() => certDB.findCertByDBKey(dbKey), /NS_ERROR_ILLEGAL_INPUT/,
|
||||
`findCertByDBKey(${dbKey}) should raise NS_ERROR_ILLEGAL_INPUT`);
|
||||
throws(
|
||||
() => certDB.findCertByDBKey(dbKey),
|
||||
/NS_ERROR_ILLEGAL_INPUT/,
|
||||
`findCertByDBKey(${dbKey}) should raise NS_ERROR_ILLEGAL_INPUT`
|
||||
);
|
||||
}
|
||||
|
||||
function testDBKeyForNonexistentCert(certDB, dbKey) {
|
||||
|
|
@ -72,75 +77,187 @@ function byteArrayToByteString(bytes) {
|
|||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
let cert = constructCertFromFile("bad_certs/test-ca.pem");
|
||||
equal(cert.issuerName, "CN=" + cert.issuerCommonName,
|
||||
"test assumption: this certificate's issuer distinguished name " +
|
||||
"consists only of a common name");
|
||||
equal(
|
||||
cert.issuerName,
|
||||
"CN=" + cert.issuerCommonName,
|
||||
"test assumption: this certificate's issuer distinguished name " +
|
||||
"consists only of a common name"
|
||||
);
|
||||
let issuerBytes = encodeCommonNameAsBytes(cert.issuerCommonName);
|
||||
ok(issuerBytes.length < 256,
|
||||
"test assumption: length of encoded issuer is less than 256 bytes");
|
||||
ok(
|
||||
issuerBytes.length < 256,
|
||||
"test assumption: length of encoded issuer is less than 256 bytes"
|
||||
);
|
||||
let serialNumberBytes = hexStringToBytes(cert.serialNumber);
|
||||
ok(serialNumberBytes.length < 256,
|
||||
"test assumption: length of encoded serial number is less than 256 bytes");
|
||||
let dbKeyHeader = [ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, serialNumberBytes.length,
|
||||
0, 0, 0, issuerBytes.length ];
|
||||
ok(
|
||||
serialNumberBytes.length < 256,
|
||||
"test assumption: length of encoded serial number is less than 256 bytes"
|
||||
);
|
||||
let dbKeyHeader = [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
serialNumberBytes.length,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
issuerBytes.length,
|
||||
];
|
||||
let expectedDbKeyBytes = dbKeyHeader.concat(serialNumberBytes, issuerBytes);
|
||||
let expectedDbKey = btoa(byteArrayToByteString(expectedDbKeyBytes));
|
||||
equal(cert.dbKey, expectedDbKey,
|
||||
"actual and expected dbKey values should match");
|
||||
equal(
|
||||
cert.dbKey,
|
||||
expectedDbKey,
|
||||
"actual and expected dbKey values should match"
|
||||
);
|
||||
|
||||
let certFromDbKey = certDB.findCertByDBKey(expectedDbKey);
|
||||
ok(certFromDbKey.equals(cert),
|
||||
"nsIX509CertDB.findCertByDBKey should find the right certificate");
|
||||
ok(
|
||||
certFromDbKey.equals(cert),
|
||||
"nsIX509CertDB.findCertByDBKey should find the right certificate"
|
||||
);
|
||||
|
||||
ok(expectedDbKey.length > 64,
|
||||
"test assumption: dbKey should be longer than 64 characters");
|
||||
ok(
|
||||
expectedDbKey.length > 64,
|
||||
"test assumption: dbKey should be longer than 64 characters"
|
||||
);
|
||||
let expectedDbKeyWithCRLF = expectedDbKey.replace(/(.{64})/, "$1\r\n");
|
||||
ok(expectedDbKeyWithCRLF.indexOf("\r\n") == 64,
|
||||
"test self-check: adding CRLF to dbKey should succeed");
|
||||
ok(
|
||||
expectedDbKeyWithCRLF.indexOf("\r\n") == 64,
|
||||
"test self-check: adding CRLF to dbKey should succeed"
|
||||
);
|
||||
certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithCRLF);
|
||||
ok(certFromDbKey.equals(cert),
|
||||
"nsIX509CertDB.findCertByDBKey should work with dbKey with CRLF");
|
||||
ok(
|
||||
certFromDbKey.equals(cert),
|
||||
"nsIX509CertDB.findCertByDBKey should work with dbKey with CRLF"
|
||||
);
|
||||
|
||||
let expectedDbKeyWithSpaces = expectedDbKey.replace(/(.{64})/, "$1 ");
|
||||
ok(expectedDbKeyWithSpaces.indexOf(" ") == 64,
|
||||
"test self-check: adding spaces to dbKey should succeed");
|
||||
ok(
|
||||
expectedDbKeyWithSpaces.indexOf(" ") == 64,
|
||||
"test self-check: adding spaces to dbKey should succeed"
|
||||
);
|
||||
certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithSpaces);
|
||||
ok(certFromDbKey.equals(cert),
|
||||
"nsIX509CertDB.findCertByDBKey should work with dbKey with spaces");
|
||||
ok(
|
||||
certFromDbKey.equals(cert),
|
||||
"nsIX509CertDB.findCertByDBKey should work with dbKey with spaces"
|
||||
);
|
||||
|
||||
// Test some invalid dbKey values.
|
||||
testInvalidDBKey(certDB, "AAAA"); // Not long enough.
|
||||
// No header.
|
||||
testInvalidDBKey(certDB, btoa(byteArrayToByteString(
|
||||
[ 0, 0, 0, serialNumberBytes.length,
|
||||
0, 0, 0, issuerBytes.length ].concat(serialNumberBytes, issuerBytes))));
|
||||
testInvalidDBKey(certDB, btoa(byteArrayToByteString(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
255, 255, 255, 255, // serial number length is way too long
|
||||
255, 255, 255, 255, // issuer length is way too long
|
||||
0, 0, 0, 0 ])));
|
||||
testInvalidDBKey(
|
||||
certDB,
|
||||
btoa(
|
||||
byteArrayToByteString(
|
||||
[0, 0, 0, serialNumberBytes.length, 0, 0, 0, issuerBytes.length].concat(
|
||||
serialNumberBytes,
|
||||
issuerBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
testInvalidDBKey(
|
||||
certDB,
|
||||
btoa(
|
||||
byteArrayToByteString([
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255, // serial number length is way too long
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255, // issuer length is way too long
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
])
|
||||
)
|
||||
);
|
||||
// Truncated issuer.
|
||||
testInvalidDBKey(certDB, btoa(byteArrayToByteString(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 10,
|
||||
1,
|
||||
1, 2, 3 ])));
|
||||
testInvalidDBKey(
|
||||
certDB,
|
||||
btoa(
|
||||
byteArrayToByteString([
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
10,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
])
|
||||
)
|
||||
);
|
||||
// Issuer doesn't decode to valid common name.
|
||||
testDBKeyForNonexistentCert(certDB, btoa(byteArrayToByteString(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 3,
|
||||
1,
|
||||
1, 2, 3 ])));
|
||||
testDBKeyForNonexistentCert(
|
||||
certDB,
|
||||
btoa(
|
||||
byteArrayToByteString([
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
// zero-length serial number and issuer -> no such certificate
|
||||
testDBKeyForNonexistentCert(certDB, btoa(byteArrayToByteString(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0 ])));
|
||||
testDBKeyForNonexistentCert(
|
||||
certDB,
|
||||
btoa(
|
||||
byteArrayToByteString([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function certFromFile(certName) {
|
||||
return constructCertFromFile(`test_cert_eku/${certName}.pem`);
|
||||
|
|
@ -23,19 +24,26 @@ function loadCertWithTrust(certName, trustString) {
|
|||
}
|
||||
|
||||
function checkEndEntity(cert, expectedResult) {
|
||||
return checkCertErrorGeneric(certdb, cert, expectedResult,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
expectedResult,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
function checkCertOn25August2016(cert, expectedResult) {
|
||||
// (new Date("2016-08-25T00:00:00Z")).getTime() / 1000
|
||||
const VALIDATION_TIME = 1472083200;
|
||||
return checkCertErrorGenericAtTime(certdb, cert, expectedResult,
|
||||
certificateUsageSSLServer,
|
||||
VALIDATION_TIME);
|
||||
return checkCertErrorGenericAtTime(
|
||||
certdb,
|
||||
cert,
|
||||
expectedResult,
|
||||
certificateUsageSSLServer,
|
||||
VALIDATION_TIME
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
add_task(async function() {
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("privacy.reduceTimerPrecision");
|
||||
|
|
@ -60,20 +68,35 @@ add_task(async function() {
|
|||
// Verify this for all Netscape Step Up policy configurations.
|
||||
// 0 = "always accept nsSGC in place of serverAuth for CA certificates"
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0);
|
||||
await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-nsSGC"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
// 1 = "accept nsSGC before 23 August 2016"
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1);
|
||||
await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-nsSGC"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
// 2 = "accept nsSGC before 23 August 2015"
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2);
|
||||
await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-nsSGC"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
// 3 = "never accept nsSGC"
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3);
|
||||
await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-nsSGC"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
|
||||
// end-entity has id-kp-OCSPSigning, which is not acceptable for end-entity
|
||||
// certificates being verified as TLS server certificates => failure
|
||||
await checkEndEntity(certFromFile("ee-SA-OCSP"), SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-SA-OCSP"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
|
||||
// intermediate has id-kp-serverAuth => success
|
||||
loadCertWithTrust("int-SA", ",,");
|
||||
|
|
@ -84,7 +107,10 @@ add_task(async function() {
|
|||
// intermediate has extended key usage, but id-kp-serverAuth is not present
|
||||
// => failure
|
||||
loadCertWithTrust("int-CA", ",,");
|
||||
await checkEndEntity(certFromFile("ee-int-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-int-CA"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
// intermediate has id-kp-serverAuth => success
|
||||
loadCertWithTrust("int-SA-nsSGC", ",,");
|
||||
await checkEndEntity(certFromFile("ee-int-SA-nsSGC"), PRErrorCodeSuccess);
|
||||
|
|
@ -98,39 +124,63 @@ add_task(async function() {
|
|||
// 0 = "always accept nsSGC in place of serverAuth for CA certificates"
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0);
|
||||
info("Netscape Step Up policy: always accept");
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-recent"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
// 1 = "accept nsSGC before 23 August 2016"
|
||||
info("Netscape Step Up policy: accept before 23 August 2016");
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-recent"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-old"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
// 2 = "accept nsSGC before 23 August 2015"
|
||||
info("Netscape Step Up policy: accept before 23 August 2015");
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
|
||||
PRErrorCodeSuccess);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-recent"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-old"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-older"),
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
// 3 = "never accept nsSGC"
|
||||
info("Netscape Step Up policy: never accept");
|
||||
Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-recent"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-old"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
await checkCertOn25August2016(
|
||||
certFromFile("ee-int-nsSGC-older"),
|
||||
SEC_ERROR_INADEQUATE_CERT_TYPE
|
||||
);
|
||||
|
||||
// intermediate has id-kp-OCSPSigning, which is acceptable for CA
|
||||
// certificates => success
|
||||
|
|
|
|||
|
|
@ -11,23 +11,37 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
async function do_testcase(certname, checkCommonName) {
|
||||
let cert = constructCertFromFile(`test_cert_embedded_null/${certname}.pem`);
|
||||
// Where applicable, check that the testcase is meaningful (i.e. that the
|
||||
// certificate's subject common name has an embedded NUL in it).
|
||||
if (checkCommonName) {
|
||||
equal(cert.commonName, "www.bank1.com\\00www.bad-guy.com",
|
||||
"certificate subject common name should have an embedded NUL byte");
|
||||
equal(
|
||||
cert.commonName,
|
||||
"www.bank1.com\\00www.bad-guy.com",
|
||||
"certificate subject common name should have an embedded NUL byte"
|
||||
);
|
||||
}
|
||||
await checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
|
||||
certificateUsageSSLServer, undefined,
|
||||
"www.bank1.com");
|
||||
await checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
|
||||
certificateUsageSSLServer, undefined,
|
||||
"www.bad-guy.com");
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN,
|
||||
certificateUsageSSLServer,
|
||||
undefined,
|
||||
"www.bank1.com"
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN,
|
||||
certificateUsageSSLServer,
|
||||
undefined,
|
||||
"www.bad-guy.com"
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
|
|||
|
|
@ -10,14 +10,19 @@
|
|||
// See bug 1525191.
|
||||
add_task(async function() {
|
||||
do_get_profile();
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
addCertFromFile(certDB, "bad_certs/test-ca.pem", "CTu,,");
|
||||
let threeWeeksFromNowInSeconds = (Date.now() / 1000) +
|
||||
(3 * 7 * 24 * 60 * 60);
|
||||
let threeWeeksFromNowInSeconds = Date.now() / 1000 + 3 * 7 * 24 * 60 * 60;
|
||||
let ee = constructCertFromFile("bad_certs/default-ee.pem");
|
||||
await checkCertErrorGenericAtTime(certDB, ee, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer,
|
||||
threeWeeksFromNowInSeconds, false,
|
||||
"test.example.com");
|
||||
await checkCertErrorGenericAtTime(
|
||||
certDB,
|
||||
ee,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer,
|
||||
threeWeeksFromNowInSeconds,
|
||||
false,
|
||||
"test.example.com"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// This is a certificate that (currently) ships with the platform.
|
||||
// It should be considered a built-in root.
|
||||
const sGeoTrustBase64 = "" +
|
||||
const sGeoTrustBase64 =
|
||||
"" +
|
||||
"MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL" +
|
||||
"MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj" +
|
||||
"KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2" +
|
||||
|
|
@ -30,10 +32,10 @@ const sGeoTrustBase64 = "" +
|
|||
"qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz" +
|
||||
"rD6ogRLQy7rQkgu2npaqBA+K";
|
||||
|
||||
|
||||
// This is a certificate that does not ship with the platform.
|
||||
// It should not be considered a built-in root.
|
||||
const sLetsEncryptBase64 = "" +
|
||||
const sLetsEncryptBase64 =
|
||||
"" +
|
||||
"MIIEqDCCA5CgAwIBAgIRAJgT9HUT5XULQ+dDHpceRL0wDQYJKoZIhvcNAQELBQAw" +
|
||||
"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD" +
|
||||
"Ew5EU1QgUm9vdCBDQSBYMzAeFw0xNTEwMTkyMjMzMzZaFw0yMDEwMTkyMjMzMzZa" +
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@
|
|||
|
||||
function run_test() {
|
||||
const isAndroid = AppConstants.platform == "android";
|
||||
const certDBName = isAndroid ? "cert9.db" : "cert8.db";
|
||||
const certDBName = isAndroid ? "cert9.db" : "cert8.db";
|
||||
const keyDBName = isAndroid ? "key4.db" : "key3.db";
|
||||
let profile = do_get_profile();
|
||||
let certDBFile = do_get_file(`test_cert_isBuiltInRoot_reload/${certDBName}`);
|
||||
|
|
@ -86,8 +86,9 @@ function run_test() {
|
|||
let keyDBFile = do_get_file(`test_cert_isBuiltInRoot_reload/${keyDBName}`);
|
||||
keyDBFile.copyTo(profile, keyDBName);
|
||||
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// This is a built-in root, but not one that was added to the preexisting
|
||||
// certificate DB.
|
||||
|
|
|
|||
|
|
@ -6,20 +6,33 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const caList = [ "ca-no-keyUsage-extension", "ca-missing-keyCertSign",
|
||||
"ca-all-usages" ];
|
||||
const eeList = [ "ee-no-keyUsage-extension", "ee-keyCertSign-only",
|
||||
"ee-keyEncipherment-only", "ee-keyCertSign-and-keyEncipherment" ];
|
||||
const caList = [
|
||||
"ca-no-keyUsage-extension",
|
||||
"ca-missing-keyCertSign",
|
||||
"ca-all-usages",
|
||||
];
|
||||
const eeList = [
|
||||
"ee-no-keyUsage-extension",
|
||||
"ee-keyCertSign-only",
|
||||
"ee-keyEncipherment-only",
|
||||
"ee-keyCertSign-and-keyEncipherment",
|
||||
];
|
||||
|
||||
const caUsage = [ certificateUsageSSLCA ];
|
||||
const allEEUsages = [ certificateUsageSSLClient, certificateUsageSSLServer,
|
||||
certificateUsageEmailSigner,
|
||||
certificateUsageEmailRecipient ];
|
||||
const serverEEUsages = [ certificateUsageSSLServer,
|
||||
certificateUsageEmailRecipient ];
|
||||
const caUsage = [certificateUsageSSLCA];
|
||||
const allEEUsages = [
|
||||
certificateUsageSSLClient,
|
||||
certificateUsageSSLServer,
|
||||
certificateUsageEmailSigner,
|
||||
certificateUsageEmailRecipient,
|
||||
];
|
||||
const serverEEUsages = [
|
||||
certificateUsageSSLServer,
|
||||
certificateUsageEmailRecipient,
|
||||
];
|
||||
|
||||
const expectedUsagesMap = {
|
||||
"ca-no-keyUsage-extension": caUsage,
|
||||
|
|
@ -50,8 +63,14 @@ add_task(async function() {
|
|||
await asyncTestCertificateUsages(certdb, caCert, expectedUsagesMap[ca]);
|
||||
for (let ee of eeList) {
|
||||
let eeFullName = ee + "-" + ca;
|
||||
let eeCert = constructCertFromFile("test_cert_keyUsage/" + eeFullName + ".pem");
|
||||
await asyncTestCertificateUsages(certdb, eeCert, expectedUsagesMap[eeFullName]);
|
||||
let eeCert = constructCertFromFile(
|
||||
"test_cert_keyUsage/" + eeFullName + ".pem"
|
||||
);
|
||||
await asyncTestCertificateUsages(
|
||||
certdb,
|
||||
eeCert,
|
||||
expectedUsagesMap[eeFullName]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,26 +12,39 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
function add_override_bits_mismatch_test(host, certPath, expectedBits,
|
||||
expectedError) {
|
||||
const MAX_BITS = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME;
|
||||
function add_override_bits_mismatch_test(
|
||||
host,
|
||||
certPath,
|
||||
expectedBits,
|
||||
expectedError
|
||||
) {
|
||||
const MAX_BITS =
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME;
|
||||
let cert = constructCertFromFile(certPath);
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
for (let overrideBits = 0; overrideBits <= MAX_BITS; overrideBits++) {
|
||||
add_test(function() {
|
||||
certOverrideService.clearValidityOverride(host, 8443);
|
||||
certOverrideService.rememberValidityOverride(host, 8443, cert,
|
||||
overrideBits, true);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
host,
|
||||
8443,
|
||||
cert,
|
||||
overrideBits,
|
||||
true
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
// The override will succeed only if the set of error bits in the override
|
||||
// contains each bit in the set of expected error bits.
|
||||
let successExpected = (overrideBits | expectedBits) == overrideBits;
|
||||
add_connection_test(host, successExpected ? PRErrorCodeSuccess
|
||||
: expectedError);
|
||||
add_connection_test(
|
||||
host,
|
||||
successExpected ? PRErrorCodeSuccess : expectedError
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,48 +53,62 @@ function run_test() {
|
|||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
|
||||
let fakeOCSPResponder = new HttpServer();
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
|
||||
});
|
||||
fakeOCSPResponder.start(8888);
|
||||
|
||||
add_override_bits_mismatch_test("unknownissuer.example.com",
|
||||
"bad_certs/unknownissuer.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_override_bits_mismatch_test("mismatch.example.com",
|
||||
"bad_certs/mismatch.pem",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_override_bits_mismatch_test("expired.example.com",
|
||||
"bad_certs/expired-ee.pem",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
add_override_bits_mismatch_test(
|
||||
"unknownissuer.example.com",
|
||||
"bad_certs/unknownissuer.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_override_bits_mismatch_test(
|
||||
"mismatch.example.com",
|
||||
"bad_certs/mismatch.pem",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
add_override_bits_mismatch_test(
|
||||
"expired.example.com",
|
||||
"bad_certs/expired-ee.pem",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE
|
||||
);
|
||||
|
||||
add_override_bits_mismatch_test("mismatch-untrusted.example.com",
|
||||
"bad_certs/mismatch-untrusted.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_override_bits_mismatch_test("untrusted-expired.example.com",
|
||||
"bad_certs/untrusted-expired.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_override_bits_mismatch_test("mismatch-expired.example.com",
|
||||
"bad_certs/mismatch-expired.pem",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_override_bits_mismatch_test(
|
||||
"mismatch-untrusted.example.com",
|
||||
"bad_certs/mismatch-untrusted.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_override_bits_mismatch_test(
|
||||
"untrusted-expired.example.com",
|
||||
"bad_certs/untrusted-expired.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_override_bits_mismatch_test(
|
||||
"mismatch-expired.example.com",
|
||||
"bad_certs/mismatch-expired.pem",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
|
||||
add_override_bits_mismatch_test("mismatch-untrusted-expired.example.com",
|
||||
"bad_certs/mismatch-untrusted-expired.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_override_bits_mismatch_test(
|
||||
"mismatch-untrusted-expired.example.com",
|
||||
"bad_certs/mismatch-untrusted-expired.pem",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
fakeOCSPResponder.stop(run_next_test);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -15,89 +15,183 @@ do_get_profile();
|
|||
|
||||
function check_telemetry() {
|
||||
let histogram = Services.telemetry
|
||||
.getHistogramById("SSL_CERT_ERROR_OVERRIDES")
|
||||
.snapshot();
|
||||
.getHistogramById("SSL_CERT_ERROR_OVERRIDES")
|
||||
.snapshot();
|
||||
equal(histogram.values[0], 0, "Should have 0 unclassified values");
|
||||
equal(histogram.values[2], 9,
|
||||
"Actual and expected SEC_ERROR_UNKNOWN_ISSUER values should match");
|
||||
equal(histogram.values[3], 1,
|
||||
"Actual and expected SEC_ERROR_CA_CERT_INVALID values should match");
|
||||
equal(histogram.values[4] || 0, 0,
|
||||
"Actual and expected SEC_ERROR_UNTRUSTED_ISSUER values should match");
|
||||
equal(histogram.values[5], 1,
|
||||
"Actual and expected SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE values should match");
|
||||
equal(histogram.values[6] || 0, 0,
|
||||
"Actual and expected SEC_ERROR_UNTRUSTED_CERT values should match");
|
||||
equal(histogram.values[7] || 0, 0,
|
||||
"Actual and expected SEC_ERROR_INADEQUATE_KEY_USAGE values should match");
|
||||
equal(histogram.values[8], 2,
|
||||
"Actual and expected SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED values should match");
|
||||
equal(histogram.values[9], 13,
|
||||
"Actual and expected SSL_ERROR_BAD_CERT_DOMAIN values should match");
|
||||
equal(histogram.values[10], 5,
|
||||
"Actual and expected SEC_ERROR_EXPIRED_CERTIFICATE values should match");
|
||||
equal(histogram.values[11], 2,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY values should match");
|
||||
equal(histogram.values[12], 1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA values should match");
|
||||
equal(histogram.values[13], 1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE values should match");
|
||||
equal(histogram.values[14], 2,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE values should match");
|
||||
equal(histogram.values[15], 1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE values should match");
|
||||
equal(histogram.values[16], 2,
|
||||
"Actual and expected SEC_ERROR_INVALID_TIME values should match");
|
||||
equal(histogram.values[17], 1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME values should match");
|
||||
equal(histogram.values[19], 3,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT values should match");
|
||||
equal(histogram.values[20], 1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_MITM_DETECTED values should match");
|
||||
equal(
|
||||
histogram.values[2],
|
||||
9,
|
||||
"Actual and expected SEC_ERROR_UNKNOWN_ISSUER values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[3],
|
||||
1,
|
||||
"Actual and expected SEC_ERROR_CA_CERT_INVALID values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[4] || 0,
|
||||
0,
|
||||
"Actual and expected SEC_ERROR_UNTRUSTED_ISSUER values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[5],
|
||||
1,
|
||||
"Actual and expected SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[6] || 0,
|
||||
0,
|
||||
"Actual and expected SEC_ERROR_UNTRUSTED_CERT values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[7] || 0,
|
||||
0,
|
||||
"Actual and expected SEC_ERROR_INADEQUATE_KEY_USAGE values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[8],
|
||||
2,
|
||||
"Actual and expected SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[9],
|
||||
13,
|
||||
"Actual and expected SSL_ERROR_BAD_CERT_DOMAIN values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[10],
|
||||
5,
|
||||
"Actual and expected SEC_ERROR_EXPIRED_CERTIFICATE values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[11],
|
||||
2,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[12],
|
||||
1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[13],
|
||||
1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[14],
|
||||
2,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[15],
|
||||
1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[16],
|
||||
2,
|
||||
"Actual and expected SEC_ERROR_INVALID_TIME values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[17],
|
||||
1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[19],
|
||||
3,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT values should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[20],
|
||||
1,
|
||||
"Actual and expected MOZILLA_PKIX_ERROR_MITM_DETECTED values should match"
|
||||
);
|
||||
|
||||
let keySizeHistogram = Services.telemetry
|
||||
.getHistogramById("CERT_CHAIN_KEY_SIZE_STATUS")
|
||||
.snapshot();
|
||||
equal(keySizeHistogram.values[0], 0,
|
||||
"Actual and expected unchecked key size values should match");
|
||||
equal(keySizeHistogram.values[1], 16,
|
||||
"Actual and expected successful verifications of 2048-bit keys should match");
|
||||
equal(keySizeHistogram.values[2] || 0, 0,
|
||||
"Actual and expected successful verifications of 1024-bit keys should match");
|
||||
equal(keySizeHistogram.values[3], 68,
|
||||
"Actual and expected verification failures unrelated to key size should match");
|
||||
.getHistogramById("CERT_CHAIN_KEY_SIZE_STATUS")
|
||||
.snapshot();
|
||||
equal(
|
||||
keySizeHistogram.values[0],
|
||||
0,
|
||||
"Actual and expected unchecked key size values should match"
|
||||
);
|
||||
equal(
|
||||
keySizeHistogram.values[1],
|
||||
16,
|
||||
"Actual and expected successful verifications of 2048-bit keys should match"
|
||||
);
|
||||
equal(
|
||||
keySizeHistogram.values[2] || 0,
|
||||
0,
|
||||
"Actual and expected successful verifications of 1024-bit keys should match"
|
||||
);
|
||||
equal(
|
||||
keySizeHistogram.values[3],
|
||||
68,
|
||||
"Actual and expected verification failures unrelated to key size should match"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Internally, specifying "port" -1 is the same as port 443. This tests that.
|
||||
function run_port_equivalency_test(inPort, outPort) {
|
||||
Assert.ok((inPort == 443 && outPort == -1) || (inPort == -1 && outPort == 443),
|
||||
"The two specified ports must be -1 and 443 (in any order)");
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
Assert.ok(
|
||||
(inPort == 443 && outPort == -1) || (inPort == -1 && outPort == 443),
|
||||
"The two specified ports must be -1 and 443 (in any order)"
|
||||
);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
let cert = constructCertFromFile("bad_certs/default-ee.pem");
|
||||
let expectedBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED;
|
||||
let expectedTemporary = true;
|
||||
certOverrideService.rememberValidityOverride("example.com", inPort, cert,
|
||||
expectedBits, expectedTemporary);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
"example.com",
|
||||
inPort,
|
||||
cert,
|
||||
expectedBits,
|
||||
expectedTemporary
|
||||
);
|
||||
let actualBits = {};
|
||||
let actualTemporary = {};
|
||||
Assert.ok(certOverrideService.hasMatchingOverride("example.com", outPort,
|
||||
cert, actualBits,
|
||||
actualTemporary),
|
||||
`override set on port ${inPort} should match port ${outPort}`);
|
||||
equal(actualBits.value, expectedBits,
|
||||
"input override bits should match output bits");
|
||||
equal(actualTemporary.value, expectedTemporary,
|
||||
"input override temporary value should match output temporary value");
|
||||
Assert.ok(!certOverrideService.hasMatchingOverride("example.com", 563,
|
||||
cert, {}, {}),
|
||||
`override set on port ${inPort} should not match port 563`);
|
||||
Assert.ok(
|
||||
certOverrideService.hasMatchingOverride(
|
||||
"example.com",
|
||||
outPort,
|
||||
cert,
|
||||
actualBits,
|
||||
actualTemporary
|
||||
),
|
||||
`override set on port ${inPort} should match port ${outPort}`
|
||||
);
|
||||
equal(
|
||||
actualBits.value,
|
||||
expectedBits,
|
||||
"input override bits should match output bits"
|
||||
);
|
||||
equal(
|
||||
actualTemporary.value,
|
||||
expectedTemporary,
|
||||
"input override temporary value should match output temporary value"
|
||||
);
|
||||
Assert.ok(
|
||||
!certOverrideService.hasMatchingOverride("example.com", 563, cert, {}, {}),
|
||||
`override set on port ${inPort} should not match port 563`
|
||||
);
|
||||
certOverrideService.clearValidityOverride("example.com", inPort);
|
||||
Assert.ok(!certOverrideService.hasMatchingOverride("example.com", outPort,
|
||||
cert, actualBits, {}),
|
||||
`override cleared on port ${inPort} should match port ${outPort}`);
|
||||
Assert.ok(
|
||||
!certOverrideService.hasMatchingOverride(
|
||||
"example.com",
|
||||
outPort,
|
||||
cert,
|
||||
actualBits,
|
||||
{}
|
||||
),
|
||||
`override cleared on port ${inPort} should match port ${outPort}`
|
||||
);
|
||||
equal(actualBits.value, 0, "should have no bits set if there is no override");
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +203,7 @@ function run_test() {
|
|||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
|
||||
let fakeOCSPResponder = new HttpServer();
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
|
||||
});
|
||||
fakeOCSPResponder.start(8888);
|
||||
|
|
@ -119,7 +213,7 @@ function run_test() {
|
|||
add_combo_tests();
|
||||
add_distrust_tests();
|
||||
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
fakeOCSPResponder.stop(check_telemetry);
|
||||
});
|
||||
|
||||
|
|
@ -127,99 +221,144 @@ function run_test() {
|
|||
}
|
||||
|
||||
function add_simple_tests() {
|
||||
add_cert_override_test("expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
add_cert_override_test("notyetvalid.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE);
|
||||
add_cert_override_test("before-epoch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_INVALID_TIME);
|
||||
add_cert_override_test("selfsigned.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT);
|
||||
add_cert_override_test("unknownissuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test("expiredissuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
|
||||
add_cert_override_test("notyetvalidissuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE);
|
||||
add_cert_override_test("before-epoch-issuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_INVALID_TIME);
|
||||
add_cert_override_test("md5signature.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
add_cert_override_test("emptyissuername.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME);
|
||||
add_cert_override_test(
|
||||
"expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE
|
||||
);
|
||||
add_cert_override_test(
|
||||
"notyetvalid.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE
|
||||
);
|
||||
add_cert_override_test(
|
||||
"before-epoch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_INVALID_TIME
|
||||
);
|
||||
add_cert_override_test(
|
||||
"selfsigned.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
|
||||
);
|
||||
add_cert_override_test(
|
||||
"unknownissuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_cert_override_test(
|
||||
"expiredissuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE
|
||||
);
|
||||
add_cert_override_test(
|
||||
"notyetvalidissuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE
|
||||
);
|
||||
add_cert_override_test(
|
||||
"before-epoch-issuer.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_INVALID_TIME
|
||||
);
|
||||
add_cert_override_test(
|
||||
"md5signature.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
add_cert_override_test(
|
||||
"emptyissuername.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME
|
||||
);
|
||||
// This has name information in the subject alternative names extension,
|
||||
// but not the subject common name.
|
||||
add_cert_override_test("mismatch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test(
|
||||
"mismatch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
// This has name information in the subject common name but not the subject
|
||||
// alternative names extension.
|
||||
add_cert_override_test("mismatch-CN.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test(
|
||||
"mismatch-CN.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
|
||||
// A Microsoft IIS utility generates self-signed certificates with
|
||||
// properties similar to the one this "host" will present.
|
||||
add_cert_override_test("selfsigned-inadequateEKU.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT);
|
||||
add_cert_override_test(
|
||||
"selfsigned-inadequateEKU.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
|
||||
);
|
||||
|
||||
add_prevented_cert_override_test("inadequatekeyusage.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_INADEQUATE_KEY_USAGE);
|
||||
add_prevented_cert_override_test(
|
||||
"inadequatekeyusage.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_INADEQUATE_KEY_USAGE
|
||||
);
|
||||
|
||||
// Test triggering the MitM detection. We don't set-up a proxy here. Just
|
||||
// set the pref. Without the pref set we expect an unkown issuer error.
|
||||
add_cert_override_test("mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test(
|
||||
"mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_test(function() {
|
||||
Services.prefs.setStringPref("security.pki.mitm_canary_issuer",
|
||||
"CN=Test MITM Root");
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
Services.prefs.setStringPref(
|
||||
"security.pki.mitm_canary_issuer",
|
||||
"CN=Test MITM Root"
|
||||
);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride("mitm.example.com", 8443);
|
||||
run_next_test();
|
||||
});
|
||||
add_cert_override_test("mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_MITM_DETECTED);
|
||||
add_cert_override_test(
|
||||
"mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_MITM_DETECTED
|
||||
);
|
||||
add_test(function() {
|
||||
Services.prefs.setStringPref("security.pki.mitm_canary_issuer",
|
||||
"CN=Other MITM Root");
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
Services.prefs.setStringPref(
|
||||
"security.pki.mitm_canary_issuer",
|
||||
"CN=Other MITM Root"
|
||||
);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride("mitm.example.com", 8443);
|
||||
run_next_test();
|
||||
});
|
||||
// If the canary issuer doesn't match the one we see, we exepct and unknown
|
||||
// issuer error.
|
||||
add_cert_override_test("mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test(
|
||||
"mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
// If security.pki.mitm_canary_issuer.enabled is false, there should always
|
||||
// be an unknown issuer error.
|
||||
add_test(function() {
|
||||
Services.prefs.setBoolPref("security.pki.mitm_canary_issuer.enabled",
|
||||
false);
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.pki.mitm_canary_issuer.enabled",
|
||||
false
|
||||
);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride("mitm.example.com", 8443);
|
||||
run_next_test();
|
||||
});
|
||||
add_cert_override_test("mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test(
|
||||
"mitm.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_test(function() {
|
||||
Services.prefs.clearUserPref("security.pki.mitm_canary_issuer");
|
||||
run_next_test();
|
||||
|
|
@ -234,9 +373,11 @@ function add_simple_tests() {
|
|||
setCertTrust(rootCert, ",,");
|
||||
run_next_test();
|
||||
});
|
||||
add_prevented_cert_override_test("nsCertTypeCritical.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
|
||||
add_prevented_cert_override_test(
|
||||
"nsCertTypeCritical.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION
|
||||
);
|
||||
add_test(function() {
|
||||
let rootCert = constructCertFromFile("bad_certs/test-ca.pem");
|
||||
setCertTrust(rootCert, "CTu,,");
|
||||
|
|
@ -246,31 +387,43 @@ function add_simple_tests() {
|
|||
// Bug 990603: Apache documentation has recommended generating a self-signed
|
||||
// test certificate with basic constraints: CA:true. For compatibility, this
|
||||
// is a scenario in which an override is allowed.
|
||||
add_cert_override_test("self-signed-end-entity-with-cA-true.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT);
|
||||
add_cert_override_test(
|
||||
"self-signed-end-entity-with-cA-true.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
|
||||
);
|
||||
|
||||
add_cert_override_test("ca-used-as-end-entity.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
|
||||
add_cert_override_test(
|
||||
"ca-used-as-end-entity.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
|
||||
);
|
||||
|
||||
// If an X.509 version 1 certificate is not a trust anchor, we will
|
||||
// encounter an overridable error.
|
||||
add_cert_override_test("end-entity-issued-by-v1-cert.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
|
||||
add_cert_override_test(
|
||||
"end-entity-issued-by-v1-cert.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA
|
||||
);
|
||||
// If we make that certificate a trust anchor, the connection will succeed.
|
||||
add_test(function() {
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride("end-entity-issued-by-v1-cert.example.com", 8443);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride(
|
||||
"end-entity-issued-by-v1-cert.example.com",
|
||||
8443
|
||||
);
|
||||
let v1Cert = constructCertFromFile("bad_certs/v1Cert.pem");
|
||||
setCertTrust(v1Cert, "CTu,,");
|
||||
clearSessionCache();
|
||||
run_next_test();
|
||||
});
|
||||
add_connection_test("end-entity-issued-by-v1-cert.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test(
|
||||
"end-entity-issued-by-v1-cert.example.com",
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
// Reset the trust for that certificate.
|
||||
add_test(function() {
|
||||
let v1Cert = constructCertFromFile("bad_certs/v1Cert.pem");
|
||||
|
|
@ -281,163 +434,284 @@ function add_simple_tests() {
|
|||
|
||||
// Due to compatibility issues, we allow overrides for certificates issued by
|
||||
// certificates that are not valid CAs.
|
||||
add_cert_override_test("end-entity-issued-by-non-CA.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_CA_CERT_INVALID);
|
||||
add_cert_override_test(
|
||||
"end-entity-issued-by-non-CA.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
// This host presents a 1016-bit RSA key.
|
||||
add_cert_override_test("inadequate-key-size-ee.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
|
||||
add_cert_override_test(
|
||||
"inadequate-key-size-ee.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE
|
||||
);
|
||||
|
||||
add_cert_override_test("ipAddressAsDNSNameInSAN.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test("noValidNames.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test("badSubjectAltNames.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test(
|
||||
"ipAddressAsDNSNameInSAN.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
add_cert_override_test(
|
||||
"noValidNames.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
add_cert_override_test(
|
||||
"badSubjectAltNames.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
|
||||
add_cert_override_test("bug413909.xn--hxajbheg2az3al.xn--jxalpdlp",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test(
|
||||
"bug413909.xn--hxajbheg2az3al.xn--jxalpdlp",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_test(function() {
|
||||
// At this point, the override for bug413909.xn--hxajbheg2az3al.xn--jxalpdlp
|
||||
// is still valid. Do some additional tests relating to IDN handling.
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
let uri = Services.io.newURI("https://bug413909.xn--hxajbheg2az3al.xn--jxalpdlp");
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
let uri = Services.io.newURI(
|
||||
"https://bug413909.xn--hxajbheg2az3al.xn--jxalpdlp"
|
||||
);
|
||||
let cert = constructCertFromFile("bad_certs/idn-certificate.pem");
|
||||
Assert.ok(certOverrideService.hasMatchingOverride(uri.asciiHost, 8443, cert, {}, {}),
|
||||
"IDN certificate should have matching override using ascii host");
|
||||
Assert.throws(() => !certOverrideService.hasMatchingOverride(uri.displayHost, 8443, cert, {}, {}),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"IDN certificate should not have matching override using (non-ascii) host");
|
||||
let invalidHost =
|
||||
uri.asciiHost.replace(/./g, c => String.fromCharCode(c.charCodeAt(0) | 0x100));
|
||||
Assert.throws(() => !certOverrideService.hasMatchingOverride(invalidHost, 8443, cert, {}, {}),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"hasMatchingOverride should not truncate high-bytes");
|
||||
Assert.ok(
|
||||
certOverrideService.hasMatchingOverride(
|
||||
uri.asciiHost,
|
||||
8443,
|
||||
cert,
|
||||
{},
|
||||
{}
|
||||
),
|
||||
"IDN certificate should have matching override using ascii host"
|
||||
);
|
||||
Assert.throws(
|
||||
() =>
|
||||
!certOverrideService.hasMatchingOverride(
|
||||
uri.displayHost,
|
||||
8443,
|
||||
cert,
|
||||
{},
|
||||
{}
|
||||
),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"IDN certificate should not have matching override using (non-ascii) host"
|
||||
);
|
||||
let invalidHost = uri.asciiHost.replace(/./g, c =>
|
||||
String.fromCharCode(c.charCodeAt(0) | 0x100)
|
||||
);
|
||||
Assert.throws(
|
||||
() =>
|
||||
!certOverrideService.hasMatchingOverride(
|
||||
invalidHost,
|
||||
8443,
|
||||
cert,
|
||||
{},
|
||||
{}
|
||||
),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"hasMatchingOverride should not truncate high-bytes"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function() {
|
||||
// Add a bunch of overrides...
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
let cert = constructCertFromFile("bad_certs/default-ee.pem");
|
||||
let expectedBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED;
|
||||
certOverrideService.rememberValidityOverride("example.com", 443, cert,
|
||||
expectedBits, false);
|
||||
Assert.ok(certOverrideService.hasMatchingOverride("example.com", 443, cert, {}, {}),
|
||||
"Should have added override for example.com:443");
|
||||
certOverrideService.rememberValidityOverride("example.com", 80, cert,
|
||||
expectedBits, false);
|
||||
Assert.ok(certOverrideService.hasMatchingOverride("example.com", 80, cert, {}, {}),
|
||||
"Should have added override for example.com:80");
|
||||
certOverrideService.rememberValidityOverride("example.org", 443, cert,
|
||||
expectedBits, false);
|
||||
Assert.ok(certOverrideService.hasMatchingOverride("example.org", 443, cert, {}, {}),
|
||||
"Should have added override for example.org:443");
|
||||
certOverrideService.rememberValidityOverride("example.org", 80, cert,
|
||||
expectedBits, true);
|
||||
Assert.ok(certOverrideService.hasMatchingOverride("example.org", 80, cert, {}, {}),
|
||||
"Should have added override for example.org:80");
|
||||
certOverrideService.rememberValidityOverride(
|
||||
"example.com",
|
||||
443,
|
||||
cert,
|
||||
expectedBits,
|
||||
false
|
||||
);
|
||||
Assert.ok(
|
||||
certOverrideService.hasMatchingOverride("example.com", 443, cert, {}, {}),
|
||||
"Should have added override for example.com:443"
|
||||
);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
"example.com",
|
||||
80,
|
||||
cert,
|
||||
expectedBits,
|
||||
false
|
||||
);
|
||||
Assert.ok(
|
||||
certOverrideService.hasMatchingOverride("example.com", 80, cert, {}, {}),
|
||||
"Should have added override for example.com:80"
|
||||
);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
"example.org",
|
||||
443,
|
||||
cert,
|
||||
expectedBits,
|
||||
false
|
||||
);
|
||||
Assert.ok(
|
||||
certOverrideService.hasMatchingOverride("example.org", 443, cert, {}, {}),
|
||||
"Should have added override for example.org:443"
|
||||
);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
"example.org",
|
||||
80,
|
||||
cert,
|
||||
expectedBits,
|
||||
true
|
||||
);
|
||||
Assert.ok(
|
||||
certOverrideService.hasMatchingOverride("example.org", 80, cert, {}, {}),
|
||||
"Should have added override for example.org:80"
|
||||
);
|
||||
|
||||
// Clear them all...
|
||||
certOverrideService.clearAllOverrides();
|
||||
|
||||
// And ensure they're all gone.
|
||||
Assert.ok(!certOverrideService.hasMatchingOverride("example.com", 443, cert, {}, {}),
|
||||
"Should have removed override for example.com:443");
|
||||
Assert.ok(!certOverrideService.hasMatchingOverride("example.com", 80, cert, {}, {}),
|
||||
"Should have removed override for example.com:80");
|
||||
Assert.ok(!certOverrideService.hasMatchingOverride("example.org", 443, cert, {}, {}),
|
||||
"Should have removed override for example.org:443");
|
||||
Assert.ok(!certOverrideService.hasMatchingOverride("example.org", 80, cert, {}, {}),
|
||||
"Should have removed override for example.org:80");
|
||||
Assert.ok(
|
||||
!certOverrideService.hasMatchingOverride(
|
||||
"example.com",
|
||||
443,
|
||||
cert,
|
||||
{},
|
||||
{}
|
||||
),
|
||||
"Should have removed override for example.com:443"
|
||||
);
|
||||
Assert.ok(
|
||||
!certOverrideService.hasMatchingOverride("example.com", 80, cert, {}, {}),
|
||||
"Should have removed override for example.com:80"
|
||||
);
|
||||
Assert.ok(
|
||||
!certOverrideService.hasMatchingOverride(
|
||||
"example.org",
|
||||
443,
|
||||
cert,
|
||||
{},
|
||||
{}
|
||||
),
|
||||
"Should have removed override for example.org:443"
|
||||
);
|
||||
Assert.ok(
|
||||
!certOverrideService.hasMatchingOverride("example.org", 80, cert, {}, {}),
|
||||
"Should have removed override for example.org:80"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
function add_localhost_tests() {
|
||||
add_cert_override_test("localhost",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test("127.0.0.1",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test("::1",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test(
|
||||
"localhost",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_cert_override_test(
|
||||
"127.0.0.1",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
add_cert_override_test(
|
||||
"::1",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
}
|
||||
|
||||
function add_combo_tests() {
|
||||
add_cert_override_test("mismatch-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test("mismatch-notYetValid.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN);
|
||||
add_cert_override_test("mismatch-untrusted.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test("untrusted-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test("mismatch-untrusted-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_cert_override_test(
|
||||
"mismatch-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
add_cert_override_test(
|
||||
"mismatch-notYetValid.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SSL_ERROR_BAD_CERT_DOMAIN
|
||||
);
|
||||
add_cert_override_test(
|
||||
"mismatch-untrusted.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_cert_override_test(
|
||||
"untrusted-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_cert_override_test(
|
||||
"mismatch-untrusted-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
|
||||
add_cert_override_test("md5signature-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
add_cert_override_test(
|
||||
"md5signature-expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_TIME,
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
|
||||
add_cert_override_test("ca-used-as-end-entity-name-mismatch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
|
||||
add_cert_override_test(
|
||||
"ca-used-as-end-entity-name-mismatch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
|
||||
);
|
||||
}
|
||||
|
||||
function add_distrust_tests() {
|
||||
// Before we specifically distrust this certificate, it should be trusted.
|
||||
add_connection_test("untrusted.example.com", PRErrorCodeSuccess);
|
||||
|
||||
add_distrust_test("bad_certs/default-ee.pem", "untrusted.example.com",
|
||||
SEC_ERROR_UNTRUSTED_CERT);
|
||||
add_distrust_test(
|
||||
"bad_certs/default-ee.pem",
|
||||
"untrusted.example.com",
|
||||
SEC_ERROR_UNTRUSTED_CERT
|
||||
);
|
||||
|
||||
add_distrust_test("bad_certs/other-test-ca.pem",
|
||||
"untrustedissuer.example.com", SEC_ERROR_UNTRUSTED_ISSUER);
|
||||
add_distrust_test(
|
||||
"bad_certs/other-test-ca.pem",
|
||||
"untrustedissuer.example.com",
|
||||
SEC_ERROR_UNTRUSTED_ISSUER
|
||||
);
|
||||
|
||||
add_distrust_test("bad_certs/test-ca.pem",
|
||||
"ca-used-as-end-entity.example.com",
|
||||
SEC_ERROR_UNTRUSTED_ISSUER);
|
||||
add_distrust_test(
|
||||
"bad_certs/test-ca.pem",
|
||||
"ca-used-as-end-entity.example.com",
|
||||
SEC_ERROR_UNTRUSTED_ISSUER
|
||||
);
|
||||
}
|
||||
|
||||
function add_distrust_test(certFileName, hostName, expectedResult) {
|
||||
let certToDistrust = constructCertFromFile(certFileName);
|
||||
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
// Add an entry to the NSS certDB that says to distrust the cert
|
||||
setCertTrust(certToDistrust, "pu,,");
|
||||
clearSessionCache();
|
||||
run_next_test();
|
||||
});
|
||||
add_prevented_cert_override_test(hostName,
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
expectedResult);
|
||||
add_test(function () {
|
||||
add_prevented_cert_override_test(
|
||||
hostName,
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
expectedResult
|
||||
);
|
||||
add_test(function() {
|
||||
setCertTrust(certToDistrust, "u,,");
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,32 +11,57 @@
|
|||
// to be called directly.
|
||||
function add_read_only_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
||||
let bits =
|
||||
(aSecurityInfo.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) |
|
||||
(aSecurityInfo.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) |
|
||||
(aSecurityInfo.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0);
|
||||
(aSecurityInfo.isUntrusted
|
||||
? Ci.nsICertOverrideService.ERROR_UNTRUSTED
|
||||
: 0) |
|
||||
(aSecurityInfo.isDomainMismatch
|
||||
? Ci.nsICertOverrideService.ERROR_MISMATCH
|
||||
: 0) |
|
||||
(aSecurityInfo.isNotValidAtThisTime
|
||||
? Ci.nsICertOverrideService.ERROR_TIME
|
||||
: 0);
|
||||
|
||||
Assert.equal(bits, aExpectedBits,
|
||||
"Actual and expected override bits should match");
|
||||
Assert.equal(
|
||||
bits,
|
||||
aExpectedBits,
|
||||
"Actual and expected override bits should match"
|
||||
);
|
||||
let cert = aSecurityInfo.serverCert;
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
// Setting the last argument to false here ensures that we attempt to store a
|
||||
// permanent override (which is what was failing in bug 1427273).
|
||||
certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits,
|
||||
false);
|
||||
certOverrideService.rememberValidityOverride(
|
||||
aHost,
|
||||
8443,
|
||||
cert,
|
||||
aExpectedBits,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// Given a host, expected error bits (see nsICertOverrideService.idl), and an
|
||||
// expected error code, tests that an initial connection to the host fails with
|
||||
// the expected errors and that adding an override results in a subsequent
|
||||
// connection succeeding.
|
||||
function add_read_only_cert_override_test(aHost, aExpectedBits, aExpectedError) {
|
||||
add_connection_test(aHost, aExpectedError, null,
|
||||
add_read_only_cert_override.bind(this, aHost, aExpectedBits));
|
||||
function add_read_only_cert_override_test(
|
||||
aHost,
|
||||
aExpectedBits,
|
||||
aExpectedError
|
||||
) {
|
||||
add_connection_test(
|
||||
aHost,
|
||||
aExpectedError,
|
||||
null,
|
||||
add_read_only_cert_override.bind(this, aHost, aExpectedBits)
|
||||
);
|
||||
add_connection_test(aHost, PRErrorCodeSuccess, null, aSecurityInfo => {
|
||||
Assert.ok(aSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
|
||||
"Cert override flag should be set on the security state");
|
||||
Assert.ok(
|
||||
aSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
|
||||
"Cert override flag should be set on the security state"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -44,9 +69,13 @@ function run_test() {
|
|||
let profile = do_get_profile();
|
||||
const KEY_DB_NAME = "key4.db";
|
||||
const CERT_DB_NAME = "cert9.db";
|
||||
let srcKeyDBFile = do_get_file(`test_cert_overrides_read_only/${KEY_DB_NAME}`);
|
||||
let srcKeyDBFile = do_get_file(
|
||||
`test_cert_overrides_read_only/${KEY_DB_NAME}`
|
||||
);
|
||||
srcKeyDBFile.copyTo(profile, KEY_DB_NAME);
|
||||
let srcCertDBFile = do_get_file(`test_cert_overrides_read_only/${CERT_DB_NAME}`);
|
||||
let srcCertDBFile = do_get_file(
|
||||
`test_cert_overrides_read_only/${CERT_DB_NAME}`
|
||||
);
|
||||
srcCertDBFile.copyTo(profile, CERT_DB_NAME);
|
||||
|
||||
// set the databases to read-only
|
||||
|
|
@ -63,7 +92,7 @@ function run_test() {
|
|||
add_tls_server_setup("BadCertServer", "bad_certs", false);
|
||||
|
||||
let fakeOCSPResponder = new HttpServer();
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
|
||||
});
|
||||
fakeOCSPResponder.start(8888);
|
||||
|
|
@ -71,19 +100,25 @@ function run_test() {
|
|||
// Since we can't add the root CA to the (read-only) trust db, all of these
|
||||
// will result in an "unknown issuer error" and need the "untrusted" error bit
|
||||
// set in addition to whatever other specific error bits are necessary.
|
||||
add_read_only_cert_override_test("expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_read_only_cert_override_test("selfsigned.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT);
|
||||
add_read_only_cert_override_test("mismatch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_read_only_cert_override_test(
|
||||
"expired.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_TIME |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
add_read_only_cert_override_test(
|
||||
"selfsigned.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
|
||||
);
|
||||
add_read_only_cert_override_test(
|
||||
"mismatch.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH |
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
fakeOCSPResponder.stop(run_next_test);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// We need to test as if we are at a fixed time, so that we are testing the
|
||||
// 2016 checks on SHA-1, not the notBefore checks.
|
||||
|
|
@ -27,9 +28,13 @@ function loadCertWithTrust(certName, trustString) {
|
|||
}
|
||||
|
||||
function checkEndEntity(cert, expectedResult) {
|
||||
return checkCertErrorGenericAtTime(certdb, cert, expectedResult,
|
||||
certificateUsageSSLServer,
|
||||
VALIDATION_TIME);
|
||||
return checkCertErrorGenericAtTime(
|
||||
certdb,
|
||||
cert,
|
||||
expectedResult,
|
||||
certificateUsageSSLServer,
|
||||
VALIDATION_TIME
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
@ -94,15 +99,33 @@ add_task(async function() {
|
|||
|
||||
// SHA-1 forbidden
|
||||
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 1);
|
||||
await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-pre_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-post"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
|
||||
// SHA-1 forbidden (test the case where the pref has been set to 2)
|
||||
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 2);
|
||||
await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-pre_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-post"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
|
||||
// SHA-1 allowed only when issued by an imported root. First test with the
|
||||
// test root considered a built-in (on debug only - this functionality is
|
||||
|
|
@ -110,10 +133,22 @@ add_task(async function() {
|
|||
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 3);
|
||||
if (isDebugBuild) {
|
||||
let root = certFromFile("ca");
|
||||
Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
|
||||
await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
Services.prefs.setCharPref(
|
||||
"security.test.built_in_root_hash",
|
||||
root.sha256Fingerprint
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-pre_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-post"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
Services.prefs.clearUserPref("security.test.built_in_root_hash");
|
||||
}
|
||||
|
||||
|
|
@ -128,10 +163,19 @@ add_task(async function() {
|
|||
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
|
||||
if (isDebugBuild) {
|
||||
let root = certFromFile("ca");
|
||||
Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
|
||||
Services.prefs.setCharPref(
|
||||
"security.test.built_in_root_hash",
|
||||
root.sha256Fingerprint
|
||||
);
|
||||
await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
|
||||
await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-pre"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-post_int-post"),
|
||||
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
);
|
||||
Services.prefs.clearUserPref("security.test.built_in_root_hash");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@
|
|||
// the rest of the certificate.
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// Reads a PEM-encoded certificate, modifies the nth byte (0-indexed), and
|
||||
// returns the base64-encoded bytes of the certificate. Negative indices may be
|
||||
|
|
@ -44,15 +45,23 @@ function addSignatureTamperedCertificate(certificatePath) {
|
|||
|
||||
function ensureSignatureVerificationFailure(certificatePath) {
|
||||
let cert = constructCertFromFile(certificatePath);
|
||||
return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
SEC_ERROR_BAD_SIGNATURE,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
function tamperWithSignatureAndEnsureVerificationFailure(certificatePath) {
|
||||
let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
|
||||
let cert = certdb.constructX509FromBase64(base64);
|
||||
return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
SEC_ERROR_BAD_SIGNATURE,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
// The beginning of a certificate looks like this (in hex, using DER):
|
||||
|
|
@ -72,17 +81,19 @@ function tamperWithSignatureAndEnsureVerificationFailure(certificatePath) {
|
|||
// issues there. Thus byte 17 is a good byte to modify.
|
||||
const BYTE_IN_SERIAL_NUMBER = 17;
|
||||
function addSerialNumberTamperedCertificate(certificatePath) {
|
||||
let base64 = readAndTamperWithNthByte(certificatePath,
|
||||
BYTE_IN_SERIAL_NUMBER);
|
||||
let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SERIAL_NUMBER);
|
||||
certdb.addCertFromBase64(base64, ",,");
|
||||
}
|
||||
|
||||
function tamperWithSerialNumberAndEnsureVerificationFailure(certificatePath) {
|
||||
let base64 = readAndTamperWithNthByte(certificatePath,
|
||||
BYTE_IN_SERIAL_NUMBER);
|
||||
let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SERIAL_NUMBER);
|
||||
let cert = certdb.constructX509FromBase64(base64);
|
||||
return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
SEC_ERROR_BAD_SIGNATURE,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
@ -95,14 +106,18 @@ add_task(async function() {
|
|||
addSignatureTamperedCertificate("test_cert_signatures/int-rsa.pem");
|
||||
addSignatureTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
|
||||
await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
|
||||
await ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
|
||||
await ensureSignatureVerificationFailure(
|
||||
"test_cert_signatures/ee-secp384r1.pem"
|
||||
);
|
||||
|
||||
// Tamper with the signatures on end-entity certificates and ensure that they
|
||||
// do not validate successfully.
|
||||
await tamperWithSignatureAndEnsureVerificationFailure(
|
||||
"test_cert_signatures/ee-rsa-direct.pem");
|
||||
"test_cert_signatures/ee-rsa-direct.pem"
|
||||
);
|
||||
await tamperWithSignatureAndEnsureVerificationFailure(
|
||||
"test_cert_signatures/ee-secp384r1-direct.pem");
|
||||
"test_cert_signatures/ee-secp384r1-direct.pem"
|
||||
);
|
||||
|
||||
// Tamper with the serial numbers of intermediate certificates and ensure
|
||||
// that end-entity certificates issued by those intermediates do not validate
|
||||
|
|
@ -110,12 +125,16 @@ add_task(async function() {
|
|||
addSerialNumberTamperedCertificate("test_cert_signatures/int-rsa.pem");
|
||||
addSerialNumberTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
|
||||
await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
|
||||
await ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
|
||||
await ensureSignatureVerificationFailure(
|
||||
"test_cert_signatures/ee-secp384r1.pem"
|
||||
);
|
||||
|
||||
// Tamper with the serial numbers of end-entity certificates and ensure that
|
||||
// they do not validate successfully.
|
||||
await tamperWithSerialNumberAndEnsureVerificationFailure(
|
||||
"test_cert_signatures/ee-rsa-direct.pem");
|
||||
"test_cert_signatures/ee-rsa-direct.pem"
|
||||
);
|
||||
await tamperWithSerialNumberAndEnsureVerificationFailure(
|
||||
"test_cert_signatures/ee-secp384r1-direct.pem");
|
||||
"test_cert_signatures/ee-secp384r1-direct.pem"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,17 +12,21 @@
|
|||
// * it does a sanity check to ensure other cert verifier behavior is
|
||||
// unmodified
|
||||
|
||||
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm", {});
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import("resource://gre/modules/psm/RemoteSecuritySettings.jsm");
|
||||
const { setTimeout } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm",
|
||||
{}
|
||||
);
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import(
|
||||
"resource://gre/modules/psm/RemoteSecuritySettings.jsm"
|
||||
);
|
||||
|
||||
// First, we need to setup appInfo for the blocklist service to work
|
||||
var id = "xpcshell@tests.mozilla.org";
|
||||
var appName = "XPCShell";
|
||||
var version = "1";
|
||||
var platformVersion = "1.9.2";
|
||||
ChromeUtils.import("resource://testing-common/AppInfo.jsm", this);
|
||||
/* global updateAppInfo:false */ // Imported via AppInfo.jsm.
|
||||
updateAppInfo({
|
||||
ChromeUtils.import("resource://testing-common/AppInfo.jsm", this); // Imported via AppInfo.jsm.
|
||||
/* global updateAppInfo:false */ updateAppInfo({
|
||||
name: appName,
|
||||
ID: id,
|
||||
version,
|
||||
|
|
@ -41,8 +45,9 @@ if (!gRevocations.exists()) {
|
|||
existing.copyTo(gProfile, "revocations.txt");
|
||||
}
|
||||
|
||||
var certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const certBlocklist = [
|
||||
// test with some bad data ...
|
||||
|
|
@ -99,19 +104,35 @@ const certBlocklist = [
|
|||
|
||||
function verify_cert(file, expectedError) {
|
||||
let ee = constructCertFromFile(file);
|
||||
return checkCertErrorGeneric(certDB, ee, expectedError,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee,
|
||||
expectedError,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
// The certificate blocklist currently only applies to TLS server certificates.
|
||||
async function verify_non_tls_usage_succeeds(file) {
|
||||
let ee = constructCertFromFile(file);
|
||||
await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
}
|
||||
|
||||
function load_cert(cert, trust) {
|
||||
|
|
@ -131,8 +152,10 @@ async function update_blocklist() {
|
|||
await OneCRLBlocklistClient.emit("sync", { data: fakeEvent });
|
||||
// Save the last check timestamp, used by cert_storage to assert
|
||||
// if the blocklist is «fresh».
|
||||
Services.prefs.setIntPref(OneCRLBlocklistClient.lastCheckTimePref,
|
||||
Math.floor(Date.now() / 1000));
|
||||
Services.prefs.setIntPref(
|
||||
OneCRLBlocklistClient.lastCheckTimePref,
|
||||
Math.floor(Date.now() / 1000)
|
||||
);
|
||||
}
|
||||
|
||||
function* generate_revocations_txt_lines() {
|
||||
|
|
@ -140,8 +163,9 @@ function* generate_revocations_txt_lines() {
|
|||
let revocations = profile.clone();
|
||||
revocations.append("revocations.txt");
|
||||
ok(revocations.exists(), "the revocations file should exist");
|
||||
let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
let inputStream = Cc[
|
||||
"@mozilla.org/network/file-input-stream;1"
|
||||
].createInstance(Ci.nsIFileInputStream);
|
||||
inputStream.init(revocations, -1, -1, 0);
|
||||
inputStream.QueryInterface(Ci.nsILineInputStream);
|
||||
let hasmore = false;
|
||||
|
|
@ -159,10 +183,16 @@ function* generate_revocations_txt_lines() {
|
|||
function check_revocations_txt_contents(expected) {
|
||||
let lineGenerator = generate_revocations_txt_lines();
|
||||
let firstLine = lineGenerator.next();
|
||||
equal(firstLine.done, false,
|
||||
"first line of revocations.txt should be present");
|
||||
equal(firstLine.value, "# Auto generated contents. Do not edit.",
|
||||
"first line of revocations.txt");
|
||||
equal(
|
||||
firstLine.done,
|
||||
false,
|
||||
"first line of revocations.txt should be present"
|
||||
);
|
||||
equal(
|
||||
firstLine.value,
|
||||
"# Auto generated contents. Do not edit.",
|
||||
"first line of revocations.txt"
|
||||
);
|
||||
let line = lineGenerator.next();
|
||||
let topLevelFound = {};
|
||||
while (true) {
|
||||
|
|
@ -170,10 +200,14 @@ function check_revocations_txt_contents(expected) {
|
|||
break;
|
||||
}
|
||||
|
||||
ok(line.value in expected,
|
||||
`${line.value} should be an expected top-level line in revocations.txt`);
|
||||
ok(!(line.value in topLevelFound),
|
||||
`should not have seen ${line.value} before in revocations.txt`);
|
||||
ok(
|
||||
line.value in expected,
|
||||
`${line.value} should be an expected top-level line in revocations.txt`
|
||||
);
|
||||
ok(
|
||||
!(line.value in topLevelFound),
|
||||
`should not have seen ${line.value} before in revocations.txt`
|
||||
);
|
||||
topLevelFound[line.value] = true;
|
||||
let topLevelLine = line.value;
|
||||
|
||||
|
|
@ -184,18 +218,24 @@ function check_revocations_txt_contents(expected) {
|
|||
if (line.done || !(line.value in sublines)) {
|
||||
break;
|
||||
}
|
||||
ok(!(line.value in subFound),
|
||||
`should not have seen ${line.value} before in revocations.txt`);
|
||||
ok(
|
||||
!(line.value in subFound),
|
||||
`should not have seen ${line.value} before in revocations.txt`
|
||||
);
|
||||
subFound[line.value] = true;
|
||||
}
|
||||
for (let subline in sublines) {
|
||||
ok(subFound[subline],
|
||||
`should have found ${subline} below ${topLevelLine} in revocations.txt`);
|
||||
ok(
|
||||
subFound[subline],
|
||||
`should have found ${subline} below ${topLevelLine} in revocations.txt`
|
||||
);
|
||||
}
|
||||
}
|
||||
for (let topLevelLine in expected) {
|
||||
ok(topLevelFound[topLevelLine],
|
||||
`should have found ${topLevelLine} in revocations.txt`);
|
||||
ok(
|
||||
topLevelFound[topLevelLine],
|
||||
`should have found ${topLevelLine} in revocations.txt`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -205,20 +245,22 @@ function run_test() {
|
|||
load_cert("test-int", ",,");
|
||||
load_cert("other-test-ca", "CTu,CTu,CTu");
|
||||
|
||||
let certList = AppConstants.MOZ_NEW_CERT_STORAGE ?
|
||||
Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage) :
|
||||
Cc["@mozilla.org/security/certblocklist;1"].getService(Ci.nsICertBlocklist);
|
||||
let certList = AppConstants.MOZ_NEW_CERT_STORAGE
|
||||
? Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage)
|
||||
: Cc["@mozilla.org/security/certblocklist;1"].getService(
|
||||
Ci.nsICertBlocklist
|
||||
);
|
||||
|
||||
let expected = { "MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5":
|
||||
{ "\tVCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=": true },
|
||||
"MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=":
|
||||
{ " Rym6o+VN9xgZXT/QLrvN/nv1ZN4=": true},
|
||||
"MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=":
|
||||
{ " a0X7/7DlTaedpgrIJg25iBPOkIM=": true},
|
||||
"MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl":
|
||||
{ " Tg==": true,
|
||||
" Hw==": true },
|
||||
};
|
||||
let expected = {
|
||||
MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5: {
|
||||
"\tVCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=": true,
|
||||
},
|
||||
"MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=": {
|
||||
" Rym6o+VN9xgZXT/QLrvN/nv1ZN4=": true,
|
||||
},
|
||||
"MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=": { " a0X7/7DlTaedpgrIJg25iBPOkIM=": true },
|
||||
MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl: { " Tg==": true, " Hw==": true },
|
||||
};
|
||||
|
||||
add_task(async function() {
|
||||
// check some existing items in revocations.txt are blocked.
|
||||
|
|
@ -321,28 +363,39 @@ function run_test() {
|
|||
// check that save with no further update is a no-op
|
||||
let lastModified = gRevocations.lastModifiedTime;
|
||||
// add an already existing entry
|
||||
certList.revokeCertByIssuerAndSerial("MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl",
|
||||
"Hw==");
|
||||
certList.revokeCertByIssuerAndSerial(
|
||||
"MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRl",
|
||||
"Hw=="
|
||||
);
|
||||
certList.saveEntries();
|
||||
let newModified = gRevocations.lastModifiedTime;
|
||||
equal(lastModified, newModified,
|
||||
"saveEntries with no modifications should not update the backing file");
|
||||
equal(
|
||||
lastModified,
|
||||
newModified,
|
||||
"saveEntries with no modifications should not update the backing file"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_test({
|
||||
skip_if: () => AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, function() {
|
||||
// Check the blocklist entry has not changed
|
||||
check_revocations_txt_contents(expected);
|
||||
run_next_test();
|
||||
});
|
||||
add_test(
|
||||
{
|
||||
skip_if: () => AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
function() {
|
||||
// Check the blocklist entry has not changed
|
||||
check_revocations_txt_contents(expected);
|
||||
run_next_test();
|
||||
}
|
||||
);
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function() {
|
||||
ok(certList.isBlocklistFresh(), "Blocklist should be fresh.");
|
||||
});
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function() {
|
||||
ok(certList.isBlocklistFresh(), "Blocklist should be fresh.");
|
||||
}
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
|
||||
// This file tests cert_storage's automatic database recreation mechanism. If
|
||||
// opening the database for the first time fails, cert_storage will re-create
|
||||
// it.
|
||||
|
||||
function call_has_prior_data(certStorage, type) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
certStorage.hasPriorData(type, (rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
|
|
@ -19,63 +18,83 @@ function call_has_prior_data(certStorage, type) {
|
|||
}
|
||||
|
||||
async function check_has_prior_revocation_data(certStorage, expectedResult) {
|
||||
let hasPriorRevocationData = await call_has_prior_data(certStorage,
|
||||
Ci.nsICertStorage.DATA_TYPE_REVOCATION);
|
||||
Assert.equal(hasPriorRevocationData, expectedResult,
|
||||
`should ${expectedResult ? "have" : "not have"} prior revocation data`);
|
||||
let hasPriorRevocationData = await call_has_prior_data(
|
||||
certStorage,
|
||||
Ci.nsICertStorage.DATA_TYPE_REVOCATION
|
||||
);
|
||||
Assert.equal(
|
||||
hasPriorRevocationData,
|
||||
expectedResult,
|
||||
`should ${expectedResult ? "have" : "not have"} prior revocation data`
|
||||
);
|
||||
}
|
||||
|
||||
async function check_has_prior_cert_data(certStorage, expectedResult) {
|
||||
let hasPriorCertData = await call_has_prior_data(certStorage,
|
||||
Ci.nsICertStorage.DATA_TYPE_CERTIFICATE);
|
||||
Assert.equal(hasPriorCertData, expectedResult,
|
||||
`should ${expectedResult ? "have" : "not have"} prior cert data`);
|
||||
let hasPriorCertData = await call_has_prior_data(
|
||||
certStorage,
|
||||
Ci.nsICertStorage.DATA_TYPE_CERTIFICATE
|
||||
);
|
||||
Assert.equal(
|
||||
hasPriorCertData,
|
||||
expectedResult,
|
||||
`should ${expectedResult ? "have" : "not have"} prior cert data`
|
||||
);
|
||||
}
|
||||
|
||||
async function check_has_prior_crlite_data(certStorage, expectedResult) {
|
||||
let hasPriorCRLiteData = await call_has_prior_data(certStorage,
|
||||
Ci.nsICertStorage.DATA_TYPE_CRLITE);
|
||||
Assert.equal(hasPriorCRLiteData, expectedResult,
|
||||
`should ${expectedResult ? "have" : "not have"} prior CRLite data`);
|
||||
let hasPriorCRLiteData = await call_has_prior_data(
|
||||
certStorage,
|
||||
Ci.nsICertStorage.DATA_TYPE_CRLITE
|
||||
);
|
||||
Assert.equal(
|
||||
hasPriorCRLiteData,
|
||||
expectedResult,
|
||||
`should ${expectedResult ? "have" : "not have"} prior CRLite data`
|
||||
);
|
||||
}
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function() {
|
||||
// Create an invalid database.
|
||||
let fileToCopy = do_get_file("test_cert_storage_broken_db.js");
|
||||
let dbDirectory = do_get_profile();
|
||||
dbDirectory.append("security_state");
|
||||
fileToCopy.copyTo(dbDirectory, "data.mdb");
|
||||
},
|
||||
async function() {
|
||||
// Create an invalid database.
|
||||
let fileToCopy = do_get_file("test_cert_storage_broken_db.js");
|
||||
let dbDirectory = do_get_profile();
|
||||
dbDirectory.append("security_state");
|
||||
fileToCopy.copyTo(dbDirectory, "data.mdb");
|
||||
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
check_has_prior_revocation_data(certStorage, false);
|
||||
check_has_prior_cert_data(certStorage, false);
|
||||
check_has_prior_crlite_data(certStorage, false);
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
check_has_prior_revocation_data(certStorage, false);
|
||||
check_has_prior_cert_data(certStorage, false);
|
||||
check_has_prior_crlite_data(certStorage, false);
|
||||
|
||||
let result = await new Promise((resolve) => {
|
||||
certStorage.setRevocations([], resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "setRevocations should succeed");
|
||||
let result = await new Promise(resolve => {
|
||||
certStorage.setRevocations([], resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "setRevocations should succeed");
|
||||
|
||||
check_has_prior_revocation_data(certStorage, true);
|
||||
check_has_prior_cert_data(certStorage, false);
|
||||
check_has_prior_crlite_data(certStorage, false);
|
||||
check_has_prior_revocation_data(certStorage, true);
|
||||
check_has_prior_cert_data(certStorage, false);
|
||||
check_has_prior_crlite_data(certStorage, false);
|
||||
|
||||
result = await new Promise((resolve) => {
|
||||
certStorage.addCerts([], resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "addCerts should succeed");
|
||||
result = await new Promise(resolve => {
|
||||
certStorage.addCerts([], resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "addCerts should succeed");
|
||||
|
||||
check_has_prior_revocation_data(certStorage, true);
|
||||
check_has_prior_cert_data(certStorage, true);
|
||||
check_has_prior_crlite_data(certStorage, false);
|
||||
check_has_prior_revocation_data(certStorage, true);
|
||||
check_has_prior_cert_data(certStorage, true);
|
||||
check_has_prior_crlite_data(certStorage, false);
|
||||
|
||||
result = await new Promise((resolve) => {
|
||||
certStorage.setCRLiteState([], resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "setCRLiteState should succeed");
|
||||
check_has_prior_revocation_data(certStorage, true);
|
||||
check_has_prior_cert_data(certStorage, true);
|
||||
check_has_prior_crlite_data(certStorage, true);
|
||||
});
|
||||
result = await new Promise(resolve => {
|
||||
certStorage.setCRLiteState([], resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "setCRLiteState should succeed");
|
||||
check_has_prior_revocation_data(certStorage, true);
|
||||
check_has_prior_cert_data(certStorage, true);
|
||||
check_has_prior_crlite_data(certStorage, true);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,18 +10,20 @@
|
|||
do_get_profile();
|
||||
|
||||
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
||||
this.certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
this.certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
}
|
||||
|
||||
async function addCerts(certInfos) {
|
||||
let result = await new Promise((resolve) => {
|
||||
let result = await new Promise(resolve => {
|
||||
certStorage.addCerts(certInfos, resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "addCerts should succeed");
|
||||
}
|
||||
|
||||
async function removeCertsByHashes(hashesBase64) {
|
||||
let result = await new Promise((resolve) => {
|
||||
let result = await new Promise(resolve => {
|
||||
certStorage.removeCertsByHashes(hashesBase64, resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "removeCertsByHashes should succeed");
|
||||
|
|
@ -42,119 +44,227 @@ if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
|||
CertInfo.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsICertInfo]);
|
||||
}
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_common_subject() {
|
||||
let someCert1 = new CertInfo("some certificate bytes 1", "some common subject");
|
||||
let someCert2 = new CertInfo("some certificate bytes 2", "some common subject");
|
||||
let someCert3 = new CertInfo("some certificate bytes 3", "some common subject");
|
||||
await addCerts([someCert1, someCert2, someCert3]);
|
||||
let storedCerts = certStorage.findCertsBySubject(stringToArray("some common subject"));
|
||||
let storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
let expectedCerts = ["some certificate bytes 1", "some certificate bytes 2",
|
||||
"some certificate bytes 3"];
|
||||
Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(), "should find expected certs");
|
||||
},
|
||||
async function test_common_subject() {
|
||||
let someCert1 = new CertInfo(
|
||||
"some certificate bytes 1",
|
||||
"some common subject"
|
||||
);
|
||||
let someCert2 = new CertInfo(
|
||||
"some certificate bytes 2",
|
||||
"some common subject"
|
||||
);
|
||||
let someCert3 = new CertInfo(
|
||||
"some certificate bytes 3",
|
||||
"some common subject"
|
||||
);
|
||||
await addCerts([someCert1, someCert2, someCert3]);
|
||||
let storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("some common subject")
|
||||
);
|
||||
let storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
let expectedCerts = [
|
||||
"some certificate bytes 1",
|
||||
"some certificate bytes 2",
|
||||
"some certificate bytes 3",
|
||||
];
|
||||
Assert.deepEqual(
|
||||
storedCertsAsStrings.sort(),
|
||||
expectedCerts.sort(),
|
||||
"should find expected certs"
|
||||
);
|
||||
|
||||
await addCerts([new CertInfo("some other certificate bytes", "some other subject")]);
|
||||
storedCerts = certStorage.findCertsBySubject(stringToArray("some common subject"));
|
||||
storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(),
|
||||
"should still find expected certs");
|
||||
await addCerts([
|
||||
new CertInfo("some other certificate bytes", "some other subject"),
|
||||
]);
|
||||
storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("some common subject")
|
||||
);
|
||||
storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
Assert.deepEqual(
|
||||
storedCertsAsStrings.sort(),
|
||||
expectedCerts.sort(),
|
||||
"should still find expected certs"
|
||||
);
|
||||
|
||||
let storedOtherCerts = certStorage.findCertsBySubject(stringToArray("some other subject"));
|
||||
let storedOtherCertsAsStrings = storedOtherCerts.map(arrayToString);
|
||||
let expectedOtherCerts = ["some other certificate bytes"];
|
||||
Assert.deepEqual(storedOtherCertsAsStrings, expectedOtherCerts, "should have other certificate");
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_many_entries() {
|
||||
const NUM_CERTS = 500;
|
||||
const CERT_LENGTH = 3000;
|
||||
const SUBJECT_LENGTH = 40;
|
||||
let certs = [];
|
||||
for (let i = 0; i < NUM_CERTS; i++) {
|
||||
certs.push(new CertInfo(getLongString(i, CERT_LENGTH), getLongString(i, SUBJECT_LENGTH)));
|
||||
let storedOtherCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("some other subject")
|
||||
);
|
||||
let storedOtherCertsAsStrings = storedOtherCerts.map(arrayToString);
|
||||
let expectedOtherCerts = ["some other certificate bytes"];
|
||||
Assert.deepEqual(
|
||||
storedOtherCertsAsStrings,
|
||||
expectedOtherCerts,
|
||||
"should have other certificate"
|
||||
);
|
||||
}
|
||||
await addCerts(certs);
|
||||
for (let i = 0; i < NUM_CERTS; i++) {
|
||||
let subject = stringToArray(getLongString(i, SUBJECT_LENGTH));
|
||||
let storedCerts = certStorage.findCertsBySubject(subject);
|
||||
Assert.equal(storedCerts.length, 1, "should have 1 certificate (lots of data test)");
|
||||
let storedCertAsString = arrayToString(storedCerts[0]);
|
||||
Assert.equal(storedCertAsString, getLongString(i, CERT_LENGTH),
|
||||
"certificate should be as expected (lots of data test)");
|
||||
);
|
||||
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_many_entries() {
|
||||
const NUM_CERTS = 500;
|
||||
const CERT_LENGTH = 3000;
|
||||
const SUBJECT_LENGTH = 40;
|
||||
let certs = [];
|
||||
for (let i = 0; i < NUM_CERTS; i++) {
|
||||
certs.push(
|
||||
new CertInfo(
|
||||
getLongString(i, CERT_LENGTH),
|
||||
getLongString(i, SUBJECT_LENGTH)
|
||||
)
|
||||
);
|
||||
}
|
||||
await addCerts(certs);
|
||||
for (let i = 0; i < NUM_CERTS; i++) {
|
||||
let subject = stringToArray(getLongString(i, SUBJECT_LENGTH));
|
||||
let storedCerts = certStorage.findCertsBySubject(subject);
|
||||
Assert.equal(
|
||||
storedCerts.length,
|
||||
1,
|
||||
"should have 1 certificate (lots of data test)"
|
||||
);
|
||||
let storedCertAsString = arrayToString(storedCerts[0]);
|
||||
Assert.equal(
|
||||
storedCertAsString,
|
||||
getLongString(i, CERT_LENGTH),
|
||||
"certificate should be as expected (lots of data test)"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_removal() {
|
||||
// As long as cert_storage is given valid base64, attempting to delete some nonexistent
|
||||
// certificate will "succeed" (it'll do nothing).
|
||||
await removeCertsByHashes([btoa("thishashisthewrongsize")]);
|
||||
},
|
||||
async function test_removal() {
|
||||
// As long as cert_storage is given valid base64, attempting to delete some nonexistent
|
||||
// certificate will "succeed" (it'll do nothing).
|
||||
await removeCertsByHashes([btoa("thishashisthewrongsize")]);
|
||||
|
||||
let removalCert1 = new CertInfo("removal certificate bytes 1", "common subject to remove");
|
||||
let removalCert2 = new CertInfo("removal certificate bytes 2", "common subject to remove");
|
||||
let removalCert3 = new CertInfo("removal certificate bytes 3", "common subject to remove");
|
||||
await addCerts([removalCert1, removalCert2, removalCert3]);
|
||||
let removalCert1 = new CertInfo(
|
||||
"removal certificate bytes 1",
|
||||
"common subject to remove"
|
||||
);
|
||||
let removalCert2 = new CertInfo(
|
||||
"removal certificate bytes 2",
|
||||
"common subject to remove"
|
||||
);
|
||||
let removalCert3 = new CertInfo(
|
||||
"removal certificate bytes 3",
|
||||
"common subject to remove"
|
||||
);
|
||||
await addCerts([removalCert1, removalCert2, removalCert3]);
|
||||
|
||||
let storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove"));
|
||||
let storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
let expectedCerts = ["removal certificate bytes 1", "removal certificate bytes 2",
|
||||
"removal certificate bytes 3"];
|
||||
Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(),
|
||||
"should find expected certs before removing them");
|
||||
let storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("common subject to remove")
|
||||
);
|
||||
let storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
let expectedCerts = [
|
||||
"removal certificate bytes 1",
|
||||
"removal certificate bytes 2",
|
||||
"removal certificate bytes 3",
|
||||
];
|
||||
Assert.deepEqual(
|
||||
storedCertsAsStrings.sort(),
|
||||
expectedCerts.sort(),
|
||||
"should find expected certs before removing them"
|
||||
);
|
||||
|
||||
// echo -n "removal certificate bytes 2" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["2nUPHwl5TVr1mAD1FU9FivLTlTb0BAdnVUhsYgBccN4="]);
|
||||
storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove"));
|
||||
storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
expectedCerts = ["removal certificate bytes 1", "removal certificate bytes 3"];
|
||||
Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(),
|
||||
"should only have first and third certificates now");
|
||||
// echo -n "removal certificate bytes 2" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["2nUPHwl5TVr1mAD1FU9FivLTlTb0BAdnVUhsYgBccN4="]);
|
||||
storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("common subject to remove")
|
||||
);
|
||||
storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
expectedCerts = [
|
||||
"removal certificate bytes 1",
|
||||
"removal certificate bytes 3",
|
||||
];
|
||||
Assert.deepEqual(
|
||||
storedCertsAsStrings.sort(),
|
||||
expectedCerts.sort(),
|
||||
"should only have first and third certificates now"
|
||||
);
|
||||
|
||||
// echo -n "removal certificate bytes 1" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["8zoRqHYrklr7Zx6UWpzrPuL+ol8KL1Ml6XHBQmXiaTY="]);
|
||||
storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove"));
|
||||
storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
expectedCerts = ["removal certificate bytes 3"];
|
||||
Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(),
|
||||
"should only have third certificate now");
|
||||
// echo -n "removal certificate bytes 1" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["8zoRqHYrklr7Zx6UWpzrPuL+ol8KL1Ml6XHBQmXiaTY="]);
|
||||
storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("common subject to remove")
|
||||
);
|
||||
storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
expectedCerts = ["removal certificate bytes 3"];
|
||||
Assert.deepEqual(
|
||||
storedCertsAsStrings.sort(),
|
||||
expectedCerts.sort(),
|
||||
"should only have third certificate now"
|
||||
);
|
||||
|
||||
// echo -n "removal certificate bytes 3" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="]);
|
||||
storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove"));
|
||||
Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now");
|
||||
// echo -n "removal certificate bytes 3" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="]);
|
||||
storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("common subject to remove")
|
||||
);
|
||||
Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now");
|
||||
|
||||
// echo -n "removal certificate bytes 3" | sha256sum | xxd -r -p | base64
|
||||
// Again, removing a nonexistent certificate should "succeed".
|
||||
await removeCertsByHashes(["vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="]);
|
||||
});
|
||||
// echo -n "removal certificate bytes 3" | sha256sum | xxd -r -p | base64
|
||||
// Again, removing a nonexistent certificate should "succeed".
|
||||
await removeCertsByHashes(["vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="]);
|
||||
}
|
||||
);
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_batched_removal() {
|
||||
let removalCert1 = new CertInfo("batch removal certificate bytes 1", "batch subject to remove");
|
||||
let removalCert2 = new CertInfo("batch removal certificate bytes 2", "batch subject to remove");
|
||||
let removalCert3 = new CertInfo("batch removal certificate bytes 3", "batch subject to remove");
|
||||
await addCerts([removalCert1, removalCert2, removalCert3]);
|
||||
let storedCerts = certStorage.findCertsBySubject(stringToArray("batch subject to remove"));
|
||||
let storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
let expectedCerts = ["batch removal certificate bytes 1", "batch removal certificate bytes 2",
|
||||
"batch removal certificate bytes 3"];
|
||||
Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(),
|
||||
"should find expected certs before removing them");
|
||||
// echo -n "batch removal certificate bytes 1" | sha256sum | xxd -r -p | base64
|
||||
// echo -n "batch removal certificate bytes 2" | sha256sum | xxd -r -p | base64
|
||||
// echo -n "batch removal certificate bytes 3" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes(["EOEEUTuanHZX9NFVCoMKVT22puIJC6g+ZuNPpJgvaa8=",
|
||||
"Xz6h/Kvn35cCLJEZXkjPqk1GG36b56sreLyAXpO+0zg=",
|
||||
"Jr7XdiTT8ZONUL+ogNNMW2oxKxanvYOLQPKBPgH/has="]);
|
||||
storedCerts = certStorage.findCertsBySubject(stringToArray("batch subject to remove"));
|
||||
Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now");
|
||||
});
|
||||
},
|
||||
async function test_batched_removal() {
|
||||
let removalCert1 = new CertInfo(
|
||||
"batch removal certificate bytes 1",
|
||||
"batch subject to remove"
|
||||
);
|
||||
let removalCert2 = new CertInfo(
|
||||
"batch removal certificate bytes 2",
|
||||
"batch subject to remove"
|
||||
);
|
||||
let removalCert3 = new CertInfo(
|
||||
"batch removal certificate bytes 3",
|
||||
"batch subject to remove"
|
||||
);
|
||||
await addCerts([removalCert1, removalCert2, removalCert3]);
|
||||
let storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("batch subject to remove")
|
||||
);
|
||||
let storedCertsAsStrings = storedCerts.map(arrayToString);
|
||||
let expectedCerts = [
|
||||
"batch removal certificate bytes 1",
|
||||
"batch removal certificate bytes 2",
|
||||
"batch removal certificate bytes 3",
|
||||
];
|
||||
Assert.deepEqual(
|
||||
storedCertsAsStrings.sort(),
|
||||
expectedCerts.sort(),
|
||||
"should find expected certs before removing them"
|
||||
);
|
||||
// echo -n "batch removal certificate bytes 1" | sha256sum | xxd -r -p | base64
|
||||
// echo -n "batch removal certificate bytes 2" | sha256sum | xxd -r -p | base64
|
||||
// echo -n "batch removal certificate bytes 3" | sha256sum | xxd -r -p | base64
|
||||
await removeCertsByHashes([
|
||||
"EOEEUTuanHZX9NFVCoMKVT22puIJC6g+ZuNPpJgvaa8=",
|
||||
"Xz6h/Kvn35cCLJEZXkjPqk1GG36b56sreLyAXpO+0zg=",
|
||||
"Jr7XdiTT8ZONUL+ogNNMW2oxKxanvYOLQPKBPgH/has=",
|
||||
]);
|
||||
storedCerts = certStorage.findCertsBySubject(
|
||||
stringToArray("batch subject to remove")
|
||||
);
|
||||
Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now");
|
||||
}
|
||||
);
|
||||
|
||||
class CRLiteState {
|
||||
constructor(subject, spkiHash, state) {
|
||||
|
|
@ -164,89 +274,132 @@ class CRLiteState {
|
|||
}
|
||||
}
|
||||
if (AppConstants.MOZ_NEW_CERT_STORAGE) {
|
||||
CRLiteState.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsICRLiteState]);
|
||||
CRLiteState.prototype.QueryInterface = ChromeUtils.generateQI([
|
||||
Ci.nsICRLiteState,
|
||||
]);
|
||||
}
|
||||
|
||||
async function addCRLiteState(state) {
|
||||
let result = await new Promise((resolve) => {
|
||||
let result = await new Promise(resolve => {
|
||||
certStorage.setCRLiteState(state, resolve);
|
||||
});
|
||||
Assert.equal(result, Cr.NS_OK, "setCRLiteState should succeed");
|
||||
}
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_crlite_state() {
|
||||
// echo -n "some spki 1" | sha256sum | xxd -r -p | base64
|
||||
let crliteState1 = new CRLiteState("some subject 1",
|
||||
"bDlKlhR5ptlvuxclnZ3RQHznG8/3pgIybrRJ/Zvn9L8=",
|
||||
Ci.nsICertStorage.STATE_ENFORCE);
|
||||
// echo -n "some spki 2" | sha256sum | xxd -r -p | base64
|
||||
let crliteState2 = new CRLiteState("some subject 2",
|
||||
"ZlXvlHhtdx4yKwkhZqg7Opv5T1ofwzorlsCoLf0wnlY=",
|
||||
Ci.nsICertStorage.STATE_UNSET);
|
||||
// echo -n "some spki 3" | sha256sum | xxd -r -p | base64
|
||||
let crliteState3 = new CRLiteState("some subject 3",
|
||||
"pp1SRn6njaHX/c+b2uf82JPeBkWhPfTBp/Mxb3xkjRM=",
|
||||
Ci.nsICertStorage.STATE_ENFORCE);
|
||||
await addCRLiteState([crliteState1, crliteState2, crliteState3]);
|
||||
},
|
||||
async function test_crlite_state() {
|
||||
// echo -n "some spki 1" | sha256sum | xxd -r -p | base64
|
||||
let crliteState1 = new CRLiteState(
|
||||
"some subject 1",
|
||||
"bDlKlhR5ptlvuxclnZ3RQHznG8/3pgIybrRJ/Zvn9L8=",
|
||||
Ci.nsICertStorage.STATE_ENFORCE
|
||||
);
|
||||
// echo -n "some spki 2" | sha256sum | xxd -r -p | base64
|
||||
let crliteState2 = new CRLiteState(
|
||||
"some subject 2",
|
||||
"ZlXvlHhtdx4yKwkhZqg7Opv5T1ofwzorlsCoLf0wnlY=",
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
);
|
||||
// echo -n "some spki 3" | sha256sum | xxd -r -p | base64
|
||||
let crliteState3 = new CRLiteState(
|
||||
"some subject 3",
|
||||
"pp1SRn6njaHX/c+b2uf82JPeBkWhPfTBp/Mxb3xkjRM=",
|
||||
Ci.nsICertStorage.STATE_ENFORCE
|
||||
);
|
||||
await addCRLiteState([crliteState1, crliteState2, crliteState3]);
|
||||
|
||||
let state1 = certStorage.getCRLiteState(stringToArray("some subject 1"),
|
||||
stringToArray("some spki 1"));
|
||||
Assert.equal(state1, Ci.nsICertStorage.STATE_ENFORCE);
|
||||
let state2 = certStorage.getCRLiteState(stringToArray("some subject 2"),
|
||||
stringToArray("some spki 2"));
|
||||
Assert.equal(state2, Ci.nsICertStorage.STATE_UNSET);
|
||||
let state3 = certStorage.getCRLiteState(stringToArray("some subject 3"),
|
||||
stringToArray("some spki 3"));
|
||||
Assert.equal(state3, Ci.nsICertStorage.STATE_ENFORCE);
|
||||
let state1 = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 1"),
|
||||
stringToArray("some spki 1")
|
||||
);
|
||||
Assert.equal(state1, Ci.nsICertStorage.STATE_ENFORCE);
|
||||
let state2 = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 2"),
|
||||
stringToArray("some spki 2")
|
||||
);
|
||||
Assert.equal(state2, Ci.nsICertStorage.STATE_UNSET);
|
||||
let state3 = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 3"),
|
||||
stringToArray("some spki 3")
|
||||
);
|
||||
Assert.equal(state3, Ci.nsICertStorage.STATE_ENFORCE);
|
||||
|
||||
// Check that if we never set the state of a particular subject/spki pair, we get "unset" when we
|
||||
// look it up.
|
||||
let stateNeverSet = certStorage.getCRLiteState(stringToArray("some unknown subject"),
|
||||
stringToArray("some unknown spki"));
|
||||
Assert.equal(stateNeverSet, Ci.nsICertStorage.STATE_UNSET);
|
||||
// Check that if we never set the state of a particular subject/spki pair, we get "unset" when we
|
||||
// look it up.
|
||||
let stateNeverSet = certStorage.getCRLiteState(
|
||||
stringToArray("some unknown subject"),
|
||||
stringToArray("some unknown spki")
|
||||
);
|
||||
Assert.equal(stateNeverSet, Ci.nsICertStorage.STATE_UNSET);
|
||||
|
||||
// "some subject 1"/"some spki 1" and "some subject 3"/"some spki 3" both have their CRLite state
|
||||
// set. However, the combination of "some subject 3"/"some spki1" should not.
|
||||
let stateDifferentSubjectSPKI = certStorage.getCRLiteState(stringToArray("some subject 3"),
|
||||
stringToArray("some spki 1"));
|
||||
Assert.equal(stateDifferentSubjectSPKI, Ci.nsICertStorage.STATE_UNSET);
|
||||
// "some subject 1"/"some spki 1" and "some subject 3"/"some spki 3" both have their CRLite state
|
||||
// set. However, the combination of "some subject 3"/"some spki1" should not.
|
||||
let stateDifferentSubjectSPKI = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 3"),
|
||||
stringToArray("some spki 1")
|
||||
);
|
||||
Assert.equal(stateDifferentSubjectSPKI, Ci.nsICertStorage.STATE_UNSET);
|
||||
|
||||
let anotherStateDifferentSubjectSPKI = certStorage.getCRLiteState(stringToArray("some subject 1"),
|
||||
stringToArray("some spki 2"));
|
||||
Assert.equal(anotherStateDifferentSubjectSPKI, Ci.nsICertStorage.STATE_UNSET);
|
||||
let yetAnotherStateDifferentSubjectSPKI =
|
||||
certStorage.getCRLiteState(stringToArray("some subject 2"), stringToArray("some spki 1"));
|
||||
Assert.equal(yetAnotherStateDifferentSubjectSPKI, Ci.nsICertStorage.STATE_UNSET);
|
||||
let anotherStateDifferentSubjectSPKI = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 1"),
|
||||
stringToArray("some spki 2")
|
||||
);
|
||||
Assert.equal(
|
||||
anotherStateDifferentSubjectSPKI,
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
);
|
||||
let yetAnotherStateDifferentSubjectSPKI = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 2"),
|
||||
stringToArray("some spki 1")
|
||||
);
|
||||
Assert.equal(
|
||||
yetAnotherStateDifferentSubjectSPKI,
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
);
|
||||
|
||||
crliteState3 = new CRLiteState("some subject 3",
|
||||
"pp1SRn6njaHX/c+b2uf82JPeBkWhPfTBp/Mxb3xkjRM=",
|
||||
Ci.nsICertStorage.STATE_UNSET);
|
||||
await addCRLiteState([crliteState3]);
|
||||
state3 = certStorage.getCRLiteState(stringToArray("some subject 3"),
|
||||
stringToArray("some spki 3"));
|
||||
Assert.equal(state3, Ci.nsICertStorage.STATE_UNSET);
|
||||
crliteState3 = new CRLiteState(
|
||||
"some subject 3",
|
||||
"pp1SRn6njaHX/c+b2uf82JPeBkWhPfTBp/Mxb3xkjRM=",
|
||||
Ci.nsICertStorage.STATE_UNSET
|
||||
);
|
||||
await addCRLiteState([crliteState3]);
|
||||
state3 = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 3"),
|
||||
stringToArray("some spki 3")
|
||||
);
|
||||
Assert.equal(state3, Ci.nsICertStorage.STATE_UNSET);
|
||||
|
||||
crliteState2 = new CRLiteState("some subject 2",
|
||||
"ZlXvlHhtdx4yKwkhZqg7Opv5T1ofwzorlsCoLf0wnlY=",
|
||||
Ci.nsICertStorage.STATE_ENFORCE);
|
||||
await addCRLiteState([crliteState2]);
|
||||
state2 = certStorage.getCRLiteState(stringToArray("some subject 2"),
|
||||
stringToArray("some spki 2"));
|
||||
Assert.equal(state2, Ci.nsICertStorage.STATE_ENFORCE);
|
||||
crliteState2 = new CRLiteState(
|
||||
"some subject 2",
|
||||
"ZlXvlHhtdx4yKwkhZqg7Opv5T1ofwzorlsCoLf0wnlY=",
|
||||
Ci.nsICertStorage.STATE_ENFORCE
|
||||
);
|
||||
await addCRLiteState([crliteState2]);
|
||||
state2 = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 2"),
|
||||
stringToArray("some spki 2")
|
||||
);
|
||||
Assert.equal(state2, Ci.nsICertStorage.STATE_ENFORCE);
|
||||
|
||||
// Inserting a subject/spki pair with a state value outside of our expected
|
||||
// values will succeed. However, since our data type is a signed 16-bit value,
|
||||
// values outside that range will be truncated. The least significant 16 bits
|
||||
// of 2013003773 are FFFD, which when interpreted as a signed 16-bit integer
|
||||
// comes out to -3.
|
||||
// echo -n "some spki 4" | sha256sum | xxd -r -p | base64
|
||||
let bogusValueState = new CRLiteState("some subject 4",
|
||||
"1eA0++hCqzt8vpzREYSqHAqpEOLchZca1Gx8viCVYzc=",
|
||||
2013003773);
|
||||
await addCRLiteState([bogusValueState]);
|
||||
let bogusValueStateValue = certStorage.getCRLiteState(stringToArray("some subject 4"),
|
||||
stringToArray("some spki 4"));
|
||||
Assert.equal(bogusValueStateValue, -3);
|
||||
});
|
||||
// Inserting a subject/spki pair with a state value outside of our expected
|
||||
// values will succeed. However, since our data type is a signed 16-bit value,
|
||||
// values outside that range will be truncated. The least significant 16 bits
|
||||
// of 2013003773 are FFFD, which when interpreted as a signed 16-bit integer
|
||||
// comes out to -3.
|
||||
// echo -n "some spki 4" | sha256sum | xxd -r -p | base64
|
||||
let bogusValueState = new CRLiteState(
|
||||
"some subject 4",
|
||||
"1eA0++hCqzt8vpzREYSqHAqpEOLchZca1Gx8viCVYzc=",
|
||||
2013003773
|
||||
);
|
||||
await addCRLiteState([bogusValueState]);
|
||||
let bogusValueStateValue = certStorage.getCRLiteState(
|
||||
stringToArray("some subject 4"),
|
||||
stringToArray("some spki 4")
|
||||
);
|
||||
Assert.equal(bogusValueStateValue, -3);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,45 +4,62 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
|
||||
// This file tests that cert_storage correctly persists its "has prior data"
|
||||
// information across runs of the browser.
|
||||
// (The test DB files for this test were created by running the test
|
||||
// `test_cert_storage_broken_db.js` and copying them from that test's profile
|
||||
// directory.)
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function() {
|
||||
let dbDirectory = do_get_profile();
|
||||
dbDirectory.append("security_state");
|
||||
let dbFile = do_get_file("test_cert_storage_preexisting/data.mdb");
|
||||
dbFile.copyTo(dbDirectory, "data.mdb");
|
||||
let lockFile = do_get_file("test_cert_storage_preexisting/lock.mdb");
|
||||
lockFile.copyTo(dbDirectory, "lock.mdb");
|
||||
},
|
||||
async function() {
|
||||
let dbDirectory = do_get_profile();
|
||||
dbDirectory.append("security_state");
|
||||
let dbFile = do_get_file("test_cert_storage_preexisting/data.mdb");
|
||||
dbFile.copyTo(dbDirectory, "data.mdb");
|
||||
let lockFile = do_get_file("test_cert_storage_preexisting/lock.mdb");
|
||||
lockFile.copyTo(dbDirectory, "lock.mdb");
|
||||
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let hasPriorRevocationData = await new Promise((resolve) => {
|
||||
certStorage.hasPriorData(Ci.nsICertStorage.DATA_TYPE_REVOCATION, (rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let hasPriorRevocationData = await new Promise(resolve => {
|
||||
certStorage.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_REVOCATION,
|
||||
(rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
Assert.equal(hasPriorRevocationData, true, "should have prior revocation data");
|
||||
Assert.equal(
|
||||
hasPriorRevocationData,
|
||||
true,
|
||||
"should have prior revocation data"
|
||||
);
|
||||
|
||||
let hasPriorCertData = await new Promise((resolve) => {
|
||||
certStorage.hasPriorData(Ci.nsICertStorage.DATA_TYPE_CERTIFICATE, (rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
let hasPriorCertData = await new Promise(resolve => {
|
||||
certStorage.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_CERTIFICATE,
|
||||
(rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
Assert.equal(hasPriorCertData, true, "should have prior cert data");
|
||||
Assert.equal(hasPriorCertData, true, "should have prior cert data");
|
||||
|
||||
let hasPriorCRLiteData = await new Promise((resolve) => {
|
||||
certStorage.hasPriorData(Ci.nsICertStorage.DATA_TYPE_CRLITE, (rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
let hasPriorCRLiteData = await new Promise(resolve => {
|
||||
certStorage.hasPriorData(
|
||||
Ci.nsICertStorage.DATA_TYPE_CRLITE,
|
||||
(rv, hasPriorData) => {
|
||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
||||
resolve(hasPriorData);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
Assert.equal(hasPriorCRLiteData, true, "should have prior cert data");
|
||||
});
|
||||
Assert.equal(hasPriorCRLiteData, true, "should have prior cert data");
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,17 +11,28 @@ function run_test() {
|
|||
return;
|
||||
}
|
||||
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
// Since none of our prefs start with values, looking them up will fail. cert_storage should use
|
||||
// safe fallbacks.
|
||||
ok(!certStorage.isBlocklistFresh(), "checking blocklist freshness shouldn't crash");
|
||||
ok(
|
||||
!certStorage.isBlocklistFresh(),
|
||||
"checking blocklist freshness shouldn't crash"
|
||||
);
|
||||
|
||||
// If we set nonsensical values, cert_storage should still use safe fallbacks.
|
||||
Services.prefs.setIntPref("services.blocklist.onecrl.checked", -2);
|
||||
Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds", -7);
|
||||
ok(!certStorage.isBlocklistFresh(), "checking blocklist freshness still shouldn't crash");
|
||||
ok(
|
||||
!certStorage.isBlocklistFresh(),
|
||||
"checking blocklist freshness still shouldn't crash"
|
||||
);
|
||||
|
||||
// Clearing prefs shouldn't cause failures.
|
||||
Services.prefs.clearUserPref("services.blocklist.onecrl.checked");
|
||||
ok(!certStorage.isBlocklistFresh(), "checking blocklist freshness again shouldn't crash");
|
||||
ok(
|
||||
!certStorage.isBlocklistFresh(),
|
||||
"checking blocklist freshness again shouldn't crash"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,141 +6,271 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function load_cert(cert_name, trust_string) {
|
||||
let cert_filename = cert_name + ".pem";
|
||||
return addCertFromFile(certdb, "test_cert_trust/" + cert_filename,
|
||||
trust_string);
|
||||
return addCertFromFile(
|
||||
certdb,
|
||||
"test_cert_trust/" + cert_filename,
|
||||
trust_string
|
||||
);
|
||||
}
|
||||
|
||||
function setup_basic_trusts(ca_cert, int_cert) {
|
||||
certdb.setCertTrust(ca_cert, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL |
|
||||
Ci.nsIX509CertDB.TRUSTED_EMAIL);
|
||||
certdb.setCertTrust(
|
||||
ca_cert,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL | Ci.nsIX509CertDB.TRUSTED_EMAIL
|
||||
);
|
||||
|
||||
certdb.setCertTrust(int_cert, Ci.nsIX509Cert.CA_CERT, 0);
|
||||
}
|
||||
|
||||
async function test_ca_distrust(ee_cert, cert_to_modify_trust, isRootCA) {
|
||||
// On reset most usages are successful
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
|
||||
// Test of active distrust. No usage should pass.
|
||||
setCertTrust(cert_to_modify_trust, "p,p,p");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
|
||||
// Trust set to T - trusted CA to issue client certs, where client cert is
|
||||
// usageSSLClient.
|
||||
setCertTrust(cert_to_modify_trust, "T,T,T");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
|
||||
// XXX(Bug 982340)
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
|
||||
// Now tests on the SSL trust bit
|
||||
setCertTrust(cert_to_modify_trust, "p,C,C");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
|
||||
// XXX(Bug 982340)
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
|
||||
// Inherited trust SSL
|
||||
setCertTrust(cert_to_modify_trust, ",C,C");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
// XXX(Bug 982340)
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
|
||||
// Now tests on the EMAIL trust bit
|
||||
setCertTrust(cert_to_modify_trust, "C,p,C");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailRecipient);
|
||||
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNTRUSTED_ISSUER,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
|
||||
// inherited EMAIL Trust
|
||||
setCertTrust(cert_to_modify_trust, "C,,C");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
|
||||
: PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
SEC_ERROR_CA_CERT_INVALID,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
isRootCA ? SEC_ERROR_UNKNOWN_ISSUER : PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
add_task(async function() {
|
||||
let certList = [
|
||||
"ca",
|
||||
"int",
|
||||
"ee",
|
||||
];
|
||||
let certList = ["ca", "int", "ee"];
|
||||
let loadedCerts = [];
|
||||
for (let certName of certList) {
|
||||
loadedCerts.push(load_cert(certName, ",,"));
|
||||
|
|
@ -167,12 +297,28 @@ add_task(async function() {
|
|||
// prefer not to build a hierarchy and instead directly trust a particular
|
||||
// server certificate.
|
||||
setCertTrust(ee_cert, "CTu,CTu,CTu");
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner);
|
||||
await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLClient
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailSigner
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certdb,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageEmailRecipient
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function run_test() {
|
||||
const pem =
|
||||
|
|
@ -48,31 +49,49 @@ function run_test() {
|
|||
// but isn't. Getting the asn1 structure of it exercises the code path that
|
||||
// decodes this value. If we don't assert in debug builds, presumably we
|
||||
// handled this value safely.
|
||||
notEqual(cert.ASN1Structure, null,
|
||||
"accessing nsIX509Cert.ASN1Structure shouldn't assert");
|
||||
notEqual(
|
||||
cert.ASN1Structure,
|
||||
null,
|
||||
"accessing nsIX509Cert.ASN1Structure shouldn't assert"
|
||||
);
|
||||
|
||||
// This certificate has a number of placeholder byte sequences that we can
|
||||
// replace with invalid UTF-8 to ensure that we handle these cases safely.
|
||||
let certificateToAlterFile =
|
||||
do_get_file("test_cert_utf8/certificateToAlter.pem", false);
|
||||
let certificateBytesToAlter =
|
||||
atob(pemToBase64(readFile(certificateToAlterFile)));
|
||||
let certificateToAlterFile = do_get_file(
|
||||
"test_cert_utf8/certificateToAlter.pem",
|
||||
false
|
||||
);
|
||||
let certificateBytesToAlter = atob(
|
||||
pemToBase64(readFile(certificateToAlterFile))
|
||||
);
|
||||
testUTF8InField("issuerName", "ISSUER CN", certificateBytesToAlter);
|
||||
testUTF8InField("issuerOrganization", "ISSUER O", certificateBytesToAlter);
|
||||
testUTF8InField("issuerOrganizationUnit", "ISSUER OU",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField(
|
||||
"issuerOrganizationUnit",
|
||||
"ISSUER OU",
|
||||
certificateBytesToAlter
|
||||
);
|
||||
testUTF8InField("issuerCommonName", "ISSUER CN", certificateBytesToAlter);
|
||||
testUTF8InField("organization", "SUBJECT O", certificateBytesToAlter);
|
||||
testUTF8InField("organizationalUnit", "SUBJECT OU", certificateBytesToAlter);
|
||||
testUTF8InField("subjectName", "SUBJECT CN", certificateBytesToAlter);
|
||||
testUTF8InField("displayName", "SUBJECT CN", certificateBytesToAlter);
|
||||
testUTF8InField("commonName", "SUBJECT CN", certificateBytesToAlter);
|
||||
testUTF8InField("emailAddress", "SUBJECT EMAILADDRESS",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField("subjectAltNames", "SUBJECT ALT DNSNAME",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField("subjectAltNames", "SUBJECT ALT RFC822@NAME",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField(
|
||||
"emailAddress",
|
||||
"SUBJECT EMAILADDRESS",
|
||||
certificateBytesToAlter
|
||||
);
|
||||
testUTF8InField(
|
||||
"subjectAltNames",
|
||||
"SUBJECT ALT DNSNAME",
|
||||
certificateBytesToAlter
|
||||
);
|
||||
testUTF8InField(
|
||||
"subjectAltNames",
|
||||
"SUBJECT ALT RFC822@NAME",
|
||||
certificateBytesToAlter
|
||||
);
|
||||
}
|
||||
|
||||
// Every (issuer, serial number) pair must be unique. If NSS ever encounters two
|
||||
|
|
@ -91,18 +110,28 @@ function testUTF8InField(field, replacementPrefix, certificateBytesToAlter) {
|
|||
replacement += "\xEB";
|
||||
}
|
||||
let bytes = certificateBytesToAlter.replace(toReplace, replacement);
|
||||
let uniqueIssuerReplacement = "ALWAYS MAKE ME UNIQU" +
|
||||
String.fromCharCode(gUniqueIssuerCounter);
|
||||
let uniqueIssuerReplacement =
|
||||
"ALWAYS MAKE ME UNIQU" + String.fromCharCode(gUniqueIssuerCounter);
|
||||
bytes = bytes.replace("ALWAYS MAKE ME UNIQUE", uniqueIssuerReplacement);
|
||||
ok(gUniqueIssuerCounter < 127,
|
||||
"should have enough ASCII replacements to make a unique issuer DN");
|
||||
ok(
|
||||
gUniqueIssuerCounter < 127,
|
||||
"should have enough ASCII replacements to make a unique issuer DN"
|
||||
);
|
||||
gUniqueIssuerCounter++;
|
||||
let cert = gCertDB.constructX509(bytes);
|
||||
notEqual(cert[field], null, `accessing nsIX509Cert.${field} shouldn't fail`);
|
||||
notEqual(cert.ASN1Structure, null,
|
||||
"accessing nsIX509Cert.ASN1Structure shouldn't assert");
|
||||
notEqual(cert.getEmailAddresses(), null,
|
||||
"calling nsIX509Cert.getEmailAddresses() shouldn't assert");
|
||||
ok(!cert.containsEmailAddress("test@test.test"),
|
||||
"calling nsIX509Cert.containsEmailAddress() shouldn't assert");
|
||||
notEqual(
|
||||
cert.ASN1Structure,
|
||||
null,
|
||||
"accessing nsIX509Cert.ASN1Structure shouldn't assert"
|
||||
);
|
||||
notEqual(
|
||||
cert.getEmailAddresses(),
|
||||
null,
|
||||
"calling nsIX509Cert.getEmailAddresses() shouldn't assert"
|
||||
);
|
||||
ok(
|
||||
!cert.containsEmailAddress("test@test.test"),
|
||||
"calling nsIX509Cert.containsEmailAddress() shouldn't assert"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,25 +30,38 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function certFromFile(certName) {
|
||||
return constructCertFromFile("test_cert_version/" + certName + ".pem");
|
||||
}
|
||||
|
||||
function loadCertWithTrust(certName, trustString) {
|
||||
addCertFromFile(certdb, "test_cert_version/" + certName + ".pem", trustString);
|
||||
addCertFromFile(
|
||||
certdb,
|
||||
"test_cert_version/" + certName + ".pem",
|
||||
trustString
|
||||
);
|
||||
}
|
||||
|
||||
function checkEndEntity(cert, expectedResult) {
|
||||
return checkCertErrorGeneric(certdb, cert, expectedResult,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
expectedResult,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
function checkIntermediate(cert, expectedResult) {
|
||||
return checkCertErrorGeneric(certdb, cert, expectedResult,
|
||||
certificateUsageSSLCA);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
expectedResult,
|
||||
certificateUsageSSLCA
|
||||
);
|
||||
}
|
||||
|
||||
// Test that the code that decodes certificates to display them in the
|
||||
|
|
@ -57,8 +70,11 @@ function checkCertVersion(cert, expectedVersionString) {
|
|||
let asn1 = cert.ASN1Structure.QueryInterface(Ci.nsIASN1Sequence);
|
||||
let tbsCertificate = asn1.ASN1Objects.queryElementAt(0, Ci.nsIASN1Sequence);
|
||||
let version = tbsCertificate.ASN1Objects.queryElementAt(0, Ci.nsIASN1Object);
|
||||
equal(version.displayValue, expectedVersionString,
|
||||
"Actual and expected version strings should match");
|
||||
equal(
|
||||
version.displayValue,
|
||||
expectedVersionString,
|
||||
"Actual and expected version strings should match"
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
@ -66,8 +82,14 @@ add_task(async function() {
|
|||
|
||||
// Section for CAs lacking the basicConstraints extension entirely:
|
||||
loadCertWithTrust("int-v1-noBC_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v1-noBC_ca"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
|
||||
await checkEndEntity(certFromFile("ee_int-v1-noBC"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v1-noBC_ca"),
|
||||
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v1-noBC"),
|
||||
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA
|
||||
);
|
||||
// A v1 certificate with no basicConstraints extension may issue certificates
|
||||
// if it is a trust anchor.
|
||||
loadCertWithTrust("int-v1-noBC_ca", "CTu,,");
|
||||
|
|
@ -75,54 +97,138 @@ add_task(async function() {
|
|||
await checkEndEntity(certFromFile("ee_int-v1-noBC"), PRErrorCodeSuccess);
|
||||
|
||||
loadCertWithTrust("int-v2-noBC_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v2-noBC_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v2-noBC"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v2-noBC_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v2-noBC_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v2-noBC"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
loadCertWithTrust("int-v3-noBC_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v3-noBC_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v3-noBC"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v3-noBC_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v3-noBC_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v3-noBC"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
loadCertWithTrust("int-v4-noBC_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v4-noBC_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v4-noBC"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v4-noBC_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v4-noBC_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v4-noBC"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
// Section for CAs with basicConstraints not specifying cA:
|
||||
loadCertWithTrust("int-v1-BC-not-cA_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v1-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v1-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v1-BC-not-cA_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v1-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v1-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
loadCertWithTrust("int-v2-BC-not-cA_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v2-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v2-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v2-BC-not-cA_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v2-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v2-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
loadCertWithTrust("int-v3-BC-not-cA_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v3-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v3-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v3-BC-not-cA_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v3-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v3-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
loadCertWithTrust("int-v4-BC-not-cA_ca", ",,");
|
||||
await checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v4-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v4-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
loadCertWithTrust("int-v4-BC-not-cA_ca", "CTu,,");
|
||||
await checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
|
||||
await checkIntermediate(
|
||||
certFromFile("int-v4-BC-not-cA_ca"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee_int-v4-BC-not-cA"),
|
||||
SEC_ERROR_CA_CERT_INVALID
|
||||
);
|
||||
|
||||
// Section for CAs with basicConstraints specifying cA:
|
||||
loadCertWithTrust("int-v1-BC-cA_ca", ",,");
|
||||
|
|
@ -164,10 +270,22 @@ add_task(async function() {
|
|||
await checkEndEntity(certFromFile("ee-v3-BC-not-cA_ca"), PRErrorCodeSuccess);
|
||||
await checkEndEntity(certFromFile("ee-v4-BC-not-cA_ca"), PRErrorCodeSuccess);
|
||||
|
||||
await checkEndEntity(certFromFile("ee-v1-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
|
||||
await checkEndEntity(certFromFile("ee-v2-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
|
||||
await checkEndEntity(certFromFile("ee-v3-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
|
||||
await checkEndEntity(certFromFile("ee-v4-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-v1-BC-cA_ca"),
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-v2-BC-cA_ca"),
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-v3-BC-cA_ca"),
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ee-v4-BC-cA_ca"),
|
||||
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
|
||||
);
|
||||
|
||||
// Section for self-signed certificates:
|
||||
await checkEndEntity(certFromFile("ss-v1-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
|
|
@ -175,10 +293,22 @@ add_task(async function() {
|
|||
await checkEndEntity(certFromFile("ss-v3-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
await checkEndEntity(certFromFile("ss-v4-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
|
||||
await checkEndEntity(certFromFile("ss-v1-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
await checkEndEntity(certFromFile("ss-v2-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
await checkEndEntity(certFromFile("ss-v3-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
await checkEndEntity(certFromFile("ss-v4-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
await checkEndEntity(
|
||||
certFromFile("ss-v1-BC-not-cA"),
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ss-v2-BC-not-cA"),
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ss-v3-BC-not-cA"),
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
await checkEndEntity(
|
||||
certFromFile("ss-v4-BC-not-cA"),
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
|
||||
await checkEndEntity(certFromFile("ss-v1-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
await checkEndEntity(certFromFile("ss-v2-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
// Checks that invalid OID encodings are detected in the Cert Viewer Details tab.
|
||||
|
||||
do_get_profile(); // Must be called before getting nsIX509CertDB
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function certFromFile(filename) {
|
||||
return constructCertFromFile(`test_certviewer_invalid_oids/${filename}.pem`);
|
||||
|
|
@ -16,47 +17,51 @@ function certFromFile(filename) {
|
|||
|
||||
function test(certFilename, expectedOIDText) {
|
||||
let cert = certFromFile(certFilename);
|
||||
let certDumpTree = Cc["@mozilla.org/security/nsASN1Tree;1"]
|
||||
.createInstance(Ci.nsIASN1Tree);
|
||||
let certDumpTree = Cc["@mozilla.org/security/nsASN1Tree;1"].createInstance(
|
||||
Ci.nsIASN1Tree
|
||||
);
|
||||
certDumpTree.loadASN1Structure(cert.ASN1Structure);
|
||||
let actualOIDText = certDumpTree.getDisplayData(9);
|
||||
|
||||
equal(actualOIDText, expectedOIDText,
|
||||
"Actual and expected OID text should match");
|
||||
equal(
|
||||
actualOIDText,
|
||||
expectedOIDText,
|
||||
"Actual and expected OID text should match"
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
test("bug483440-attack2b",
|
||||
"Object Identifier (2 5 4 Unknown) = www.bank.com\n" +
|
||||
"OU = Hacking Division\n" +
|
||||
"CN = www.badguy.com\nO = Badguy Inc\n");
|
||||
test(
|
||||
"bug483440-attack2b",
|
||||
"Object Identifier (2 5 4 Unknown) = www.bank.com\n" +
|
||||
"OU = Hacking Division\n" +
|
||||
"CN = www.badguy.com\nO = Badguy Inc\n"
|
||||
);
|
||||
|
||||
test("bug483440-pk10oflo",
|
||||
"Object Identifier (2 5 4 Unknown) = www.bank.com\n" +
|
||||
"OU = Hacking Division\n" +
|
||||
"CN = www.badguy.com\nO = Badguy Inc\n");
|
||||
test(
|
||||
"bug483440-pk10oflo",
|
||||
"Object Identifier (2 5 4 Unknown) = www.bank.com\n" +
|
||||
"OU = Hacking Division\n" +
|
||||
"CN = www.badguy.com\nO = Badguy Inc\n"
|
||||
);
|
||||
|
||||
test("bug483440-attack7",
|
||||
test(
|
||||
"bug483440-attack7",
|
||||
|
||||
// Check 88 80 80 80 01, not leading, have to pass
|
||||
"Object Identifier (2 5 4 2147483649) = attack1\n" +
|
||||
|
||||
// Check 90 80 80 80 01, not leading, have to fail
|
||||
"Object Identifier (2 5 4 Unknown) = attack2\n" +
|
||||
|
||||
// Check 80 80 80 80 80, not leading, have to fail
|
||||
"Object Identifier (2 5 4 Unknown) = attack3\n" +
|
||||
|
||||
// Check 81 81, trailing, have to fail
|
||||
"Object Identifier (2 5 4 3 Unknown) = attack4\n" +
|
||||
|
||||
// Check FF FF FF 7F, not leading, have to pass
|
||||
"Object Identifier (2 5 4 268435455) = attack5\n" +
|
||||
|
||||
// Check 80 leading, have to fail
|
||||
"Object Identifier (Unknown 3) = attack6\n" +
|
||||
|
||||
// Check 14757 = 2*40 + 14677 leading single byte encoded as F325,
|
||||
// have to pass
|
||||
"Object Identifier (2 14677 4 3) = attack7\n");
|
||||
// Check 88 80 80 80 01, not leading, have to pass
|
||||
"Object Identifier (2 5 4 2147483649) = attack1\n" +
|
||||
// Check 90 80 80 80 01, not leading, have to fail
|
||||
"Object Identifier (2 5 4 Unknown) = attack2\n" +
|
||||
// Check 80 80 80 80 80, not leading, have to fail
|
||||
"Object Identifier (2 5 4 Unknown) = attack3\n" +
|
||||
// Check 81 81, trailing, have to fail
|
||||
"Object Identifier (2 5 4 3 Unknown) = attack4\n" +
|
||||
// Check FF FF FF 7F, not leading, have to pass
|
||||
"Object Identifier (2 5 4 268435455) = attack5\n" +
|
||||
// Check 80 leading, have to fail
|
||||
"Object Identifier (Unknown 3) = attack6\n" +
|
||||
// Check 14757 = 2*40 + 14677 leading single byte encoded as F325,
|
||||
// have to pass
|
||||
"Object Identifier (2 14677 4 3) = attack7\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
// input.
|
||||
|
||||
do_get_profile(); // Must be called before getting nsIX509CertDB
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function excMessage(e) {
|
||||
if (e.message) {
|
||||
|
|
@ -26,8 +27,11 @@ function excMessage(e) {
|
|||
function testGood(data) {
|
||||
try {
|
||||
let cert = certDB.constructX509FromBase64(data.cert);
|
||||
equal(cert.commonName, data.cn,
|
||||
"Actual and expected commonName should match");
|
||||
equal(
|
||||
cert.commonName,
|
||||
data.cn,
|
||||
"Actual and expected commonName should match"
|
||||
);
|
||||
} catch (e) {
|
||||
info(`Exception: ${excMessage(e)}`);
|
||||
ok(false, `Should not have gotten an exception for "CN=${data.cn}"`);
|
||||
|
|
@ -35,8 +39,11 @@ function testGood(data) {
|
|||
}
|
||||
|
||||
function testBad(data) {
|
||||
throws(() => certDB.constructX509FromBase64(data.input), data.result,
|
||||
`Should get "${data.result}" for "${data.input}"`);
|
||||
throws(
|
||||
() => certDB.constructX509FromBase64(data.input),
|
||||
data.result,
|
||||
`Should get "${data.result}" for "${data.input}"`
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -49,15 +56,29 @@ function run_test() {
|
|||
// Not base64
|
||||
{ input: "forty-four dead stone lions", result: /NS_ERROR_ILLEGAL_VALUE/ },
|
||||
// Not a cert
|
||||
{ input: "Zm9ydHktZm91ciBkZWFkIHN0b25lIGxpb25z",
|
||||
result: /NS_ERROR_FAILURE/ },
|
||||
{
|
||||
input: "Zm9ydHktZm91ciBkZWFkIHN0b25lIGxpb25z",
|
||||
result: /NS_ERROR_FAILURE/,
|
||||
},
|
||||
];
|
||||
|
||||
// Real certs with all three padding levels
|
||||
const goodCases = [
|
||||
{ cn: "A", cert: "MIHhMIGcAgEAMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMTEwMzIzMjMyNTE3WhcNMTEwNDIyMjMyNTE3WjAMMQowCAYDVQQDEwFBMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxANFm7ZCfYNJViaDWTFuMClX3+9u18VFGiyLfM6xJrxir4QVtQC7VUC/WUGoBUs9COQIDAQABMA0GCSqGSIb3DQEBBQUAAzEAx2+gIwmuYjJO5SyabqIm4lB1MandHH1HQc0y0tUFshBOMESTzQRPSVwPn77a6R9t" },
|
||||
{ cn: "Bo", cert: "MIHjMIGeAgEAMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAMTAkJvMB4XDTExMDMyMzIzMjYwMloXDTExMDQyMjIzMjYwMlowDTELMAkGA1UEAxMCQm8wTDANBgkqhkiG9w0BAQEFAAM7ADA4AjEA1FoSl9w9HqMqVgk2K0J3OTiRsgHeNsQdPUl6S82ME33gH+E56PcWZA3nse+fpS3NAgMBAAEwDQYJKoZIhvcNAQEFBQADMQAo/e3BvQAmygiATljQ68tWPoWcbMwa1xxAvpWTEc1LOvMqeDBinBUqbAbSmPhGWb4=" },
|
||||
{ cn: "Cid", cert: "MIHlMIGgAgEAMA0GCSqGSIb3DQEBBQUAMA4xDDAKBgNVBAMTA0NpZDAeFw0xMTAzMjMyMzI2MzJaFw0xMTA0MjIyMzI2MzJaMA4xDDAKBgNVBAMTA0NpZDBMMA0GCSqGSIb3DQEBAQUAAzsAMDgCMQDUUxlF5xKN+8KCSsR83sN+SRwJmZdliXsnBB7PU0OgbmOWN0u8yehRkmu39kN9tzcCAwEAATANBgkqhkiG9w0BAQUFAAMxAJ3UScNqRcjHFrNu4nuwRldZLJlVJvRYXp982V4/kYodQEGN4gJ+Qyj+HTsaXy5x/w==" },
|
||||
{
|
||||
cn: "A",
|
||||
cert:
|
||||
"MIHhMIGcAgEAMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMTEwMzIzMjMyNTE3WhcNMTEwNDIyMjMyNTE3WjAMMQowCAYDVQQDEwFBMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxANFm7ZCfYNJViaDWTFuMClX3+9u18VFGiyLfM6xJrxir4QVtQC7VUC/WUGoBUs9COQIDAQABMA0GCSqGSIb3DQEBBQUAAzEAx2+gIwmuYjJO5SyabqIm4lB1MandHH1HQc0y0tUFshBOMESTzQRPSVwPn77a6R9t",
|
||||
},
|
||||
{
|
||||
cn: "Bo",
|
||||
cert:
|
||||
"MIHjMIGeAgEAMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAMTAkJvMB4XDTExMDMyMzIzMjYwMloXDTExMDQyMjIzMjYwMlowDTELMAkGA1UEAxMCQm8wTDANBgkqhkiG9w0BAQEFAAM7ADA4AjEA1FoSl9w9HqMqVgk2K0J3OTiRsgHeNsQdPUl6S82ME33gH+E56PcWZA3nse+fpS3NAgMBAAEwDQYJKoZIhvcNAQEFBQADMQAo/e3BvQAmygiATljQ68tWPoWcbMwa1xxAvpWTEc1LOvMqeDBinBUqbAbSmPhGWb4=",
|
||||
},
|
||||
{
|
||||
cn: "Cid",
|
||||
cert:
|
||||
"MIHlMIGgAgEAMA0GCSqGSIb3DQEBBQUAMA4xDDAKBgNVBAMTA0NpZDAeFw0xMTAzMjMyMzI2MzJaFw0xMTA0MjIyMzI2MzJaMA4xDDAKBgNVBAMTA0NpZDBMMA0GCSqGSIb3DQEBAQUAAzsAMDgCMQDUUxlF5xKN+8KCSsR83sN+SRwJmZdliXsnBB7PU0OgbmOWN0u8yehRkmu39kN9tzcCAwEAATANBgkqhkiG9w0BAQUFAAMxAJ3UScNqRcjHFrNu4nuwRldZLJlVJvRYXp982V4/kYodQEGN4gJ+Qyj+HTsaXy5x/w==",
|
||||
},
|
||||
];
|
||||
|
||||
for (let badCase of badCases) {
|
||||
|
|
|
|||
|
|
@ -13,14 +13,17 @@ const TEST_DATA_DIR = "test_content_signing/";
|
|||
|
||||
const ONECRL_NAME = "oneCRL-signer.mozilla.org";
|
||||
const ABOUT_NEWTAB_NAME = "remotenewtab.content-signature.mozilla.org";
|
||||
var VERIFICATION_HISTOGRAM = Services.telemetry
|
||||
.getHistogramById("CONTENT_SIGNATURE_VERIFICATION_STATUS");
|
||||
var ERROR_HISTOGRAM = Services.telemetry
|
||||
.getKeyedHistogramById("CONTENT_SIGNATURE_VERIFICATION_ERRORS");
|
||||
var VERIFICATION_HISTOGRAM = Services.telemetry.getHistogramById(
|
||||
"CONTENT_SIGNATURE_VERIFICATION_STATUS"
|
||||
);
|
||||
var ERROR_HISTOGRAM = Services.telemetry.getKeyedHistogramById(
|
||||
"CONTENT_SIGNATURE_VERIFICATION_ERRORS"
|
||||
);
|
||||
|
||||
function getSignatureVerifier() {
|
||||
return Cc["@mozilla.org/security/contentsignatureverifier;1"]
|
||||
.getService(Ci.nsIContentSignatureVerifier);
|
||||
return Cc["@mozilla.org/security/contentsignatureverifier;1"].getService(
|
||||
Ci.nsIContentSignatureVerifier
|
||||
);
|
||||
}
|
||||
|
||||
function setRoot(filename) {
|
||||
|
|
@ -55,9 +58,16 @@ function check_telemetry(expected_index, expected, expectedId) {
|
|||
equal(k, expectedId);
|
||||
equal(errorSnapshot[k].values[i] || 0, expected_value);
|
||||
}
|
||||
equal(VERIFICATION_HISTOGRAM.snapshot().values[i] || 0, expected_value,
|
||||
"count " + i + ": " + VERIFICATION_HISTOGRAM.snapshot().values[i] +
|
||||
" expected " + expected_value);
|
||||
equal(
|
||||
VERIFICATION_HISTOGRAM.snapshot().values[i] || 0,
|
||||
expected_value,
|
||||
"count " +
|
||||
i +
|
||||
": " +
|
||||
VERIFICATION_HISTOGRAM.snapshot().values[i] +
|
||||
" expected " +
|
||||
expected_value
|
||||
);
|
||||
}
|
||||
VERIFICATION_HISTOGRAM.clear();
|
||||
ERROR_HISTOGRAM.clear();
|
||||
|
|
@ -66,168 +76,293 @@ function check_telemetry(expected_index, expected, expectedId) {
|
|||
add_task(async function run_test() {
|
||||
// set up some data
|
||||
const DATA = readFile(do_get_file(TEST_DATA_DIR + "test.txt"));
|
||||
const GOOD_SIGNATURE = "p384ecdsa=" +
|
||||
readFile(do_get_file(TEST_DATA_DIR + "test.txt.signature"))
|
||||
.trim();
|
||||
const GOOD_SIGNATURE =
|
||||
"p384ecdsa=" +
|
||||
readFile(do_get_file(TEST_DATA_DIR + "test.txt.signature")).trim();
|
||||
|
||||
const BAD_SIGNATURE = "p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2r" +
|
||||
"UWM4GJke4pE8ecHiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1G" +
|
||||
"q25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L";
|
||||
const BAD_SIGNATURE =
|
||||
"p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2r" +
|
||||
"UWM4GJke4pE8ecHiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1G" +
|
||||
"q25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L";
|
||||
|
||||
let remoteNewTabChain = loadChain(TEST_DATA_DIR + "content_signing",
|
||||
["remote_newtab_ee", "int", "root"]);
|
||||
let remoteNewTabChain = loadChain(TEST_DATA_DIR + "content_signing", [
|
||||
"remote_newtab_ee",
|
||||
"int",
|
||||
"root",
|
||||
]);
|
||||
|
||||
let oneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
|
||||
["onecrl_ee", "int", "root"]);
|
||||
let oneCRLChain = loadChain(TEST_DATA_DIR + "content_signing", [
|
||||
"onecrl_ee",
|
||||
"int",
|
||||
"root",
|
||||
]);
|
||||
|
||||
let oneCRLBadKeyChain = loadChain(TEST_DATA_DIR + "content_signing",
|
||||
["onecrl_wrong_key_ee", "int", "root"]);
|
||||
let oneCRLBadKeyChain = loadChain(TEST_DATA_DIR + "content_signing", [
|
||||
"onecrl_wrong_key_ee",
|
||||
"int",
|
||||
"root",
|
||||
]);
|
||||
|
||||
let noSANChain = loadChain(TEST_DATA_DIR + "content_signing",
|
||||
["onecrl_no_SAN_ee", "int", "root"]);
|
||||
let noSANChain = loadChain(TEST_DATA_DIR + "content_signing", [
|
||||
"onecrl_no_SAN_ee",
|
||||
"int",
|
||||
"root",
|
||||
]);
|
||||
|
||||
let expiredOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
|
||||
["onecrl_ee_expired", "int", "root"]);
|
||||
let expiredOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing", [
|
||||
"onecrl_ee_expired",
|
||||
"int",
|
||||
"root",
|
||||
]);
|
||||
|
||||
let notValidYetOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
|
||||
["onecrl_ee_not_valid_yet", "int",
|
||||
"root"]);
|
||||
let notValidYetOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing", [
|
||||
"onecrl_ee_not_valid_yet",
|
||||
"int",
|
||||
"root",
|
||||
]);
|
||||
|
||||
// Check signature verification works without error before the root is set
|
||||
VERIFICATION_HISTOGRAM.clear();
|
||||
let chain1 = oneCRLChain.join("\n");
|
||||
let verifier = getSignatureVerifier();
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
|
||||
"Before the root is set, signatures should fail to verify but not throw.");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"Before the root is set, signatures should fail to verify but not throw."
|
||||
);
|
||||
// Check for generic chain building error.
|
||||
check_telemetry(6, 1, getCertHash("content_signing_onecrl_ee"));
|
||||
|
||||
setRoot(TEST_DATA_DIR + "content_signing_root.pem");
|
||||
|
||||
// Check good signatures from good certificates with the correct SAN
|
||||
ok(await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
|
||||
"A OneCRL signature should verify with the OneCRL chain");
|
||||
ok(
|
||||
await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
),
|
||||
"A OneCRL signature should verify with the OneCRL chain"
|
||||
);
|
||||
let chain2 = remoteNewTabChain.join("\n");
|
||||
ok(await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
|
||||
ABOUT_NEWTAB_NAME),
|
||||
"A newtab signature should verify with the newtab chain");
|
||||
ok(
|
||||
await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain2,
|
||||
ABOUT_NEWTAB_NAME
|
||||
),
|
||||
"A newtab signature should verify with the newtab chain"
|
||||
);
|
||||
// Check for valid signature
|
||||
check_telemetry(0, 2, getCertHash("content_signing_remote_newtab_ee"));
|
||||
|
||||
// Check a bad signature when a good chain is provided
|
||||
chain1 = oneCRLChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, BAD_SIGNATURE, chain1, ONECRL_NAME),
|
||||
"A bad signature should not verify");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
BAD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A bad signature should not verify"
|
||||
);
|
||||
// Check for invalid signature
|
||||
check_telemetry(1, 1, getCertHash("content_signing_onecrl_ee"));
|
||||
|
||||
// Check a good signature from cert with good SAN but a different key than the
|
||||
// one used to create the signature
|
||||
let badKeyChain = oneCRLBadKeyChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, badKeyChain,
|
||||
ONECRL_NAME),
|
||||
"A signature should not verify if the signing key is wrong");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
badKeyChain,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A signature should not verify if the signing key is wrong"
|
||||
);
|
||||
// Check for wrong key in cert.
|
||||
check_telemetry(9, 1, getCertHash("content_signing_onecrl_wrong_key_ee"));
|
||||
|
||||
// Check a good signature from cert with good SAN but a different key than the
|
||||
// one used to create the signature (this time, an RSA key)
|
||||
let rsaKeyChain = oneCRLBadKeyChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, rsaKeyChain,
|
||||
ONECRL_NAME),
|
||||
"A signature should not verify if the signing key is wrong (RSA)");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
rsaKeyChain,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A signature should not verify if the signing key is wrong (RSA)"
|
||||
);
|
||||
// Check for wrong key in cert.
|
||||
check_telemetry(9, 1, getCertHash("content_signing_onecrl_wrong_key_ee"));
|
||||
|
||||
// Check a good signature from cert with good SAN but with chain missing root
|
||||
let missingRoot = [oneCRLChain[0], oneCRLChain[1]].join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, missingRoot,
|
||||
ONECRL_NAME),
|
||||
"A signature should not verify if the chain is incomplete (missing root)");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
missingRoot,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A signature should not verify if the chain is incomplete (missing root)"
|
||||
);
|
||||
// Check for generic chain building error.
|
||||
check_telemetry(6, 1, getCertHash("content_signing_onecrl_ee"));
|
||||
|
||||
// Check a good signature from cert with good SAN but with no path to root
|
||||
let missingInt = [oneCRLChain[0], oneCRLChain[2]].join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, missingInt,
|
||||
ONECRL_NAME),
|
||||
"A signature should not verify if the chain is incomplete (missing int)");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
missingInt,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A signature should not verify if the chain is incomplete (missing int)"
|
||||
);
|
||||
// Check for generic chain building error.
|
||||
check_telemetry(6, 1, getCertHash("content_signing_onecrl_ee"));
|
||||
|
||||
// Check good signatures from good certificates with the wrong SANs
|
||||
chain1 = oneCRLChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
|
||||
ABOUT_NEWTAB_NAME),
|
||||
"A OneCRL signature should not verify if we require the newtab SAN");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ABOUT_NEWTAB_NAME
|
||||
)),
|
||||
"A OneCRL signature should not verify if we require the newtab SAN"
|
||||
);
|
||||
// Check for invalid EE cert.
|
||||
check_telemetry(7, 1, getCertHash("content_signing_onecrl_ee"));
|
||||
|
||||
chain2 = remoteNewTabChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
|
||||
ONECRL_NAME),
|
||||
"A newtab signature should not verify if we require the OneCRL SAN");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain2,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A newtab signature should not verify if we require the OneCRL SAN"
|
||||
);
|
||||
// Check for invalid EE cert.
|
||||
check_telemetry(7, 1, getCertHash("content_signing_remote_newtab_ee"));
|
||||
|
||||
// Check good signatures with good chains with some other invalid names
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ""),
|
||||
"A signature should not verify if the SANs do not match an empty name");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
""
|
||||
)),
|
||||
"A signature should not verify if the SANs do not match an empty name"
|
||||
);
|
||||
// Check for invalid EE cert.
|
||||
check_telemetry(7, 1, getCertHash("content_signing_onecrl_ee"));
|
||||
|
||||
// Test expired certificate.
|
||||
let chainExpired = expiredOneCRLChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chainExpired, ""),
|
||||
"A signature should not verify if the signing certificate is expired");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chainExpired,
|
||||
""
|
||||
)),
|
||||
"A signature should not verify if the signing certificate is expired"
|
||||
);
|
||||
// Check for expired cert.
|
||||
check_telemetry(4, 1, getCertHash("content_signing_onecrl_ee_expired"));
|
||||
|
||||
// Test not valid yet certificate.
|
||||
let chainNotValidYet = notValidYetOneCRLChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chainNotValidYet, ""),
|
||||
"A signature should not verify if the signing certificate is not valid yet");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chainNotValidYet,
|
||||
""
|
||||
)),
|
||||
"A signature should not verify if the signing certificate is not valid yet"
|
||||
);
|
||||
// Check for not yet valid cert.
|
||||
check_telemetry(5, 1, getCertHash("content_signing_onecrl_ee_not_valid_yet"));
|
||||
|
||||
let relatedName = "subdomain." + ONECRL_NAME;
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
|
||||
relatedName),
|
||||
"A signature should not verify if the SANs do not match a related name");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
relatedName
|
||||
)),
|
||||
"A signature should not verify if the SANs do not match a related name"
|
||||
);
|
||||
|
||||
let randomName = "\xb1\x9bU\x1c\xae\xaa3\x19H\xdb\xed\xa1\xa1\xe0\x81\xfb" +
|
||||
"\xb2\x8f\x1cP\xe5\x8b\x9c\xc2s\xd3\x1f\x8e\xbbN";
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, randomName),
|
||||
"A signature should not verify if the SANs do not match a random name");
|
||||
let randomName =
|
||||
"\xb1\x9bU\x1c\xae\xaa3\x19H\xdb\xed\xa1\xa1\xe0\x81\xfb" +
|
||||
"\xb2\x8f\x1cP\xe5\x8b\x9c\xc2s\xd3\x1f\x8e\xbbN";
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
randomName
|
||||
)),
|
||||
"A signature should not verify if the SANs do not match a random name"
|
||||
);
|
||||
|
||||
// check good signatures with chains that have strange or missing SANs
|
||||
chain1 = noSANChain.join("\n");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
|
||||
ONECRL_NAME),
|
||||
"A signature should not verify if the SANs do not match a supplied name");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A signature should not verify if the SANs do not match a supplied name"
|
||||
);
|
||||
|
||||
// Check malformed signature data
|
||||
chain1 = oneCRLChain.join("\n");
|
||||
let bad_signatures = [
|
||||
// wrong length
|
||||
"p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ecHiXoi-" +
|
||||
"7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L==",
|
||||
"7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L==",
|
||||
// incorrectly encoded
|
||||
"p384ecdsa='WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ecHiXoi" +
|
||||
"-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L=",
|
||||
"-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L=",
|
||||
// missing directive
|
||||
"other_directive=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ec" +
|
||||
"HiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L",
|
||||
"HiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L",
|
||||
// actually sha256 with RSA
|
||||
"p384ecdsa=XS_jiQsS5qlzQyUKaA1nAnQn_OvxhvDfKybflB8Xe5gNH1wNmPGK1qN-jpeTfK" +
|
||||
"6ob3l3gCTXrsMnOXMeht0kPP3wLfVgXbuuO135pQnsv0c-ltRMWLe56Cm4S4Z6E7WWKLPWaj" +
|
||||
"jhAcG5dZxjffP9g7tuPP4lTUJztyc4d1z_zQZakEG7R0vN7P5_CaX9MiMzP4R7nC3H4Ba6yi" +
|
||||
"yjlGvsZwJ_C5zDQzWWs95czUbMzbDScEZ_7AWnidw91jZn-fUK3xLb6m-Zb_b4GAqZ-vnXIf" +
|
||||
"LpLB1Nzal42BQZn7i4rhAldYdcVvy7rOMlsTUb5Zz6vpVW9LCT9lMJ7Sq1xbU-0g==",
|
||||
];
|
||||
"6ob3l3gCTXrsMnOXMeht0kPP3wLfVgXbuuO135pQnsv0c-ltRMWLe56Cm4S4Z6E7WWKLPWaj" +
|
||||
"jhAcG5dZxjffP9g7tuPP4lTUJztyc4d1z_zQZakEG7R0vN7P5_CaX9MiMzP4R7nC3H4Ba6yi" +
|
||||
"yjlGvsZwJ_C5zDQzWWs95czUbMzbDScEZ_7AWnidw91jZn-fUK3xLb6m-Zb_b4GAqZ-vnXIf" +
|
||||
"LpLB1Nzal42BQZn7i4rhAldYdcVvy7rOMlsTUb5Zz6vpVW9LCT9lMJ7Sq1xbU-0g==",
|
||||
];
|
||||
for (let badSig of bad_signatures) {
|
||||
await Assert.rejects(verifier.asyncVerifyContentSignature(DATA, badSig, chain1, ONECRL_NAME),
|
||||
/NS_ERROR/, `Bad or malformed signature "${badSig}" should be rejected`);
|
||||
await Assert.rejects(
|
||||
verifier.asyncVerifyContentSignature(DATA, badSig, chain1, ONECRL_NAME),
|
||||
/NS_ERROR/,
|
||||
`Bad or malformed signature "${badSig}" should be rejected`
|
||||
);
|
||||
}
|
||||
|
||||
// Check malformed and missing certificate chain data
|
||||
|
|
@ -237,7 +372,7 @@ add_task(async function run_test() {
|
|||
"",
|
||||
// completely wrong data
|
||||
"blah blah \n blah",
|
||||
];
|
||||
];
|
||||
|
||||
let badSections = [
|
||||
// data that looks like PEM but isn't
|
||||
|
|
@ -247,8 +382,8 @@ add_task(async function run_test() {
|
|||
"-----BEGIN CERTIFICATE-----\nnon-base64-stuff\n-----END CERTIFICATE-----",
|
||||
// data with garbage outside of PEM sections
|
||||
"this data is garbage\n-----BEGIN CERTIFICATE-----\nnon-base64-stuff\n" +
|
||||
"-----END CERTIFICATE-----",
|
||||
];
|
||||
"-----END CERTIFICATE-----",
|
||||
];
|
||||
|
||||
for (let badSection of badSections) {
|
||||
// ensure we test each bad section on its own...
|
||||
|
|
@ -258,20 +393,44 @@ add_task(async function run_test() {
|
|||
}
|
||||
|
||||
for (let badChain of badChains) {
|
||||
await Assert.rejects(verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, badChain,
|
||||
ONECRL_NAME),
|
||||
/NS_ERROR/,
|
||||
`Bad chain data starting "${badChain.substring(0, 80)}" ` +
|
||||
"should be rejected");
|
||||
await Assert.rejects(
|
||||
verifier.asyncVerifyContentSignature(
|
||||
DATA,
|
||||
GOOD_SIGNATURE,
|
||||
badChain,
|
||||
ONECRL_NAME
|
||||
),
|
||||
/NS_ERROR/,
|
||||
`Bad chain data starting "${badChain.substring(0, 80)}" ` +
|
||||
"should be rejected"
|
||||
);
|
||||
}
|
||||
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA + "appended data", GOOD_SIGNATURE, chain1,
|
||||
ONECRL_NAME),
|
||||
"A good signature should not verify if the data is tampered with (append)");
|
||||
ok(!await verifier.asyncVerifyContentSignature("prefixed data" + DATA, GOOD_SIGNATURE, chain1,
|
||||
ONECRL_NAME),
|
||||
"A good signature should not verify if the data is tampered with (prefix)");
|
||||
ok(!await verifier.asyncVerifyContentSignature(DATA.replace(/e/g, "i"), GOOD_SIGNATURE, chain1,
|
||||
ONECRL_NAME),
|
||||
"A good signature should not verify if the data is tampered with (modify)");
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA + "appended data",
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A good signature should not verify if the data is tampered with (append)"
|
||||
);
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
"prefixed data" + DATA,
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A good signature should not verify if the data is tampered with (prefix)"
|
||||
);
|
||||
ok(
|
||||
!(await verifier.asyncVerifyContentSignature(
|
||||
DATA.replace(/e/g, "i"),
|
||||
GOOD_SIGNATURE,
|
||||
chain1,
|
||||
ONECRL_NAME
|
||||
)),
|
||||
"A good signature should not verify if the data is tampered with (modify)"
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,13 +6,17 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function expectCT(value) {
|
||||
return (securityInfo) => {
|
||||
Assert.equal(securityInfo.certificateTransparencyStatus, value,
|
||||
"actual and expected CT status should match");
|
||||
return securityInfo => {
|
||||
Assert.equal(
|
||||
securityInfo.certificateTransparencyStatus,
|
||||
value,
|
||||
"actual and expected CT status should match"
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -30,12 +34,24 @@ function run_test() {
|
|||
// less than 2 years and 3 months). Our policy requires N + 1 embedded SCTs,
|
||||
// where N is 2 in this case. So, a policy-compliant certificate would have at
|
||||
// least 3 SCTs.
|
||||
add_connection_test("ct-valid.example.com", PRErrorCodeSuccess, null,
|
||||
expectCT(Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT));
|
||||
// This certificate has only 2 embedded SCTs, and so is not policy-compliant.
|
||||
add_connection_test("ct-insufficient-scts.example.com", PRErrorCodeSuccess,
|
||||
add_connection_test(
|
||||
"ct-valid.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
expectCT(Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_NOT_ENOUGH_SCTS));
|
||||
expectCT(
|
||||
Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT
|
||||
)
|
||||
);
|
||||
// This certificate has only 2 embedded SCTs, and so is not policy-compliant.
|
||||
add_connection_test(
|
||||
"ct-insufficient-scts.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
expectCT(
|
||||
Ci.nsITransportSecurityInfo
|
||||
.CERTIFICATE_TRANSPARENCY_POLICY_NOT_ENOUGH_SCTS
|
||||
)
|
||||
);
|
||||
|
||||
// Test that if an end-entity is marked as a trust anchor, CT verification
|
||||
// returns a "not enough SCTs" result.
|
||||
|
|
@ -45,8 +61,15 @@ function run_test() {
|
|||
clearSessionCache();
|
||||
run_next_test();
|
||||
});
|
||||
add_connection_test("ct-valid.example.com", PRErrorCodeSuccess, null,
|
||||
expectCT(Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_NOT_ENOUGH_SCTS));
|
||||
add_connection_test(
|
||||
"ct-valid.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
expectCT(
|
||||
Ci.nsITransportSecurityInfo
|
||||
.CERTIFICATE_TRANSPARENCY_POLICY_NOT_ENOUGH_SCTS
|
||||
)
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,40 +10,73 @@
|
|||
var { DER } = ChromeUtils.import("resource://gre/modules/psm/DER.jsm", null);
|
||||
|
||||
function run_simple_tests() {
|
||||
throws(() => new DER.DER("this is not an array"), /invalid input/,
|
||||
"should throw given non-array input");
|
||||
throws(() => new DER.DER([0, "invalid input", 1]), /invalid input/,
|
||||
"should throw given non-byte data (string case)");
|
||||
throws(() => new DER.DER([31, 1, {}]), /invalid input/,
|
||||
"should throw given non-byte data (object case)");
|
||||
throws(() => new DER.DER([0.1, 3, 1]), /invalid input/,
|
||||
"should throw given non-byte data (non-integer case)");
|
||||
throws(() => new DER.DER([1, 3, -1]), /invalid input/,
|
||||
"should throw given non-byte data (negative integer case)");
|
||||
throws(() => new DER.DER([1, 300, 79]), /invalid input/,
|
||||
"should throw given non-byte data (large integer case)");
|
||||
throws(
|
||||
() => new DER.DER("this is not an array"),
|
||||
/invalid input/,
|
||||
"should throw given non-array input"
|
||||
);
|
||||
throws(
|
||||
() => new DER.DER([0, "invalid input", 1]),
|
||||
/invalid input/,
|
||||
"should throw given non-byte data (string case)"
|
||||
);
|
||||
throws(
|
||||
() => new DER.DER([31, 1, {}]),
|
||||
/invalid input/,
|
||||
"should throw given non-byte data (object case)"
|
||||
);
|
||||
throws(
|
||||
() => new DER.DER([0.1, 3, 1]),
|
||||
/invalid input/,
|
||||
"should throw given non-byte data (non-integer case)"
|
||||
);
|
||||
throws(
|
||||
() => new DER.DER([1, 3, -1]),
|
||||
/invalid input/,
|
||||
"should throw given non-byte data (negative integer case)"
|
||||
);
|
||||
throws(
|
||||
() => new DER.DER([1, 300, 79]),
|
||||
/invalid input/,
|
||||
"should throw given non-byte data (large integer case)"
|
||||
);
|
||||
|
||||
let testReadByte = new DER.DER([0x0a, 0x0b]);
|
||||
equal(testReadByte.readByte(), 0x0a, "should read 0x0a");
|
||||
equal(testReadByte.readByte(), 0x0b, "should read 0x0b");
|
||||
throws(() => testReadByte.readByte(), /data truncated/,
|
||||
"reading more data than is available should fail");
|
||||
throws(
|
||||
() => testReadByte.readByte(),
|
||||
/data truncated/,
|
||||
"reading more data than is available should fail"
|
||||
);
|
||||
|
||||
let testReadBytes = new DER.DER([0x0c, 0x0d, 0x0e]);
|
||||
deepEqual(testReadBytes.readBytes(3), [0x0c, 0x0d, 0x0e],
|
||||
"should read correct sequence of bytes");
|
||||
deepEqual(
|
||||
testReadBytes.readBytes(3),
|
||||
[0x0c, 0x0d, 0x0e],
|
||||
"should read correct sequence of bytes"
|
||||
);
|
||||
|
||||
let testReadNegativeBytes = new DER.DER([0xff, 0xaf]);
|
||||
throws(() => testReadNegativeBytes.readBytes(-4), /invalid length/,
|
||||
"reading a negative number of bytes should fail");
|
||||
throws(
|
||||
() => testReadNegativeBytes.readBytes(-4),
|
||||
/invalid length/,
|
||||
"reading a negative number of bytes should fail"
|
||||
);
|
||||
|
||||
let testReadZeroBytes = new DER.DER([]);
|
||||
equal(testReadZeroBytes.readBytes(0).length, 0,
|
||||
"reading zero bytes should result in a zero-length array");
|
||||
equal(
|
||||
testReadZeroBytes.readBytes(0).length,
|
||||
0,
|
||||
"reading zero bytes should result in a zero-length array"
|
||||
);
|
||||
|
||||
let testReadTooManyBytes = new DER.DER([0xab, 0xcd, 0xef]);
|
||||
throws(() => testReadTooManyBytes.readBytes(4), /data truncated/,
|
||||
"reading too many bytes should fail");
|
||||
throws(
|
||||
() => testReadTooManyBytes.readBytes(4),
|
||||
/data truncated/,
|
||||
"reading too many bytes should fail"
|
||||
);
|
||||
|
||||
let testSEQUENCE = new DER.DER([0x30, 0x01, 0x01]);
|
||||
let content = testSEQUENCE.readTagAndGetContents(DER.SEQUENCE);
|
||||
|
|
@ -54,164 +87,268 @@ function run_simple_tests() {
|
|||
|
||||
// The length purports to be 4 bytes, but there are only 2 available.
|
||||
let truncatedSEQUENCE = new DER.DER([0x30, 0x04, 0x00, 0x00]);
|
||||
throws(() => truncatedSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
|
||||
/data truncated/, "should get 'data truncated' error");
|
||||
throws(
|
||||
() => truncatedSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
|
||||
/data truncated/,
|
||||
"should get 'data truncated' error"
|
||||
);
|
||||
|
||||
// With 2 bytes of content, there is 1 remaining after reading the content.
|
||||
let extraDataSEQUENCE = new DER.DER([0x30, 0x02, 0xab, 0xcd, 0xef]);
|
||||
content = extraDataSEQUENCE.readTagAndGetContents(DER.SEQUENCE);
|
||||
equal(content.length, 2, "content should have length 2");
|
||||
deepEqual(content, [0xab, 0xcd], "value of content should be [0xab, 0xcd]");
|
||||
ok(!extraDataSEQUENCE.atEnd(),
|
||||
"extraDataSEQUENCE should not be at the end of its input");
|
||||
throws(() => extraDataSEQUENCE.assertAtEnd(), /extra data/,
|
||||
"should get 'extra data' error");
|
||||
ok(
|
||||
!extraDataSEQUENCE.atEnd(),
|
||||
"extraDataSEQUENCE should not be at the end of its input"
|
||||
);
|
||||
throws(
|
||||
() => extraDataSEQUENCE.assertAtEnd(),
|
||||
/extra data/,
|
||||
"should get 'extra data' error"
|
||||
);
|
||||
|
||||
// The length of 0x81 0x01 is invalid because it could be encoded as just
|
||||
// 0x01, which is shorter.
|
||||
let invalidLengthSEQUENCE1 = new DER.DER([0x30, 0x81, 0x01, 0x00]);
|
||||
throws(() => invalidLengthSEQUENCE1.readTagAndGetContents(DER.SEQUENCE),
|
||||
/invalid length/, "should get 'invalid length' error");
|
||||
throws(
|
||||
() => invalidLengthSEQUENCE1.readTagAndGetContents(DER.SEQUENCE),
|
||||
/invalid length/,
|
||||
"should get 'invalid length' error"
|
||||
);
|
||||
|
||||
// Similarly, 0x82 0x00 0x01 could be encoded as just 0x01, which is shorter.
|
||||
let invalidLengthSEQUENCE2 = new DER.DER([0x30, 0x82, 0x00, 0x01, 0x00]);
|
||||
throws(() => invalidLengthSEQUENCE2.readTagAndGetContents(DER.SEQUENCE),
|
||||
/invalid length/, "should get 'invalid length' error");
|
||||
throws(
|
||||
() => invalidLengthSEQUENCE2.readTagAndGetContents(DER.SEQUENCE),
|
||||
/invalid length/,
|
||||
"should get 'invalid length' error"
|
||||
);
|
||||
|
||||
// Lengths requiring 4 bytes to encode are not supported.
|
||||
let unsupportedLengthSEQUENCE = new DER.DER([0x30, 0x83, 0x01, 0x01, 0x01]);
|
||||
throws(() => unsupportedLengthSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
|
||||
/unsupported length/, "should get 'unsupported length' error");
|
||||
throws(
|
||||
() => unsupportedLengthSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
|
||||
/unsupported length/,
|
||||
"should get 'unsupported length' error"
|
||||
);
|
||||
|
||||
// Indefinite lengths are not supported (and aren't DER anyway).
|
||||
let unsupportedASN1SEQUENCE = new DER.DER([0x30, 0x80, 0x01, 0x00, 0x00]);
|
||||
throws(() => unsupportedASN1SEQUENCE.readTagAndGetContents(DER.SEQUENCE),
|
||||
/unsupported asn.1/, "should get 'unsupported asn.1' error");
|
||||
throws(
|
||||
() => unsupportedASN1SEQUENCE.readTagAndGetContents(DER.SEQUENCE),
|
||||
/unsupported asn.1/,
|
||||
"should get 'unsupported asn.1' error"
|
||||
);
|
||||
|
||||
let unexpectedTag = new DER.DER([0x31, 0x01, 0x00]);
|
||||
throws(() => unexpectedTag.readTagAndGetContents(DER.SEQUENCE),
|
||||
/unexpected tag/, "should get 'unexpected tag' error");
|
||||
throws(
|
||||
() => unexpectedTag.readTagAndGetContents(DER.SEQUENCE),
|
||||
/unexpected tag/,
|
||||
"should get 'unexpected tag' error"
|
||||
);
|
||||
|
||||
let readTLVTestcase = new DER.DER([0x02, 0x03, 0x45, 0x67, 0x89]);
|
||||
let bytes = readTLVTestcase.readTLV();
|
||||
deepEqual(bytes, [0x02, 0x03, 0x45, 0x67, 0x89],
|
||||
"bytes read with readTLV should be equal to expected value");
|
||||
deepEqual(
|
||||
bytes,
|
||||
[0x02, 0x03, 0x45, 0x67, 0x89],
|
||||
"bytes read with readTLV should be equal to expected value"
|
||||
);
|
||||
|
||||
let peekTagTestcase = new DER.DER([0x30, 0x01, 0x00]);
|
||||
ok(peekTagTestcase.peekTag(DER.SEQUENCE),
|
||||
"peekTag should return true for peeking with a SEQUENCE at a SEQUENCE");
|
||||
ok(!peekTagTestcase.peekTag(DER.SET),
|
||||
"peekTag should return false for peeking with a SET at a SEQUENCE");
|
||||
ok(
|
||||
peekTagTestcase.peekTag(DER.SEQUENCE),
|
||||
"peekTag should return true for peeking with a SEQUENCE at a SEQUENCE"
|
||||
);
|
||||
ok(
|
||||
!peekTagTestcase.peekTag(DER.SET),
|
||||
"peekTag should return false for peeking with a SET at a SEQUENCE"
|
||||
);
|
||||
peekTagTestcase.readTLV();
|
||||
ok(!peekTagTestcase.peekTag(DER.SEQUENCE),
|
||||
"peekTag should return false for peeking at a DER with no more data");
|
||||
ok(
|
||||
!peekTagTestcase.peekTag(DER.SEQUENCE),
|
||||
"peekTag should return false for peeking at a DER with no more data"
|
||||
);
|
||||
|
||||
let tlvChoiceTestcase = new DER.DER([0x31, 0x02, 0xaa, 0xbb]);
|
||||
let tlvChoiceContents = tlvChoiceTestcase.readTLVChoice([DER.NULL, DER.SET]);
|
||||
deepEqual(tlvChoiceContents, [0x31, 0x02, 0xaa, 0xbb],
|
||||
"readTLVChoice should return expected bytes");
|
||||
deepEqual(
|
||||
tlvChoiceContents,
|
||||
[0x31, 0x02, 0xaa, 0xbb],
|
||||
"readTLVChoice should return expected bytes"
|
||||
);
|
||||
|
||||
let tlvChoiceNoMatchTestcase = new DER.DER([0x30, 0x01, 0xff]);
|
||||
throws(() => tlvChoiceNoMatchTestcase.readTLVChoice([DER.NULL, DER.SET]),
|
||||
/unexpected tag/,
|
||||
"readTLVChoice should throw if no matching tag is found");
|
||||
throws(
|
||||
() => tlvChoiceNoMatchTestcase.readTLVChoice([DER.NULL, DER.SET]),
|
||||
/unexpected tag/,
|
||||
"readTLVChoice should throw if no matching tag is found"
|
||||
);
|
||||
}
|
||||
|
||||
function run_bit_string_tests() {
|
||||
let bitstringDER = new DER.DER([0x03, 0x04, 0x03, 0x01, 0x02, 0xf8]);
|
||||
let bitstring = bitstringDER.readBIT_STRING();
|
||||
equal(bitstring.unusedBits, 3, "BIT STRING should have 3 unused bits");
|
||||
deepEqual(bitstring.contents, [0x01, 0x02, 0xf8],
|
||||
"BIT STRING should have expected contents");
|
||||
deepEqual(
|
||||
bitstring.contents,
|
||||
[0x01, 0x02, 0xf8],
|
||||
"BIT STRING should have expected contents"
|
||||
);
|
||||
|
||||
let bitstringTooManyUnusedBits = new DER.DER([0x03, 0x02, 0x08, 0x00]);
|
||||
throws(() => bitstringTooManyUnusedBits.readBIT_STRING(),
|
||||
/invalid BIT STRING encoding/,
|
||||
"BIT STRING with too many unused bits should throw");
|
||||
throws(
|
||||
() => bitstringTooManyUnusedBits.readBIT_STRING(),
|
||||
/invalid BIT STRING encoding/,
|
||||
"BIT STRING with too many unused bits should throw"
|
||||
);
|
||||
|
||||
// A BIT STRING must have the unused bits byte, and so its length must be at
|
||||
// least one.
|
||||
let bitstringMissingUnusedBits = new DER.DER([0x03, 0x00]);
|
||||
throws(() => bitstringMissingUnusedBits.readBIT_STRING(),
|
||||
/invalid BIT STRING encoding/,
|
||||
"BIT STRING with missing unused bits (and no contents) should throw");
|
||||
throws(
|
||||
() => bitstringMissingUnusedBits.readBIT_STRING(),
|
||||
/invalid BIT STRING encoding/,
|
||||
"BIT STRING with missing unused bits (and no contents) should throw"
|
||||
);
|
||||
|
||||
// The minimal BIT STRING is 03 01 00 (zero bits of padding and zero bytes of
|
||||
// content).
|
||||
let minimalBitstringDER = new DER.DER([0x03, 0x01, 0x00]);
|
||||
let minimalBitstring = minimalBitstringDER.readBIT_STRING();
|
||||
equal(minimalBitstring.unusedBits, 0,
|
||||
"minimal BIT STRING should have 0 unused bits");
|
||||
equal(minimalBitstring.contents.length, 0,
|
||||
"minimal BIT STRING should have empty contents");
|
||||
equal(
|
||||
minimalBitstring.unusedBits,
|
||||
0,
|
||||
"minimal BIT STRING should have 0 unused bits"
|
||||
);
|
||||
equal(
|
||||
minimalBitstring.contents.length,
|
||||
0,
|
||||
"minimal BIT STRING should have empty contents"
|
||||
);
|
||||
|
||||
// However, a BIT STRING with zero bytes of content can't have any padding,
|
||||
// because that makes no sense.
|
||||
let noContentsPaddedBitstringDER = new DER.DER([0x03, 0x01, 0x03]);
|
||||
throws(() => noContentsPaddedBitstringDER.readBIT_STRING(),
|
||||
/invalid BIT STRING encoding/,
|
||||
"BIT STRING with no contents with non-zero padding should throw");
|
||||
throws(
|
||||
() => noContentsPaddedBitstringDER.readBIT_STRING(),
|
||||
/invalid BIT STRING encoding/,
|
||||
"BIT STRING with no contents with non-zero padding should throw"
|
||||
);
|
||||
}
|
||||
|
||||
function run_compound_tests() {
|
||||
let derBytes =
|
||||
[ 0x30, 0x1a, // SEQUENCE
|
||||
0x02, 0x02, 0x77, 0xff, // INTEGER
|
||||
0x06, 0x03, 0x2b, 0x01, 0x01, // OBJECT IDENTIFIER
|
||||
0x30, 0x07, // SEQUENCE
|
||||
0x05, 0x00, // NULL
|
||||
0x02, 0x03, 0x45, 0x46, 0x47, // INTEGER
|
||||
0x30, 0x06, // SEQUENCE
|
||||
0x02, 0x02, 0x00, 0xff, // INTEGER
|
||||
0x05, 0x00 ]; // NULL
|
||||
let derBytes = [
|
||||
0x30,
|
||||
0x1a, // SEQUENCE
|
||||
0x02,
|
||||
0x02,
|
||||
0x77,
|
||||
0xff, // INTEGER
|
||||
0x06,
|
||||
0x03,
|
||||
0x2b,
|
||||
0x01,
|
||||
0x01, // OBJECT IDENTIFIER
|
||||
0x30,
|
||||
0x07, // SEQUENCE
|
||||
0x05,
|
||||
0x00, // NULL
|
||||
0x02,
|
||||
0x03,
|
||||
0x45,
|
||||
0x46,
|
||||
0x47, // INTEGER
|
||||
0x30,
|
||||
0x06, // SEQUENCE
|
||||
0x02,
|
||||
0x02,
|
||||
0x00,
|
||||
0xff, // INTEGER
|
||||
0x05,
|
||||
0x00,
|
||||
]; // NULL
|
||||
let der = new DER.DER(derBytes);
|
||||
let contents = new DER.DER(der.readTagAndGetContents(DER.SEQUENCE));
|
||||
let firstINTEGER = contents.readTagAndGetContents(DER.INTEGER);
|
||||
deepEqual(firstINTEGER, [0x77, 0xff],
|
||||
"first INTEGER should have expected value");
|
||||
deepEqual(
|
||||
firstINTEGER,
|
||||
[0x77, 0xff],
|
||||
"first INTEGER should have expected value"
|
||||
);
|
||||
let oid = contents.readTagAndGetContents(DER.OBJECT_IDENTIFIER);
|
||||
deepEqual(oid, [0x2b, 0x01, 0x01],
|
||||
"OBJECT IDENTIFIER should have expected value");
|
||||
deepEqual(
|
||||
oid,
|
||||
[0x2b, 0x01, 0x01],
|
||||
"OBJECT IDENTIFIER should have expected value"
|
||||
);
|
||||
|
||||
let firstNested = new DER.DER(contents.readTagAndGetContents(DER.SEQUENCE));
|
||||
let firstNestedNULL = firstNested.readTagAndGetContents(DER.NULL);
|
||||
equal(firstNestedNULL.length, 0,
|
||||
"first nested NULL should have expected value (empty array)");
|
||||
equal(
|
||||
firstNestedNULL.length,
|
||||
0,
|
||||
"first nested NULL should have expected value (empty array)"
|
||||
);
|
||||
let firstNestedINTEGER = firstNested.readTagAndGetContents(DER.INTEGER);
|
||||
deepEqual(firstNestedINTEGER, [0x45, 0x46, 0x47],
|
||||
"first nested INTEGER should have expected value");
|
||||
deepEqual(
|
||||
firstNestedINTEGER,
|
||||
[0x45, 0x46, 0x47],
|
||||
"first nested INTEGER should have expected value"
|
||||
);
|
||||
firstNested.assertAtEnd();
|
||||
|
||||
let secondNested = new DER.DER(contents.readTagAndGetContents(DER.SEQUENCE));
|
||||
let secondNestedINTEGER = secondNested.readTagAndGetContents(DER.INTEGER);
|
||||
deepEqual(secondNestedINTEGER, [0x00, 0xff],
|
||||
"second nested INTEGER should have expected value");
|
||||
deepEqual(
|
||||
secondNestedINTEGER,
|
||||
[0x00, 0xff],
|
||||
"second nested INTEGER should have expected value"
|
||||
);
|
||||
let secondNestedNULL = secondNested.readTagAndGetContents(DER.NULL);
|
||||
equal(secondNestedNULL.length, 0,
|
||||
"second nested NULL should have expected value (empty array)");
|
||||
equal(
|
||||
secondNestedNULL.length,
|
||||
0,
|
||||
"second nested NULL should have expected value (empty array)"
|
||||
);
|
||||
secondNested.assertAtEnd();
|
||||
|
||||
contents.assertAtEnd();
|
||||
der.assertAtEnd();
|
||||
|
||||
let invalidDERBytes =
|
||||
[ 0x30, 0x06, // SEQUENCE
|
||||
0x30, 0x02, // SEQUENCE
|
||||
0x02, 0x01, // INTEGER (missing data)
|
||||
0x05, 0x00, // NULL
|
||||
0x00, 0x00 ]; // (extra data)
|
||||
let invalidDERBytes = [
|
||||
0x30,
|
||||
0x06, // SEQUENCE
|
||||
0x30,
|
||||
0x02, // SEQUENCE
|
||||
0x02,
|
||||
0x01, // INTEGER (missing data)
|
||||
0x05,
|
||||
0x00, // NULL
|
||||
0x00,
|
||||
0x00,
|
||||
]; // (extra data)
|
||||
let invalidDER = new DER.DER(invalidDERBytes);
|
||||
let invalidContents = new DER.DER(
|
||||
invalidDER.readTagAndGetContents(DER.SEQUENCE));
|
||||
invalidDER.readTagAndGetContents(DER.SEQUENCE)
|
||||
);
|
||||
let invalidContentsContents = new DER.DER(
|
||||
invalidContents.readTagAndGetContents(DER.SEQUENCE));
|
||||
throws(() => invalidContentsContents.readTagAndGetContents(DER.INTEGER),
|
||||
/data truncated/, "should throw due to missing data");
|
||||
invalidContents.readTagAndGetContents(DER.SEQUENCE)
|
||||
);
|
||||
throws(
|
||||
() => invalidContentsContents.readTagAndGetContents(DER.INTEGER),
|
||||
/data truncated/,
|
||||
"should throw due to missing data"
|
||||
);
|
||||
let nestedNULL = invalidContents.readTagAndGetContents(DER.NULL);
|
||||
equal(nestedNULL.length, 0, "nested NULL should have expected value");
|
||||
invalidContents.assertAtEnd();
|
||||
throws(() => invalidDER.assertAtEnd(), /extra data/,
|
||||
"should throw due to extra data");
|
||||
throws(
|
||||
() => invalidDER.assertAtEnd(),
|
||||
/extra data/,
|
||||
"should throw due to extra data"
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
|
|||
|
|
@ -11,12 +11,22 @@
|
|||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
|
||||
const {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
const { TestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
async function check_no_enterprise_roots_imported(nssComponent, certDB, dbKey = undefined) {
|
||||
async function check_no_enterprise_roots_imported(
|
||||
nssComponent,
|
||||
certDB,
|
||||
dbKey = undefined
|
||||
) {
|
||||
let enterpriseRoots = nssComponent.getEnterpriseRoots();
|
||||
notEqual(enterpriseRoots, null, "enterprise roots list should not be null");
|
||||
equal(enterpriseRoots.length, 0, "should not have imported any enterprise roots");
|
||||
equal(
|
||||
enterpriseRoots.length,
|
||||
0,
|
||||
"should not have imported any enterprise roots"
|
||||
);
|
||||
if (dbKey) {
|
||||
let cert = certDB.findCertByDBKey(dbKey);
|
||||
// If the garbage-collector hasn't run, there may be reachable copies of
|
||||
|
|
@ -39,7 +49,11 @@ function der_array_to_string(derArray) {
|
|||
async function check_some_enterprise_roots_imported(nssComponent, certDB) {
|
||||
let enterpriseRoots = nssComponent.getEnterpriseRoots();
|
||||
notEqual(enterpriseRoots, null, "enterprise roots list should not be null");
|
||||
notEqual(enterpriseRoots.length, 0, "should have imported some enterprise roots");
|
||||
notEqual(
|
||||
enterpriseRoots.length,
|
||||
0,
|
||||
"should have imported some enterprise roots"
|
||||
);
|
||||
let foundNonBuiltIn = false;
|
||||
let savedDBKey = null;
|
||||
for (let certDer of enterpriseRoots) {
|
||||
|
|
@ -59,13 +73,18 @@ async function check_some_enterprise_roots_imported(nssComponent, certDB) {
|
|||
|
||||
add_task(async function run_test() {
|
||||
let nssComponent = Cc["@mozilla.org/psm;1"].getService(Ci.nsINSSComponent);
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
nssComponent.getEnterpriseRoots(); // blocks until roots are loaded
|
||||
Services.prefs.setBoolPref("security.enterprise_roots.enabled", false);
|
||||
await check_no_enterprise_roots_imported(nssComponent, certDB);
|
||||
Services.prefs.setBoolPref("security.enterprise_roots.enabled", true);
|
||||
await TestUtils.topicObserved("psm:enterprise-certs-imported");
|
||||
let savedDBKey = await check_some_enterprise_roots_imported(nssComponent, certDB);
|
||||
let savedDBKey = await check_some_enterprise_roots_imported(
|
||||
nssComponent,
|
||||
certDB
|
||||
);
|
||||
Services.prefs.setBoolPref("security.enterprise_roots.enabled", false);
|
||||
await check_no_enterprise_roots_imported(nssComponent, certDB, savedDBKey);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@
|
|||
// the end-entity and the intermediate have the test OID.
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("network.dns.localDomains");
|
||||
|
|
@ -46,8 +47,13 @@ function failingOCSPResponder() {
|
|||
}
|
||||
|
||||
class EVCertVerificationResult {
|
||||
constructor(testcase, expectedPRErrorCode, expectedEV, resolve,
|
||||
ocspResponder) {
|
||||
constructor(
|
||||
testcase,
|
||||
expectedPRErrorCode,
|
||||
expectedEV,
|
||||
resolve,
|
||||
ocspResponder
|
||||
) {
|
||||
this.testcase = testcase;
|
||||
this.expectedPRErrorCode = expectedPRErrorCode;
|
||||
this.expectedEV = expectedEV;
|
||||
|
|
@ -56,30 +62,56 @@ class EVCertVerificationResult {
|
|||
}
|
||||
|
||||
verifyCertFinished(prErrorCode, verifiedChain, hasEVPolicy) {
|
||||
equal(prErrorCode, this.expectedPRErrorCode,
|
||||
`${this.testcase} should have expected error code`);
|
||||
equal(hasEVPolicy, this.expectedEV,
|
||||
`${this.testcase} should result in expected EV status`);
|
||||
equal(
|
||||
prErrorCode,
|
||||
this.expectedPRErrorCode,
|
||||
`${this.testcase} should have expected error code`
|
||||
);
|
||||
equal(
|
||||
hasEVPolicy,
|
||||
this.expectedEV,
|
||||
`${this.testcase} should result in expected EV status`
|
||||
);
|
||||
this.ocspResponder.stop(this.resolve);
|
||||
}
|
||||
}
|
||||
|
||||
function asyncTestEV(cert, expectedPRErrorCode, expectedEV,
|
||||
expectedOCSPRequestPaths, ocspResponseTypes = undefined) {
|
||||
function asyncTestEV(
|
||||
cert,
|
||||
expectedPRErrorCode,
|
||||
expectedEV,
|
||||
expectedOCSPRequestPaths,
|
||||
ocspResponseTypes = undefined
|
||||
) {
|
||||
let now = Date.now() / 1000;
|
||||
return new Promise((resolve, reject) => {
|
||||
let ocspResponder = expectedOCSPRequestPaths.length > 0
|
||||
? startOCSPResponder(SERVER_PORT, "www.example.com",
|
||||
"test_ev_certs",
|
||||
expectedOCSPRequestPaths,
|
||||
expectedOCSPRequestPaths.slice(),
|
||||
null, ocspResponseTypes)
|
||||
: failingOCSPResponder();
|
||||
let result = new EVCertVerificationResult(cert.subjectName,
|
||||
expectedPRErrorCode, expectedEV,
|
||||
resolve, ocspResponder);
|
||||
certdb.asyncVerifyCertAtTime(cert, certificateUsageSSLServer, 0,
|
||||
"ev-test.example.com", now, result);
|
||||
let ocspResponder =
|
||||
expectedOCSPRequestPaths.length > 0
|
||||
? startOCSPResponder(
|
||||
SERVER_PORT,
|
||||
"www.example.com",
|
||||
"test_ev_certs",
|
||||
expectedOCSPRequestPaths,
|
||||
expectedOCSPRequestPaths.slice(),
|
||||
null,
|
||||
ocspResponseTypes
|
||||
)
|
||||
: failingOCSPResponder();
|
||||
let result = new EVCertVerificationResult(
|
||||
cert.subjectName,
|
||||
expectedPRErrorCode,
|
||||
expectedEV,
|
||||
resolve,
|
||||
ocspResponder
|
||||
);
|
||||
certdb.asyncVerifyCertAtTime(
|
||||
cert,
|
||||
certificateUsageSSLServer,
|
||||
0,
|
||||
"ev-test.example.com",
|
||||
now,
|
||||
result
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -87,10 +119,14 @@ function ensureVerifiesAsEV(testcase) {
|
|||
let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
|
||||
addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
|
||||
let expectedOCSPRequestPaths = gEVExpected
|
||||
? [ `${testcase}-int`, `${testcase}-ee` ]
|
||||
: [ `${testcase}-ee` ];
|
||||
return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected,
|
||||
expectedOCSPRequestPaths);
|
||||
? [`${testcase}-int`, `${testcase}-ee`]
|
||||
: [`${testcase}-ee`];
|
||||
return asyncTestEV(
|
||||
cert,
|
||||
PRErrorCodeSuccess,
|
||||
gEVExpected,
|
||||
expectedOCSPRequestPaths
|
||||
);
|
||||
}
|
||||
|
||||
function ensureVerifiesAsEVWithNoOCSPRequests(testcase) {
|
||||
|
|
@ -102,9 +138,12 @@ function ensureVerifiesAsEVWithNoOCSPRequests(testcase) {
|
|||
function ensureVerifiesAsDV(testcase, expectedOCSPRequestPaths = undefined) {
|
||||
let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
|
||||
addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
|
||||
return asyncTestEV(cert, PRErrorCodeSuccess, false,
|
||||
expectedOCSPRequestPaths ? expectedOCSPRequestPaths
|
||||
: [ `${testcase}-ee` ]);
|
||||
return asyncTestEV(
|
||||
cert,
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
expectedOCSPRequestPaths ? expectedOCSPRequestPaths : [`${testcase}-ee`]
|
||||
);
|
||||
}
|
||||
|
||||
function ensureVerificationFails(testcase, expectedPRErrorCode) {
|
||||
|
|
@ -124,12 +163,22 @@ function verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, expectSuccess) {
|
|||
return new Promise((resolve, reject) => {
|
||||
let ocspResponder = failingOCSPResponder();
|
||||
let result = new EVCertVerificationResult(
|
||||
cert.subjectName, expectedErrorCode, expectSuccess && gEVExpected,
|
||||
resolve, ocspResponder);
|
||||
let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY |
|
||||
Ci.nsIX509CertDB.FLAG_MUST_BE_EV;
|
||||
certdb.asyncVerifyCertAtTime(cert, certificateUsageSSLServer, flags,
|
||||
"ev-test.example.com", now, result);
|
||||
cert.subjectName,
|
||||
expectedErrorCode,
|
||||
expectSuccess && gEVExpected,
|
||||
resolve,
|
||||
ocspResponder
|
||||
);
|
||||
let flags =
|
||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | Ci.nsIX509CertDB.FLAG_MUST_BE_EV;
|
||||
certdb.asyncVerifyCertAtTime(
|
||||
cert,
|
||||
certificateUsageSSLServer,
|
||||
flags,
|
||||
"ev-test.example.com",
|
||||
now,
|
||||
result
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -144,34 +193,47 @@ function ensureVerifiesAsEVWithFLAG_LOCAL_ONLY(testcase) {
|
|||
function ensureOneCRLSkipsOCSPForIntermediates(testcase) {
|
||||
let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
|
||||
addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
|
||||
return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected,
|
||||
[ `${testcase}-ee` ]);
|
||||
return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected, [`${testcase}-ee`]);
|
||||
}
|
||||
|
||||
function verifyWithDifferentOCSPResponseTypes(testcase, responses, expectEV) {
|
||||
let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
|
||||
addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
|
||||
let expectedOCSPRequestPaths = gEVExpected
|
||||
? [ `${testcase}-int`, `${testcase}-ee` ]
|
||||
: [ `${testcase}-ee` ];
|
||||
? [`${testcase}-int`, `${testcase}-ee`]
|
||||
: [`${testcase}-ee`];
|
||||
let ocspResponseTypes = gEVExpected ? responses : responses.slice(1);
|
||||
return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected && expectEV,
|
||||
expectedOCSPRequestPaths, ocspResponseTypes);
|
||||
return asyncTestEV(
|
||||
cert,
|
||||
PRErrorCodeSuccess,
|
||||
gEVExpected && expectEV,
|
||||
expectedOCSPRequestPaths,
|
||||
ocspResponseTypes
|
||||
);
|
||||
}
|
||||
|
||||
function ensureVerifiesAsEVWithOldIntermediateOCSPResponse(testcase) {
|
||||
return verifyWithDifferentOCSPResponseTypes(
|
||||
testcase, [ "longvalidityalmostold", "good" ], true);
|
||||
testcase,
|
||||
["longvalidityalmostold", "good"],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function ensureVerifiesAsDVWithOldEndEntityOCSPResponse(testcase) {
|
||||
return verifyWithDifferentOCSPResponseTypes(
|
||||
testcase, [ "good", "longvalidityalmostold" ], false);
|
||||
testcase,
|
||||
["good", "longvalidityalmostold"],
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
function ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse(testcase) {
|
||||
return verifyWithDifferentOCSPResponseTypes(
|
||||
testcase, [ "good", "ancientstillvalid" ], false);
|
||||
testcase,
|
||||
["good", "ancientstillvalid"],
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// These should all verify as EV.
|
||||
|
|
@ -194,8 +256,10 @@ add_task(async function plainExpectSuccessEVTests() {
|
|||
add_task(async function expectDVFallbackTests() {
|
||||
await ensureVerifiesAsDV("anyPolicy-ee-path");
|
||||
await ensureVerifiesAsDV("non-ev-root-path");
|
||||
await ensureVerifiesAsDV("no-ocsp-ee-path",
|
||||
gEVExpected ? [ "no-ocsp-ee-path-int" ] : []);
|
||||
await ensureVerifiesAsDV(
|
||||
"no-ocsp-ee-path",
|
||||
gEVExpected ? ["no-ocsp-ee-path-int"] : []
|
||||
);
|
||||
await ensureVerifiesAsDV("no-ocsp-int-path");
|
||||
// In this case, the end-entity has the test OID and the intermediate has the
|
||||
// CA/B Forum OID. Since the CA/B Forum OID is not treated the same as the
|
||||
|
|
@ -214,12 +278,18 @@ add_task(async function expectDVFallbackTests() {
|
|||
add_task(async function evRootTrustTests() {
|
||||
clearOCSPCache();
|
||||
info("untrusting evroot");
|
||||
certdb.setCertTrust(evroot, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.UNTRUSTED);
|
||||
certdb.setCertTrust(
|
||||
evroot,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.UNTRUSTED
|
||||
);
|
||||
await ensureVerificationFails("test-oid-path", SEC_ERROR_UNKNOWN_ISSUER);
|
||||
info("re-trusting evroot");
|
||||
certdb.setCertTrust(evroot, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL);
|
||||
certdb.setCertTrust(
|
||||
evroot,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL
|
||||
);
|
||||
await ensureVerifiesAsEV("test-oid-path");
|
||||
});
|
||||
|
||||
|
|
@ -235,21 +305,25 @@ add_task(async function localOnlyMustBeEVTests() {
|
|||
await ensureNoOCSPMeansNoEV("test-oid-path");
|
||||
});
|
||||
|
||||
|
||||
// Under certain conditions, OneCRL allows us to skip OCSP requests for
|
||||
// intermediates.
|
||||
add_task(async function oneCRLTests() {
|
||||
clearOCSPCache();
|
||||
|
||||
// enable OneCRL OCSP skipping - allow staleness of up to 30 hours
|
||||
Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
|
||||
108000);
|
||||
Services.prefs.setIntPref(
|
||||
"security.onecrl.maximum_staleness_in_seconds",
|
||||
108000
|
||||
);
|
||||
// set the blocklist-background-update-timer value to the recent past
|
||||
Services.prefs.setIntPref("services.settings.security.onecrl.checked",
|
||||
Math.floor(Date.now() / 1000) - 1);
|
||||
Services.prefs.setIntPref(
|
||||
"services.settings.security.onecrl.checked",
|
||||
Math.floor(Date.now() / 1000) - 1
|
||||
);
|
||||
Services.prefs.setIntPref(
|
||||
"app.update.lastUpdateTime.blocklist-background-update-timer",
|
||||
Math.floor(Date.now() / 1000) - 1);
|
||||
Math.floor(Date.now() / 1000) - 1
|
||||
);
|
||||
|
||||
await ensureOneCRLSkipsOCSPForIntermediates("anyPolicy-int-path");
|
||||
await ensureOneCRLSkipsOCSPForIntermediates("no-ocsp-int-path");
|
||||
|
|
@ -266,14 +340,19 @@ add_task(async function oneCRLTests() {
|
|||
|
||||
clearOCSPCache();
|
||||
// enable OneCRL OCSP skipping - allow staleness of up to 30 hours
|
||||
Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
|
||||
108000);
|
||||
Services.prefs.setIntPref(
|
||||
"security.onecrl.maximum_staleness_in_seconds",
|
||||
108000
|
||||
);
|
||||
// set the blocklist-background-update-timer value to the more distant past
|
||||
Services.prefs.setIntPref("services.settings.security.onecrl.checked",
|
||||
Math.floor(Date.now() / 1000) - 108080);
|
||||
Services.prefs.setIntPref(
|
||||
"services.settings.security.onecrl.checked",
|
||||
Math.floor(Date.now() / 1000) - 108080
|
||||
);
|
||||
Services.prefs.setIntPref(
|
||||
"app.update.lastUpdateTime.blocklist-background-update-timer",
|
||||
Math.floor(Date.now() / 1000) - 108080);
|
||||
Math.floor(Date.now() / 1000) - 108080
|
||||
);
|
||||
await ensureVerifiesAsEV("anyPolicy-int-path");
|
||||
await ensureVerifiesAsDV("no-ocsp-int-path");
|
||||
await ensureVerifiesAsEV("test-oid-path");
|
||||
|
|
@ -282,13 +361,16 @@ add_task(async function oneCRLTests() {
|
|||
// test the OCSP behavior when services.settings.security.onecrl.checked is in the
|
||||
// distant past and blacklist-background-update-timer is recent
|
||||
// enable OneCRL OCSP skipping - allow staleness of up to 30 hours
|
||||
Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
|
||||
108000);
|
||||
Services.prefs.setIntPref(
|
||||
"security.onecrl.maximum_staleness_in_seconds",
|
||||
108000
|
||||
);
|
||||
// set the blocklist-background-update-timer value to the recent past
|
||||
// (services.settings.security.onecrl.checked defaults to 0)
|
||||
Services.prefs.setIntPref(
|
||||
"app.update.lastUpdateTime.blocklist-background-update-timer",
|
||||
Math.floor(Date.now() / 1000) - 1);
|
||||
Math.floor(Date.now() / 1000) - 1
|
||||
);
|
||||
|
||||
await ensureVerifiesAsEV("anyPolicy-int-path");
|
||||
await ensureVerifiesAsDV("no-ocsp-int-path");
|
||||
|
|
@ -297,11 +379,15 @@ add_task(async function oneCRLTests() {
|
|||
clearOCSPCache();
|
||||
// test the OCSP behavior when services.settings.security.onecrl.checked is recent
|
||||
// enable OneCRL OCSP skipping - allow staleness of up to 30 hours
|
||||
Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
|
||||
108000);
|
||||
Services.prefs.setIntPref(
|
||||
"security.onecrl.maximum_staleness_in_seconds",
|
||||
108000
|
||||
);
|
||||
// now set services.settings.security.onecrl.checked to a recent value
|
||||
Services.prefs.setIntPref("services.settings.security.onecrl.checked",
|
||||
Math.floor(Date.now() / 1000) - 1);
|
||||
Services.prefs.setIntPref(
|
||||
"services.settings.security.onecrl.checked",
|
||||
Math.floor(Date.now() / 1000) - 1
|
||||
);
|
||||
await ensureOneCRLSkipsOCSPForIntermediates("anyPolicy-int-path");
|
||||
await ensureOneCRLSkipsOCSPForIntermediates("no-ocsp-int-path");
|
||||
await ensureOneCRLSkipsOCSPForIntermediates("test-oid-path");
|
||||
|
|
@ -309,7 +395,8 @@ add_task(async function oneCRLTests() {
|
|||
Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
|
||||
Services.prefs.clearUserPref("services.settings.security.onecrl.checked");
|
||||
Services.prefs.clearUserPref(
|
||||
"app.update.lastUpdateTime.blocklist-background-update-timer");
|
||||
"app.update.lastUpdateTime.blocklist-background-update-timer"
|
||||
);
|
||||
});
|
||||
|
||||
// Prime the OCSP cache and then ensure that we can validate certificates as EV
|
||||
|
|
@ -344,6 +431,7 @@ add_task(async function oldOCSPResponseTests() {
|
|||
|
||||
clearOCSPCache();
|
||||
await ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse(
|
||||
"anyPolicy-int-path");
|
||||
"anyPolicy-int-path"
|
||||
);
|
||||
await ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse("test-oid-path");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,12 +9,15 @@
|
|||
// Ensures that HSTS (HTTP Strict Transport Security) and HPKP (HTTP Public key
|
||||
// pinning) are cleared when using "Forget About This Site".
|
||||
|
||||
var { ForgetAboutSite } = ChromeUtils.import("resource://gre/modules/ForgetAboutSite.jsm");
|
||||
var { ForgetAboutSite } = ChromeUtils.import(
|
||||
"resource://gre/modules/ForgetAboutSite.jsm"
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots");
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
);
|
||||
});
|
||||
|
||||
const GOOD_MAX_AGE_SECONDS = 69403;
|
||||
|
|
@ -28,45 +31,68 @@ do_get_profile(); // must be done before instantiating nsIX509CertDB
|
|||
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots", true);
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
true
|
||||
);
|
||||
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
addCertFromFile(certdb, "test_pinning_dynamic/pinningroot.pem", "CTu,CTu,CTu");
|
||||
|
||||
var sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
var sss = Cc["@mozilla.org/ssservice;1"].getService(Ci.nsISiteSecurityService);
|
||||
var uri = Services.io.newURI("https://a.pinning2.example.com");
|
||||
|
||||
// This test re-uses certificates from pinning tests because that's easier and
|
||||
// simpler than recreating new certificates, hence the slightly longer than
|
||||
// necessary domain name.
|
||||
var secInfo = new FakeTransportSecurityInfo(constructCertFromFile(
|
||||
"test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem"));
|
||||
var secInfo = new FakeTransportSecurityInfo(
|
||||
constructCertFromFile(
|
||||
"test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem"
|
||||
)
|
||||
);
|
||||
|
||||
// Test the normal case of processing HSTS and HPKP headers for
|
||||
// a.pinning2.example.com, using "Forget About Site" on a.pinning2.example.com,
|
||||
// and then checking that the platform doesn't consider a.pinning2.example.com
|
||||
// to be HSTS or HPKP any longer.
|
||||
add_task(async function() {
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri, GOOD_MAX_AGE,
|
||||
secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN, secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
GOOD_MAX_AGE,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should be HSTS");
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should be HPKP");
|
||||
Assert.ok(
|
||||
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should be HSTS"
|
||||
);
|
||||
Assert.ok(
|
||||
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should be HPKP"
|
||||
);
|
||||
|
||||
await ForgetAboutSite.removeDataFromDomain("a.pinning2.example.com");
|
||||
|
||||
Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should not be HSTS now");
|
||||
Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should not be HPKP now");
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should not be HSTS now"
|
||||
);
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should not be HPKP now"
|
||||
);
|
||||
});
|
||||
|
||||
// Test the case of processing HSTS and HPKP headers for a.pinning2.example.com,
|
||||
|
|
@ -74,37 +100,63 @@ add_task(async function() {
|
|||
// doesn't consider the subdomain to be HSTS or HPKP any longer. Also test that
|
||||
// unrelated sites don't also get removed.
|
||||
add_task(async function() {
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri, GOOD_MAX_AGE,
|
||||
secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN, secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
GOOD_MAX_AGE,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should be HSTS (subdomain case)");
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should be HPKP (subdomain case)");
|
||||
Assert.ok(
|
||||
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should be HSTS (subdomain case)"
|
||||
);
|
||||
Assert.ok(
|
||||
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should be HPKP (subdomain case)"
|
||||
);
|
||||
|
||||
// Add an unrelated site to HSTS. Not HPKP because we have no valid keys for
|
||||
// example.org.
|
||||
let unrelatedURI = Services.io.newURI("https://example.org");
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI,
|
||||
GOOD_MAX_AGE, secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI, 0), "example.org should be HSTS");
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI,
|
||||
GOOD_MAX_AGE,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
Assert.ok(
|
||||
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI, 0),
|
||||
"example.org should be HSTS"
|
||||
);
|
||||
|
||||
await ForgetAboutSite.removeDataFromDomain("example.com");
|
||||
|
||||
Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should not be HSTS now (subdomain case)");
|
||||
Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should not be HPKP now (subdomain case)");
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"a.pinning2.example.com should not be HSTS now (subdomain case)"
|
||||
);
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning2.example.com should not be HPKP now (subdomain case)"
|
||||
);
|
||||
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI, 0),
|
||||
"example.org should still be HSTS");
|
||||
Assert.ok(
|
||||
sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI, 0),
|
||||
"example.org should still be HSTS"
|
||||
);
|
||||
});
|
||||
|
||||
// Test the case of processing HSTS and HPKP headers for a.pinning2.example.com
|
||||
|
|
@ -123,46 +175,97 @@ add_task(async function() {
|
|||
let unrelatedURI = Services.io.newURI("https://example.org");
|
||||
|
||||
for (let originAttributes of originAttributesList) {
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri, GOOD_MAX_AGE,
|
||||
secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
|
||||
originAttributes);
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN, secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
|
||||
originAttributes);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
GOOD_MAX_AGE,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
|
||||
originAttributes
|
||||
);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
|
||||
originAttributes
|
||||
);
|
||||
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
|
||||
0, originAttributes),
|
||||
"a.pinning2.example.com should be HSTS (originAttributes case)");
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
0, originAttributes),
|
||||
"a.pinning2.example.com should be HPKP (originAttributes case)");
|
||||
Assert.ok(
|
||||
sss.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
0,
|
||||
originAttributes
|
||||
),
|
||||
"a.pinning2.example.com should be HSTS (originAttributes case)"
|
||||
);
|
||||
Assert.ok(
|
||||
sss.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
0,
|
||||
originAttributes
|
||||
),
|
||||
"a.pinning2.example.com should be HPKP (originAttributes case)"
|
||||
);
|
||||
|
||||
// Add an unrelated site to HSTS. Not HPKP because we have no valid keys.
|
||||
sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI,
|
||||
GOOD_MAX_AGE, secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
|
||||
originAttributes);
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI, 0, originAttributes),
|
||||
"example.org should be HSTS (originAttributes case)");
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI,
|
||||
GOOD_MAX_AGE,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST,
|
||||
originAttributes
|
||||
);
|
||||
Assert.ok(
|
||||
sss.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI,
|
||||
0,
|
||||
originAttributes
|
||||
),
|
||||
"example.org should be HSTS (originAttributes case)"
|
||||
);
|
||||
}
|
||||
|
||||
await ForgetAboutSite.removeDataFromDomain("example.com");
|
||||
|
||||
for (let originAttributes of originAttributesList) {
|
||||
Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
|
||||
0, originAttributes),
|
||||
"a.pinning2.example.com should not be HSTS now " +
|
||||
"(originAttributes case)");
|
||||
Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
|
||||
0, originAttributes),
|
||||
"a.pinning2.example.com should not be HPKP now " +
|
||||
"(originAttributes case)");
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
0,
|
||||
originAttributes
|
||||
),
|
||||
"a.pinning2.example.com should not be HSTS now " +
|
||||
"(originAttributes case)"
|
||||
);
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
0,
|
||||
originAttributes
|
||||
),
|
||||
"a.pinning2.example.com should not be HPKP now " +
|
||||
"(originAttributes case)"
|
||||
);
|
||||
|
||||
Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI, 0, originAttributes),
|
||||
"example.org should still be HSTS (originAttributes case)");
|
||||
Assert.ok(
|
||||
sss.isSecureURI(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
unrelatedURI,
|
||||
0,
|
||||
originAttributes
|
||||
),
|
||||
"example.org should still be HSTS (originAttributes case)"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
// This file tests various aspects of the nsICryptoHash implementation for all
|
||||
// of the supported algorithms.
|
||||
|
||||
const messages = [
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
"",
|
||||
];
|
||||
const messages = ["The quick brown fox jumps over the lazy dog", ""];
|
||||
const ALGORITHMS = [
|
||||
{
|
||||
initString: "md5",
|
||||
|
|
@ -15,10 +12,7 @@ const ALGORITHMS = [
|
|||
"9e107d9d372bb6826bd81d3542a419d6",
|
||||
"d41d8cd98f00b204e9800998ecf8427e",
|
||||
],
|
||||
b64Hashes: [
|
||||
"nhB9nTcrtoJr2B01QqQZ1g==",
|
||||
"1B2M2Y8AsgTpgAmY7PhCfg==",
|
||||
],
|
||||
b64Hashes: ["nhB9nTcrtoJr2B01QqQZ1g==", "1B2M2Y8AsgTpgAmY7PhCfg=="],
|
||||
},
|
||||
{
|
||||
initString: "sha1",
|
||||
|
|
@ -27,10 +21,7 @@ const ALGORITHMS = [
|
|||
"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
],
|
||||
b64Hashes: [
|
||||
"L9ThxnotKPzthJ7hu3bnORuT6xI=",
|
||||
"2jmj7l5rSw0yVb/vlWAYkK/YBwk=",
|
||||
],
|
||||
b64Hashes: ["L9ThxnotKPzthJ7hu3bnORuT6xI=", "2jmj7l5rSw0yVb/vlWAYkK/YBwk="],
|
||||
},
|
||||
{
|
||||
initString: "sha256",
|
||||
|
|
@ -71,21 +62,30 @@ const ALGORITHMS = [
|
|||
];
|
||||
|
||||
function doHash(algo, value, cmp) {
|
||||
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(
|
||||
Ci.nsICryptoHash
|
||||
);
|
||||
hash.initWithString(algo);
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
let converter = Cc[
|
||||
"@mozilla.org/intl/scriptableunicodeconverter"
|
||||
].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "utf8";
|
||||
value = converter.convertToByteArray(value);
|
||||
hash.update(value, value.length);
|
||||
equal(hexify(hash.finish(false)), cmp,
|
||||
`Actual and expected hash for ${algo} should match`);
|
||||
equal(
|
||||
hexify(hash.finish(false)),
|
||||
cmp,
|
||||
`Actual and expected hash for ${algo} should match`
|
||||
);
|
||||
|
||||
hash.initWithString(algo);
|
||||
hash.update(value, value.length);
|
||||
equal(hexify(hash.finish(false)), cmp,
|
||||
`Actual and expected hash for ${algo} should match after re-init`);
|
||||
equal(
|
||||
hexify(hash.finish(false)),
|
||||
cmp,
|
||||
`Actual and expected hash for ${algo} should match after re-init`
|
||||
);
|
||||
}
|
||||
|
||||
function doHashStream(algo, value, cmp) {
|
||||
|
|
@ -94,29 +94,46 @@ function doHashStream(algo, value, cmp) {
|
|||
return;
|
||||
}
|
||||
|
||||
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(
|
||||
Ci.nsICryptoHash
|
||||
);
|
||||
hash.initWithString(algo);
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
let converter = Cc[
|
||||
"@mozilla.org/intl/scriptableunicodeconverter"
|
||||
].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "utf8";
|
||||
let stream = converter.convertToInputStream(value);
|
||||
hash.updateFromStream(stream, stream.available());
|
||||
equal(hexify(hash.finish(false)), cmp,
|
||||
`Actual and expected hash for ${algo} should match updating from stream`);
|
||||
equal(
|
||||
hexify(hash.finish(false)),
|
||||
cmp,
|
||||
`Actual and expected hash for ${algo} should match updating from stream`
|
||||
);
|
||||
}
|
||||
|
||||
function testInitConstantAndBase64(initConstant, algoName, message, expectedOutput) {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
function testInitConstantAndBase64(
|
||||
initConstant,
|
||||
algoName,
|
||||
message,
|
||||
expectedOutput
|
||||
) {
|
||||
let converter = Cc[
|
||||
"@mozilla.org/intl/scriptableunicodeconverter"
|
||||
].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "utf8";
|
||||
let value = converter.convertToByteArray(message);
|
||||
|
||||
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(
|
||||
Ci.nsICryptoHash
|
||||
);
|
||||
hash.init(initConstant);
|
||||
hash.update(value, value.length);
|
||||
equal(hash.finish(true), expectedOutput,
|
||||
`Actual and expected base64 hash for ${algoName} should match`);
|
||||
equal(
|
||||
hash.finish(true),
|
||||
expectedOutput,
|
||||
`Actual and expected base64 hash for ${algoName} should match`
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -126,8 +143,12 @@ function run_test() {
|
|||
doHashStream(algo.initString, messages[i], hash);
|
||||
});
|
||||
algo.b64Hashes.forEach((hash, i) => {
|
||||
testInitConstantAndBase64(algo.initConstant, algo.initString, messages[i],
|
||||
hash);
|
||||
testInitConstantAndBase64(
|
||||
algo.initConstant,
|
||||
algo.initString,
|
||||
messages[i],
|
||||
hash
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,19 @@
|
|||
// of the supported algorithms.
|
||||
|
||||
function getHMAC(data, key, alg, returnBase64) {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
let converter = Cc[
|
||||
"@mozilla.org/intl/scriptableunicodeconverter"
|
||||
].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "utf8";
|
||||
let dataArray = converter.convertToByteArray(data);
|
||||
|
||||
let keyObject = Cc["@mozilla.org/security/keyobjectfactory;1"]
|
||||
.getService(Ci.nsIKeyObjectFactory)
|
||||
.keyFromString(Ci.nsIKeyObject.HMAC, key);
|
||||
.getService(Ci.nsIKeyObjectFactory)
|
||||
.keyFromString(Ci.nsIKeyObject.HMAC, key);
|
||||
|
||||
let cryptoHMAC = Cc["@mozilla.org/security/hmac;1"]
|
||||
.createInstance(Ci.nsICryptoHMAC);
|
||||
let cryptoHMAC = Cc["@mozilla.org/security/hmac;1"].createInstance(
|
||||
Ci.nsICryptoHMAC
|
||||
);
|
||||
|
||||
cryptoHMAC.init(alg, keyObject);
|
||||
cryptoHMAC.update(dataArray, dataArray.length);
|
||||
|
|
@ -29,11 +31,17 @@ function getHMAC(data, key, alg, returnBase64) {
|
|||
cryptoHMAC.updateFromStream(stream, stream.available());
|
||||
let digestFromStream = cryptoHMAC.finish(returnBase64);
|
||||
|
||||
equal(digest1, digest2,
|
||||
"Initial digest and digest after calling reset() should match");
|
||||
equal(
|
||||
digest1,
|
||||
digest2,
|
||||
"Initial digest and digest after calling reset() should match"
|
||||
);
|
||||
|
||||
equal(digest1, digestFromStream,
|
||||
"Digest from buffer and digest from stream should match");
|
||||
equal(
|
||||
digest1,
|
||||
digestFromStream,
|
||||
"Digest from buffer and digest from stream should match"
|
||||
);
|
||||
|
||||
return digest1;
|
||||
}
|
||||
|
|
@ -49,9 +57,16 @@ function testHMAC(alg) {
|
|||
let digest2 = getHMAC(key2, dataA, alg, false);
|
||||
let digest1b = getHMAC(key1, dataA, alg, false);
|
||||
|
||||
equal(digest1a, digest1b,
|
||||
"The digests for the same key, data and algorithm should match");
|
||||
notEqual(digest1a, digest2, "The digests for different keys should not match");
|
||||
equal(
|
||||
digest1a,
|
||||
digest1b,
|
||||
"The digests for the same key, data and algorithm should match"
|
||||
);
|
||||
notEqual(
|
||||
digest1a,
|
||||
digest2,
|
||||
"The digests for different keys should not match"
|
||||
);
|
||||
|
||||
let digest1 = getHMAC(key1, dataA, alg, false);
|
||||
digest2 = getHMAC(key1, dataB, alg, false);
|
||||
|
|
@ -68,41 +83,57 @@ function testVectors() {
|
|||
const vectors = [
|
||||
// RFC 2202 section 2 test case 2.
|
||||
{
|
||||
algoID: Ci.nsICryptoHMAC.MD5, algoName: "MD5",
|
||||
algoID: Ci.nsICryptoHMAC.MD5,
|
||||
algoName: "MD5",
|
||||
expectedDigest: "750c783e6ab0b503eaa86e310a5db738",
|
||||
expectedBase64: "dQx4PmqwtQPqqG4xCl23OA==",
|
||||
},
|
||||
// RFC 2202 section 2 test case 3.
|
||||
{
|
||||
algoID: Ci.nsICryptoHMAC.SHA1, algoName: "SHA-1",
|
||||
algoID: Ci.nsICryptoHMAC.SHA1,
|
||||
algoName: "SHA-1",
|
||||
expectedDigest: "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
|
||||
expectedBase64: "7/zfauXrL6LSdBbV8YTfnCWafHk=",
|
||||
},
|
||||
// RFC 4231 section 4.3.
|
||||
{
|
||||
algoID: Ci.nsICryptoHMAC.SHA256, algoName: "SHA-256",
|
||||
expectedDigest: "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
|
||||
algoID: Ci.nsICryptoHMAC.SHA256,
|
||||
algoName: "SHA-256",
|
||||
expectedDigest:
|
||||
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
|
||||
expectedBase64: "W9zBRr9gdU5qBCQmCJV1x1oAPwidJzmDnexYuWTsOEM=",
|
||||
},
|
||||
{
|
||||
algoID: Ci.nsICryptoHMAC.SHA384, algoName: "SHA-384",
|
||||
expectedDigest: "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
|
||||
expectedBase64: "r0XS43ZIQDFhf3jStYprG5x+9GT1oBtH5C7Dc2MiRF6OIkDKXmnix4syOez6shZJ",
|
||||
algoID: Ci.nsICryptoHMAC.SHA384,
|
||||
algoName: "SHA-384",
|
||||
expectedDigest:
|
||||
"af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
|
||||
expectedBase64:
|
||||
"r0XS43ZIQDFhf3jStYprG5x+9GT1oBtH5C7Dc2MiRF6OIkDKXmnix4syOez6shZJ",
|
||||
},
|
||||
{
|
||||
algoID: Ci.nsICryptoHMAC.SHA512, algoName: "SHA-512",
|
||||
expectedDigest: "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
|
||||
expectedBase64: "Fkt6e/z4GeLjlfvnO1bgo4e9ZCIugx/WECcM1+olBVSXWL91wFqZSm0DT2X48Ob9yuqxo01Ka0tjbgcKOLznNw==",
|
||||
algoID: Ci.nsICryptoHMAC.SHA512,
|
||||
algoName: "SHA-512",
|
||||
expectedDigest:
|
||||
"164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
|
||||
expectedBase64:
|
||||
"Fkt6e/z4GeLjlfvnO1bgo4e9ZCIugx/WECcM1+olBVSXWL91wFqZSm0DT2X48Ob9yuqxo01Ka0tjbgcKOLznNw==",
|
||||
},
|
||||
];
|
||||
|
||||
for (let vector of vectors) {
|
||||
let digest = getHMAC(dataTestVector, keyTestVector, vector.algoID, false);
|
||||
equal(hexify(digest), vector.expectedDigest,
|
||||
`Actual and expected ${vector.algoName} digests should match`);
|
||||
equal(
|
||||
hexify(digest),
|
||||
vector.expectedDigest,
|
||||
`Actual and expected ${vector.algoName} digests should match`
|
||||
);
|
||||
let b64Digest = getHMAC(dataTestVector, keyTestVector, vector.algoID, true);
|
||||
equal(b64Digest, vector.expectedBase64,
|
||||
`Actual and expected ${vector.algoName} base64 digest should match`);
|
||||
equal(
|
||||
b64Digest,
|
||||
vector.expectedBase64,
|
||||
`Actual and expected ${vector.algoName} base64 digest should match`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +149,9 @@ function run_test() {
|
|||
// Our buffer size for working with streams is 4096 bytes. This tests we
|
||||
// handle larger inputs.
|
||||
let digest = getHMAC(" ".repeat(4100), "test", Ci.nsICryptoHMAC.MD5, false);
|
||||
equal(hexify(digest), "befbc875f73a088cf04e77f2b1286010",
|
||||
"Actual and expected digest for large stream should match");
|
||||
equal(
|
||||
hexify(digest),
|
||||
"befbc875f73a088cf04e77f2b1286010",
|
||||
"Actual and expected digest for large stream should match"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@
|
|||
// to the console.
|
||||
|
||||
function shouldBeImminentlyDistrusted(aTransportSecurityInfo) {
|
||||
let isDistrust = aTransportSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
|
||||
let isDistrust =
|
||||
aTransportSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
|
||||
Assert.ok(isDistrust, "This host should be imminently distrusted");
|
||||
}
|
||||
|
||||
function shouldNotBeImminentlyDistrusted(aTransportSecurityInfo) {
|
||||
let isDistrust = aTransportSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
|
||||
let isDistrust =
|
||||
aTransportSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
|
||||
Assert.ok(!isDistrust, "This host should not be imminently distrusted");
|
||||
}
|
||||
|
||||
|
|
@ -22,8 +24,16 @@ do_get_profile();
|
|||
|
||||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
|
||||
add_connection_test("imminently-distrusted.example.com",
|
||||
PRErrorCodeSuccess, null, shouldBeImminentlyDistrusted);
|
||||
add_connection_test(
|
||||
"imminently-distrusted.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
shouldBeImminentlyDistrusted
|
||||
);
|
||||
|
||||
add_connection_test("include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess, null, shouldNotBeImminentlyDistrusted);
|
||||
add_connection_test(
|
||||
"include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
shouldNotBeImminentlyDistrusted
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function load_cert(name, trust) {
|
||||
let filename = "test_intermediate_basic_usage_constraints/" + name + ".pem";
|
||||
|
|
@ -14,8 +15,11 @@ function test_cert_for_usages(certChainNicks, expected_usages) {
|
|||
for (let i in certChainNicks) {
|
||||
let certNick = certChainNicks[i];
|
||||
let certPEM = readFile(
|
||||
do_get_file("test_intermediate_basic_usage_constraints/"
|
||||
+ certNick + ".pem"), false);
|
||||
do_get_file(
|
||||
"test_intermediate_basic_usage_constraints/" + certNick + ".pem"
|
||||
),
|
||||
false
|
||||
);
|
||||
certs.push(certdb.constructX509FromBase64(pemToBase64(certPEM)));
|
||||
}
|
||||
|
||||
|
|
@ -24,11 +28,14 @@ function test_cert_for_usages(certChainNicks, expected_usages) {
|
|||
}
|
||||
|
||||
add_task(async function() {
|
||||
let ee_usages = [ certificateUsageSSLClient, certificateUsageSSLServer,
|
||||
certificateUsageEmailSigner,
|
||||
certificateUsageEmailRecipient ];
|
||||
let ca_usages = [ certificateUsageSSLCA ];
|
||||
let eku_usages = [ certificateUsageSSLClient, certificateUsageSSLServer ];
|
||||
let ee_usages = [
|
||||
certificateUsageSSLClient,
|
||||
certificateUsageSSLServer,
|
||||
certificateUsageEmailSigner,
|
||||
certificateUsageEmailRecipient,
|
||||
];
|
||||
let ca_usages = [certificateUsageSSLCA];
|
||||
let eku_usages = [certificateUsageSSLClient, certificateUsageSSLServer];
|
||||
|
||||
// Load the ca into mem
|
||||
let ca_name = "ca";
|
||||
|
|
@ -51,32 +58,44 @@ add_task(async function() {
|
|||
// a certificate with basicConstraints.cA==false but with the keyCertSign
|
||||
// key usage may not act as a CA (it can act like an end-entity).
|
||||
await test_cert_for_usages(["int-cA-FALSE-asserts-keyCertSign"], ee_usages);
|
||||
await test_cert_for_usages(["ee-int-cA-FALSE-asserts-keyCertSign",
|
||||
"int-cA-FALSE-asserts-keyCertSign"], []);
|
||||
|
||||
await test_cert_for_usages(
|
||||
["ee-int-cA-FALSE-asserts-keyCertSign", "int-cA-FALSE-asserts-keyCertSign"],
|
||||
[]
|
||||
);
|
||||
|
||||
// int-limited-depth has cA==true and a path length constraint of zero.
|
||||
await test_cert_for_usages(["int-limited-depth"], ca_usages);
|
||||
|
||||
// path length constraints do not affect the ability of a non-CA cert to
|
||||
// chain to to the CA cert.
|
||||
await test_cert_for_usages(["ee-int-limited-depth", "int-limited-depth"],
|
||||
ee_usages);
|
||||
await test_cert_for_usages(
|
||||
["ee-int-limited-depth", "int-limited-depth"],
|
||||
ee_usages
|
||||
);
|
||||
|
||||
// ca
|
||||
// int-limited-depth (cA==true, pathLenConstraint==0)
|
||||
// int-limited-depth-invalid (cA==true)
|
||||
//
|
||||
await test_cert_for_usages(["int-limited-depth-invalid", "int-limited-depth"],
|
||||
[]);
|
||||
await test_cert_for_usages(["ee-int-limited-depth-invalid",
|
||||
"int-limited-depth-invalid", "int-limited-depth"],
|
||||
[]);
|
||||
await test_cert_for_usages(
|
||||
["int-limited-depth-invalid", "int-limited-depth"],
|
||||
[]
|
||||
);
|
||||
await test_cert_for_usages(
|
||||
[
|
||||
"ee-int-limited-depth-invalid",
|
||||
"int-limited-depth-invalid",
|
||||
"int-limited-depth",
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
// int-valid-ku-no-eku has keyCertSign
|
||||
await test_cert_for_usages(["int-valid-ku-no-eku"], ca_usages);
|
||||
await test_cert_for_usages(["ee-int-valid-ku-no-eku", "int-valid-ku-no-eku"],
|
||||
ee_usages);
|
||||
await test_cert_for_usages(
|
||||
["ee-int-valid-ku-no-eku", "int-valid-ku-no-eku"],
|
||||
ee_usages
|
||||
);
|
||||
|
||||
// int-bad-ku-no-eku has basicConstraints.cA==true and has a KU extension
|
||||
// but the KU extension is missing keyCertSign. Note that mozilla::pkix
|
||||
|
|
@ -88,24 +107,32 @@ add_task(async function() {
|
|||
// int-no-ku-no-eku has basicConstraints.cA==true and no KU extension.
|
||||
// We treat a missing KU as "any key usage is OK".
|
||||
await test_cert_for_usages(["int-no-ku-no-eku"], ca_usages);
|
||||
await test_cert_for_usages(["ee-int-no-ku-no-eku", "int-no-ku-no-eku"],
|
||||
ee_usages);
|
||||
await test_cert_for_usages(
|
||||
["ee-int-no-ku-no-eku", "int-no-ku-no-eku"],
|
||||
ee_usages
|
||||
);
|
||||
|
||||
// int-valid-ku-server-eku has basicConstraints.cA==true, keyCertSign in KU,
|
||||
// and EKU=={id-kp-serverAuth,id-kp-clientAuth}.
|
||||
await test_cert_for_usages(["int-valid-ku-server-eku"], ca_usages);
|
||||
await test_cert_for_usages(["ee-int-valid-ku-server-eku",
|
||||
"int-valid-ku-server-eku"], eku_usages);
|
||||
await test_cert_for_usages(
|
||||
["ee-int-valid-ku-server-eku", "int-valid-ku-server-eku"],
|
||||
eku_usages
|
||||
);
|
||||
|
||||
// int-bad-ku-server-eku has basicConstraints.cA==true, a KU without
|
||||
// keyCertSign, and EKU=={id-kp-serverAuth,id-kp-clientAuth}.
|
||||
await test_cert_for_usages(["int-bad-ku-server-eku"], []);
|
||||
await test_cert_for_usages(["ee-int-bad-ku-server-eku",
|
||||
"int-bad-ku-server-eku"], []);
|
||||
await test_cert_for_usages(
|
||||
["ee-int-bad-ku-server-eku", "int-bad-ku-server-eku"],
|
||||
[]
|
||||
);
|
||||
|
||||
// int-bad-ku-server-eku has basicConstraints.cA==true, no KU, and
|
||||
// EKU=={id-kp-serverAuth,id-kp-clientAuth}.
|
||||
await test_cert_for_usages(["int-no-ku-server-eku"], ca_usages);
|
||||
await test_cert_for_usages(["ee-int-no-ku-server-eku",
|
||||
"int-no-ku-server-eku"], eku_usages);
|
||||
await test_cert_for_usages(
|
||||
["ee-int-no-ku-server-eku", "int-no-ku-server-eku"],
|
||||
eku_usages
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
|
@ -7,25 +6,37 @@
|
|||
"use strict";
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
|
||||
const {RemoteSettings} = ChromeUtils.import("resource://services-settings/remote-settings.js");
|
||||
const {RemoteSecuritySettings} = ChromeUtils.import("resource://gre/modules/psm/RemoteSecuritySettings.jsm");
|
||||
const {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
const {X509} = ChromeUtils.import("resource://gre/modules/psm/X509.jsm");
|
||||
const { RemoteSettings } = ChromeUtils.import(
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
const { RemoteSecuritySettings } = ChromeUtils.import(
|
||||
"resource://gre/modules/psm/RemoteSecuritySettings.jsm"
|
||||
);
|
||||
const { TestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
const { X509 } = ChromeUtils.import("resource://gre/modules/psm/X509.jsm");
|
||||
|
||||
const {IntermediatePreloadsClient} = RemoteSecuritySettings.init();
|
||||
const { IntermediatePreloadsClient } = RemoteSecuritySettings.init();
|
||||
|
||||
let server;
|
||||
|
||||
let intermediate1Data;
|
||||
let intermediate2Data;
|
||||
|
||||
const INTERMEDIATES_DL_PER_POLL_PREF = "security.remote_settings.intermediates.downloads_per_poll";
|
||||
const INTERMEDIATES_ENABLED_PREF = "security.remote_settings.intermediates.enabled";
|
||||
const INTERMEDIATES_DL_PER_POLL_PREF =
|
||||
"security.remote_settings.intermediates.downloads_per_poll";
|
||||
const INTERMEDIATES_ENABLED_PREF =
|
||||
"security.remote_settings.intermediates.enabled";
|
||||
|
||||
function getHashCommon(aStr, useBase64) {
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
|
||||
Ci.nsICryptoHash
|
||||
);
|
||||
hasher.init(Ci.nsICryptoHash.SHA256);
|
||||
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
|
||||
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
|
||||
Ci.nsIStringInputStream
|
||||
);
|
||||
stringStream.data = aStr;
|
||||
hasher.updateFromStream(stringStream, -1);
|
||||
|
||||
|
|
@ -78,32 +89,34 @@ async function syncAndDownload(filenames, options = {}) {
|
|||
const certDERBytes = atob(pemToBase64(certBytes));
|
||||
|
||||
const record = {
|
||||
"details": {
|
||||
"who": "",
|
||||
"why": "",
|
||||
"name": "",
|
||||
"created": "",
|
||||
details: {
|
||||
who: "",
|
||||
why: "",
|
||||
name: "",
|
||||
created: "",
|
||||
},
|
||||
"derHash": getHashCommon(certDERBytes, true),
|
||||
"subject": "",
|
||||
"subjectDN": btoa(getSubjectBytes(certDERBytes)),
|
||||
"attachment": {
|
||||
"hash": hashFunc(certBytes),
|
||||
"size": lengthFunc(certBytes),
|
||||
"filename": `intermediate certificate #${count}.pem`,
|
||||
"location": `security-state-workspace/intermediates/${filename}`,
|
||||
"mimetype": "application/x-pem-file",
|
||||
derHash: getHashCommon(certDERBytes, true),
|
||||
subject: "",
|
||||
subjectDN: btoa(getSubjectBytes(certDERBytes)),
|
||||
attachment: {
|
||||
hash: hashFunc(certBytes),
|
||||
size: lengthFunc(certBytes),
|
||||
filename: `intermediate certificate #${count}.pem`,
|
||||
location: `security-state-workspace/intermediates/${filename}`,
|
||||
mimetype: "application/x-pem-file",
|
||||
},
|
||||
"whitelist": false,
|
||||
"pubKeyHash": getHashCommon(getSPKIBytes(certDERBytes), true),
|
||||
"crlite_enrolled": true,
|
||||
whitelist: false,
|
||||
pubKeyHash: getHashCommon(getSPKIBytes(certDERBytes), true),
|
||||
crlite_enrolled: true,
|
||||
};
|
||||
|
||||
await localDB.create(record);
|
||||
count++;
|
||||
}
|
||||
// This promise will wait for the end of downloading.
|
||||
const updatedPromise = TestUtils.topicObserved("remote-security-settings:intermediates-updated");
|
||||
const updatedPromise = TestUtils.topicObserved(
|
||||
"remote-security-settings:intermediates-updated"
|
||||
);
|
||||
// Simulate polling for changes, trigger the download of attachments.
|
||||
Services.obs.notifyObservers(null, "remote-settings:changes-poll-end");
|
||||
const results = await updatedPromise;
|
||||
|
|
@ -120,238 +133,366 @@ async function locallyDownloaded() {
|
|||
});
|
||||
}
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_preload_empty() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
},
|
||||
async function test_preload_empty() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
equal(await syncAndDownload([]), "success", "Preloading update should have run");
|
||||
equal(
|
||||
await syncAndDownload([]),
|
||||
"success",
|
||||
"Preloading update should have run"
|
||||
);
|
||||
|
||||
equal((await locallyDownloaded()).length, 0, "There should have been no downloads");
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
0,
|
||||
"There should have been no downloads"
|
||||
);
|
||||
|
||||
// check that ee cert 1 is unknown
|
||||
await checkCertErrorGeneric(certDB, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_preload_disabled() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, false);
|
||||
|
||||
equal(await syncAndDownload(["int.pem"]), "disabled", "Preloading update should not have run");
|
||||
|
||||
equal((await locallyDownloaded()).length, 0, "There should have been no downloads");
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_preload_invalid_hash() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
const invalidHash = "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d";
|
||||
|
||||
const result = await syncAndDownload(["int.pem"], {
|
||||
hashFunc: () => invalidHash,
|
||||
});
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal((await locallyDownloaded()).length, 0, "There should be no local entry");
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
// We should still have a missing intermediate.
|
||||
await checkCertErrorGeneric(certDB, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_preload_invalid_length() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
|
||||
const result = await syncAndDownload(["int.pem"], {
|
||||
lengthFunc: () => 42,
|
||||
});
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal((await locallyDownloaded()).length, 0, "There should be no local entry");
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
// We should still have a missing intermediate.
|
||||
await checkCertErrorGeneric(certDB, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
});
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_preload_basic() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
Services.prefs.setIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
// load the second end entity, ignore both intermediate and root
|
||||
let ee_cert_2 = constructCertFromFile("test_intermediate_preloads/ee2.pem");
|
||||
notEqual(ee_cert_2, null, "EE cert 2 should have successfully loaded");
|
||||
|
||||
// check that the missing intermediate causes an unknown issuer error, as
|
||||
// expected, in both cases
|
||||
await checkCertErrorGeneric(certDB, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(certDB, ee_cert_2, SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let intermediateBytes = readFile(do_get_file("test_intermediate_preloads/int.pem"));
|
||||
let intermediateDERBytes = atob(pemToBase64(intermediateBytes));
|
||||
let intermediateCert = new X509.Certificate();
|
||||
intermediateCert.parse(stringToArray(intermediateDERBytes));
|
||||
let crliteStateBefore = certStorage.getCRLiteState(
|
||||
intermediateCert.tbsCertificate.subject._der._bytes,
|
||||
intermediateCert.tbsCertificate.subjectPublicKeyInfo._der._bytes);
|
||||
equal(crliteStateBefore, Ci.nsICertStorage.STATE_UNSET, "crlite state should be unset before");
|
||||
|
||||
const result = await syncAndDownload(["int.pem", "int2.pem"]);
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal((await locallyDownloaded()).length, 2, "There should have been 2 downloads");
|
||||
|
||||
// check that ee cert 1 verifies now the update has happened and there is
|
||||
// an intermediate
|
||||
await checkCertErrorGeneric(certDB, ee_cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
|
||||
let localDB = await IntermediatePreloadsClient.client.openCollection();
|
||||
let { data } = await localDB.list();
|
||||
ok(data.length > 0, "should have some entries");
|
||||
// simulate a sync (syncAndDownload doesn't actually... sync.)
|
||||
await IntermediatePreloadsClient.client.emit("sync", {
|
||||
"data": {
|
||||
current: data,
|
||||
created: data,
|
||||
deleted: [],
|
||||
updated: [],
|
||||
},
|
||||
});
|
||||
|
||||
let crliteStateAfter = certStorage.getCRLiteState(
|
||||
intermediateCert.tbsCertificate.subject._der._bytes,
|
||||
intermediateCert.tbsCertificate.subjectPublicKeyInfo._der._bytes);
|
||||
equal(crliteStateAfter, Ci.nsICertStorage.STATE_ENFORCE, "crlite state should be set after");
|
||||
|
||||
// check that ee cert 2 does not verify - since we don't know the issuer of
|
||||
// this certificate
|
||||
await checkCertErrorGeneric(certDB, ee_cert_2, SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer);
|
||||
});
|
||||
|
||||
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_preload_200() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
Services.prefs.setIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
|
||||
const files = [];
|
||||
for (let i = 0; i < 200; i++) {
|
||||
files.push(["int.pem", "int2.pem"][i % 2]);
|
||||
// check that ee cert 1 is unknown
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
let result = await syncAndDownload(files);
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal((await locallyDownloaded()).length, 100, "There should have been only 100 downloaded");
|
||||
|
||||
// Re-run
|
||||
result = await syncAndDownload([], { clear: false });
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal((await locallyDownloaded()).length, 200, "There should have been 200 downloaded");
|
||||
});
|
||||
|
||||
add_task({
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
}, async function test_delete() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
Services.prefs.setIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
},
|
||||
async function test_preload_disabled() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, false);
|
||||
|
||||
let syncResult = await syncAndDownload(["int.pem", "int2.pem"]);
|
||||
equal(syncResult, "success", "Preloading update should have run");
|
||||
equal(
|
||||
await syncAndDownload(["int.pem"]),
|
||||
"disabled",
|
||||
"Preloading update should not have run"
|
||||
);
|
||||
|
||||
equal((await locallyDownloaded()).length, 2, "There should have been 2 downloads");
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
0,
|
||||
"There should have been no downloads"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
let localDB = await IntermediatePreloadsClient.client.openCollection();
|
||||
let { data } = await localDB.list();
|
||||
ok(data.length > 0, "should have some entries");
|
||||
let subject = data[0].subjectDN;
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage);
|
||||
let resultsBefore = certStorage.findCertsBySubject(stringToArray(atob(subject)));
|
||||
equal(resultsBefore.length, 1, "should find the intermediate in cert storage before");
|
||||
// simulate a sync where we deleted the entry
|
||||
await IntermediatePreloadsClient.client.emit("sync", {
|
||||
"data": {
|
||||
current: [],
|
||||
created: [],
|
||||
deleted: [ data[0] ],
|
||||
updated: [],
|
||||
},
|
||||
});
|
||||
let resultsAfter = certStorage.findCertsBySubject(stringToArray(atob(subject)));
|
||||
equal(resultsAfter.length, 0, "shouldn't find intermediate in cert storage now");
|
||||
});
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_preload_invalid_hash() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
const invalidHash =
|
||||
"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d";
|
||||
|
||||
const result = await syncAndDownload(["int.pem"], {
|
||||
hashFunc: () => invalidHash,
|
||||
});
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
0,
|
||||
"There should be no local entry"
|
||||
);
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
// We should still have a missing intermediate.
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_preload_invalid_length() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
|
||||
const result = await syncAndDownload(["int.pem"], {
|
||||
lengthFunc: () => 42,
|
||||
});
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
0,
|
||||
"There should be no local entry"
|
||||
);
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
// We should still have a missing intermediate.
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_preload_basic() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
Services.prefs.setIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
// load the first root and end entity, ignore the initial intermediate
|
||||
addCertFromFile(certDB, "test_intermediate_preloads/ca.pem", "CTu,,");
|
||||
|
||||
let ee_cert = constructCertFromFile("test_intermediate_preloads/ee.pem");
|
||||
notEqual(ee_cert, null, "EE cert should have successfully loaded");
|
||||
|
||||
// load the second end entity, ignore both intermediate and root
|
||||
let ee_cert_2 = constructCertFromFile("test_intermediate_preloads/ee2.pem");
|
||||
notEqual(ee_cert_2, null, "EE cert 2 should have successfully loaded");
|
||||
|
||||
// check that the missing intermediate causes an unknown issuer error, as
|
||||
// expected, in both cases
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert,
|
||||
SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert_2,
|
||||
SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let intermediateBytes = readFile(
|
||||
do_get_file("test_intermediate_preloads/int.pem")
|
||||
);
|
||||
let intermediateDERBytes = atob(pemToBase64(intermediateBytes));
|
||||
let intermediateCert = new X509.Certificate();
|
||||
intermediateCert.parse(stringToArray(intermediateDERBytes));
|
||||
let crliteStateBefore = certStorage.getCRLiteState(
|
||||
intermediateCert.tbsCertificate.subject._der._bytes,
|
||||
intermediateCert.tbsCertificate.subjectPublicKeyInfo._der._bytes
|
||||
);
|
||||
equal(
|
||||
crliteStateBefore,
|
||||
Ci.nsICertStorage.STATE_UNSET,
|
||||
"crlite state should be unset before"
|
||||
);
|
||||
|
||||
const result = await syncAndDownload(["int.pem", "int2.pem"]);
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
2,
|
||||
"There should have been 2 downloads"
|
||||
);
|
||||
|
||||
// check that ee cert 1 verifies now the update has happened and there is
|
||||
// an intermediate
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
|
||||
let localDB = await IntermediatePreloadsClient.client.openCollection();
|
||||
let { data } = await localDB.list();
|
||||
ok(data.length > 0, "should have some entries");
|
||||
// simulate a sync (syncAndDownload doesn't actually... sync.)
|
||||
await IntermediatePreloadsClient.client.emit("sync", {
|
||||
data: {
|
||||
current: data,
|
||||
created: data,
|
||||
deleted: [],
|
||||
updated: [],
|
||||
},
|
||||
});
|
||||
|
||||
let crliteStateAfter = certStorage.getCRLiteState(
|
||||
intermediateCert.tbsCertificate.subject._der._bytes,
|
||||
intermediateCert.tbsCertificate.subjectPublicKeyInfo._der._bytes
|
||||
);
|
||||
equal(
|
||||
crliteStateAfter,
|
||||
Ci.nsICertStorage.STATE_ENFORCE,
|
||||
"crlite state should be set after"
|
||||
);
|
||||
|
||||
// check that ee cert 2 does not verify - since we don't know the issuer of
|
||||
// this certificate
|
||||
await checkCertErrorGeneric(
|
||||
certDB,
|
||||
ee_cert_2,
|
||||
SEC_ERROR_UNKNOWN_ISSUER,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_preload_200() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
Services.prefs.setIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
|
||||
const files = [];
|
||||
for (let i = 0; i < 200; i++) {
|
||||
files.push(["int.pem", "int2.pem"][i % 2]);
|
||||
}
|
||||
|
||||
let result = await syncAndDownload(files);
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
100,
|
||||
"There should have been only 100 downloaded"
|
||||
);
|
||||
|
||||
// Re-run
|
||||
result = await syncAndDownload([], { clear: false });
|
||||
equal(result, "success", "Preloading update should have run");
|
||||
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
200,
|
||||
"There should have been 200 downloaded"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
{
|
||||
skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE,
|
||||
},
|
||||
async function test_delete() {
|
||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
||||
Services.prefs.setIntPref(INTERMEDIATES_DL_PER_POLL_PREF, 100);
|
||||
|
||||
let syncResult = await syncAndDownload(["int.pem", "int2.pem"]);
|
||||
equal(syncResult, "success", "Preloading update should have run");
|
||||
|
||||
equal(
|
||||
(await locallyDownloaded()).length,
|
||||
2,
|
||||
"There should have been 2 downloads"
|
||||
);
|
||||
|
||||
let localDB = await IntermediatePreloadsClient.client.openCollection();
|
||||
let { data } = await localDB.list();
|
||||
ok(data.length > 0, "should have some entries");
|
||||
let subject = data[0].subjectDN;
|
||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||
Ci.nsICertStorage
|
||||
);
|
||||
let resultsBefore = certStorage.findCertsBySubject(
|
||||
stringToArray(atob(subject))
|
||||
);
|
||||
equal(
|
||||
resultsBefore.length,
|
||||
1,
|
||||
"should find the intermediate in cert storage before"
|
||||
);
|
||||
// simulate a sync where we deleted the entry
|
||||
await IntermediatePreloadsClient.client.emit("sync", {
|
||||
data: {
|
||||
current: [],
|
||||
created: [],
|
||||
deleted: [data[0]],
|
||||
updated: [],
|
||||
},
|
||||
});
|
||||
let resultsAfter = certStorage.findCertsBySubject(
|
||||
stringToArray(atob(subject))
|
||||
);
|
||||
equal(
|
||||
resultsAfter.length,
|
||||
0,
|
||||
"shouldn't find intermediate in cert storage now"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function run_test() {
|
||||
server = new HttpServer();
|
||||
server.start(-1);
|
||||
registerCleanupFunction(() => server.stop(() => { }));
|
||||
registerCleanupFunction(() => server.stop(() => {}));
|
||||
|
||||
server.registerDirectory("/cdn/security-state-workspace/intermediates/", do_get_file("test_intermediate_preloads"));
|
||||
server.registerDirectory(
|
||||
"/cdn/security-state-workspace/intermediates/",
|
||||
do_get_file("test_intermediate_preloads")
|
||||
);
|
||||
|
||||
server.registerPathHandler("/v1/", (request, response) => {
|
||||
response.write(JSON.stringify({
|
||||
capabilities: {
|
||||
attachments: {
|
||||
base_url: `http://localhost:${server.identity.primaryPort}/cdn/`,
|
||||
response.write(
|
||||
JSON.stringify({
|
||||
capabilities: {
|
||||
attachments: {
|
||||
base_url: `http://localhost:${server.identity.primaryPort}/cdn/`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
})
|
||||
);
|
||||
response.setHeader("Content-Type", "application/json; charset=UTF-8");
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
});
|
||||
|
||||
Services.prefs.setCharPref("services.settings.server",
|
||||
`http://localhost:${server.identity.primaryPort}/v1`);
|
||||
Services.prefs.setCharPref(
|
||||
"services.settings.server",
|
||||
`http://localhost:${server.identity.primaryPort}/v1`
|
||||
);
|
||||
|
||||
Services.prefs.setCharPref("browser.policies.loglevel", "debug");
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@ const gCertOverrideService = {
|
|||
},
|
||||
|
||||
hasMatchingOverride(hostname, port, cert, overrideBits, isTemporary) {
|
||||
Assert.equal(hostname, "expired.example.com",
|
||||
"hasMatchingOverride: hostname should be expired.example.com");
|
||||
Assert.equal(
|
||||
hostname,
|
||||
"expired.example.com",
|
||||
"hasMatchingOverride: hostname should be expired.example.com"
|
||||
);
|
||||
overrideBits.value = Ci.nsICertOverrideService.ERROR_TIME;
|
||||
isTemporary.value = false;
|
||||
return true;
|
||||
|
|
@ -44,9 +47,10 @@ const gCertOverrideService = {
|
|||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
let certOverrideServiceCID =
|
||||
MockRegistrar.register("@mozilla.org/security/certoverride;1",
|
||||
gCertOverrideService);
|
||||
let certOverrideServiceCID = MockRegistrar.register(
|
||||
"@mozilla.org/security/certoverride;1",
|
||||
gCertOverrideService
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(certOverrideServiceCID);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@
|
|||
// curves are rejected.
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
/**
|
||||
* Tests a cert chain.
|
||||
|
|
@ -27,8 +28,15 @@ const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
|||
* @return {Promise} a promise that will resolve when the verification has
|
||||
* completed
|
||||
*/
|
||||
function checkChain(rootKeyType, rootKeySize, intKeyType, intKeySize,
|
||||
eeKeyType, eeKeySize, eeExpectedError) {
|
||||
function checkChain(
|
||||
rootKeyType,
|
||||
rootKeySize,
|
||||
intKeyType,
|
||||
intKeySize,
|
||||
eeKeyType,
|
||||
eeKeySize,
|
||||
eeExpectedError
|
||||
) {
|
||||
let rootName = "root_" + rootKeyType + "_" + rootKeySize;
|
||||
let intName = "int_" + intKeyType + "_" + intKeySize;
|
||||
let eeName = "ee_" + eeKeyType + "_" + eeKeySize;
|
||||
|
|
@ -42,8 +50,12 @@ function checkChain(rootKeyType, rootKeySize, intKeyType, intKeySize,
|
|||
|
||||
info("cert o=" + eeCert.organization);
|
||||
info("cert issuer o=" + eeCert.issuerOrganization);
|
||||
return checkCertErrorGeneric(certdb, eeCert, eeExpectedError,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
eeCert,
|
||||
eeExpectedError,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -54,70 +66,135 @@ function checkChain(rootKeyType, rootKeySize, intKeyType, intKeySize,
|
|||
*/
|
||||
async function checkRSAChains(inadequateKeySize, adequateKeySize) {
|
||||
// Chain with certs that have adequate sizes for DV
|
||||
await checkChain("rsa", adequateKeySize,
|
||||
"rsa", adequateKeySize,
|
||||
"rsa", adequateKeySize,
|
||||
PRErrorCodeSuccess);
|
||||
await checkChain(
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
// Chain with a root cert that has an inadequate size for DV
|
||||
await checkChain("rsa", inadequateKeySize,
|
||||
"rsa", adequateKeySize,
|
||||
"rsa", adequateKeySize,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
|
||||
await checkChain(
|
||||
"rsa",
|
||||
inadequateKeySize,
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE
|
||||
);
|
||||
|
||||
// Chain with an intermediate cert that has an inadequate size for DV
|
||||
await checkChain("rsa", adequateKeySize,
|
||||
"rsa", inadequateKeySize,
|
||||
"rsa", adequateKeySize,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
|
||||
await checkChain(
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
"rsa",
|
||||
inadequateKeySize,
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE
|
||||
);
|
||||
|
||||
// Chain with an end entity cert that has an inadequate size for DV
|
||||
await checkChain("rsa", adequateKeySize,
|
||||
"rsa", adequateKeySize,
|
||||
"rsa", inadequateKeySize,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
|
||||
await checkChain(
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
"rsa",
|
||||
adequateKeySize,
|
||||
"rsa",
|
||||
inadequateKeySize,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
async function checkECCChains() {
|
||||
await checkChain("secp256r1", 256,
|
||||
"secp384r1", 384,
|
||||
"secp521r1", 521,
|
||||
PRErrorCodeSuccess);
|
||||
await checkChain("secp256r1", 256,
|
||||
"secp224r1", 224,
|
||||
"secp256r1", 256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
await checkChain("secp256r1", 256,
|
||||
"secp256r1", 256,
|
||||
"secp224r1", 224,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
await checkChain("secp224r1", 224,
|
||||
"secp256r1", 256,
|
||||
"secp256r1", 256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
await checkChain("secp256r1", 256,
|
||||
"secp256r1", 256,
|
||||
"secp256k1", 256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
await checkChain("secp256k1", 256,
|
||||
"secp256r1", 256,
|
||||
"secp256r1", 256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
await checkChain(
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp384r1",
|
||||
384,
|
||||
"secp521r1",
|
||||
521,
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkChain(
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp224r1",
|
||||
224,
|
||||
"secp256r1",
|
||||
256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE
|
||||
);
|
||||
await checkChain(
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp224r1",
|
||||
224,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE
|
||||
);
|
||||
await checkChain(
|
||||
"secp224r1",
|
||||
224,
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp256r1",
|
||||
256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE
|
||||
);
|
||||
await checkChain(
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp256k1",
|
||||
256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE
|
||||
);
|
||||
await checkChain(
|
||||
"secp256k1",
|
||||
256,
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp256r1",
|
||||
256,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE
|
||||
);
|
||||
}
|
||||
|
||||
async function checkCombinationChains() {
|
||||
await checkChain("rsa", 2048,
|
||||
"secp256r1", 256,
|
||||
"secp384r1", 384,
|
||||
PRErrorCodeSuccess);
|
||||
await checkChain("rsa", 2048,
|
||||
"secp256r1", 256,
|
||||
"secp224r1", 224,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
await checkChain("secp256r1", 256,
|
||||
"rsa", 1016,
|
||||
"secp256r1", 256,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
|
||||
await checkChain(
|
||||
"rsa",
|
||||
2048,
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp384r1",
|
||||
384,
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
await checkChain(
|
||||
"rsa",
|
||||
2048,
|
||||
"secp256r1",
|
||||
256,
|
||||
"secp224r1",
|
||||
224,
|
||||
SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE
|
||||
);
|
||||
await checkChain(
|
||||
"secp256r1",
|
||||
256,
|
||||
"rsa",
|
||||
1016,
|
||||
"secp256r1",
|
||||
256,
|
||||
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
|
|||
|
|
@ -7,15 +7,21 @@
|
|||
// are rejected.
|
||||
|
||||
do_get_profile(); // Must be called before getting nsIX509CertDB
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const SERVER_PORT = 8888;
|
||||
|
||||
function getOCSPResponder(expectedCertNames) {
|
||||
let expectedPaths = expectedCertNames.slice();
|
||||
return startOCSPResponder(SERVER_PORT, "www.example.com", "test_keysize_ev/",
|
||||
expectedCertNames, expectedPaths);
|
||||
return startOCSPResponder(
|
||||
SERVER_PORT,
|
||||
"www.example.com",
|
||||
"test_keysize_ev/",
|
||||
expectedCertNames,
|
||||
expectedPaths
|
||||
);
|
||||
}
|
||||
|
||||
function loadCert(certName, trustString) {
|
||||
|
|
@ -39,9 +45,13 @@ function loadCert(certName, trustString) {
|
|||
* @param {Boolean} expectedResult
|
||||
* Whether the chain is expected to validate as EV.
|
||||
*/
|
||||
async function keySizeTestForEV(expectedNamesForOCSP,
|
||||
rootCertFileName, intCertFileNames,
|
||||
endEntityCertFileName, expectedResult) {
|
||||
async function keySizeTestForEV(
|
||||
expectedNamesForOCSP,
|
||||
rootCertFileName,
|
||||
intCertFileNames,
|
||||
endEntityCertFileName,
|
||||
expectedResult
|
||||
) {
|
||||
clearOCSPCache();
|
||||
let ocspResponder = getOCSPResponder(expectedNamesForOCSP);
|
||||
|
||||
|
|
@ -53,7 +63,8 @@ async function keySizeTestForEV(expectedNamesForOCSP,
|
|||
certDB,
|
||||
constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`),
|
||||
certificateUsageSSLServer,
|
||||
expectedResult);
|
||||
expectedResult
|
||||
);
|
||||
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
}
|
||||
|
|
@ -91,51 +102,70 @@ async function checkRSAChains(inadequateKeySize, adequateKeySize) {
|
|||
let intFullName = intOKName + "-" + rootOKName;
|
||||
let eeFullName = eeOKName + "-" + intOKName + "-" + rootOKName;
|
||||
let expectedNamesForOCSP = gEVExpected
|
||||
? [ intFullName,
|
||||
eeFullName ]
|
||||
: [ eeFullName ];
|
||||
await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
|
||||
[ intFullName ], eeFullName, gEVExpected);
|
||||
? [intFullName, eeFullName]
|
||||
: [eeFullName];
|
||||
await keySizeTestForEV(
|
||||
expectedNamesForOCSP,
|
||||
rootOKCertFileName,
|
||||
[intFullName],
|
||||
eeFullName,
|
||||
gEVExpected
|
||||
);
|
||||
|
||||
// Chain with a root cert that has an inadequate size for EV, but
|
||||
// adequate size for DV
|
||||
intFullName = intOKName + "-" + rootNotOKName;
|
||||
eeFullName = eeOKName + "-" + intOKName + "-" + rootNotOKName;
|
||||
expectedNamesForOCSP = [ eeFullName ];
|
||||
await keySizeTestForEV(expectedNamesForOCSP, rootNotOKName,
|
||||
[ intFullName ], eeFullName, false);
|
||||
expectedNamesForOCSP = [eeFullName];
|
||||
await keySizeTestForEV(
|
||||
expectedNamesForOCSP,
|
||||
rootNotOKName,
|
||||
[intFullName],
|
||||
eeFullName,
|
||||
false
|
||||
);
|
||||
|
||||
// Chain with an intermediate cert that has an inadequate size for EV, but
|
||||
// adequate size for DV
|
||||
intFullName = intNotOKName + "-" + rootOKName;
|
||||
eeFullName = eeOKName + "-" + intNotOKName + "-" + rootOKName;
|
||||
expectedNamesForOCSP = [ eeFullName ];
|
||||
await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
|
||||
[ intFullName ], eeFullName, false);
|
||||
expectedNamesForOCSP = [eeFullName];
|
||||
await keySizeTestForEV(
|
||||
expectedNamesForOCSP,
|
||||
rootOKCertFileName,
|
||||
[intFullName],
|
||||
eeFullName,
|
||||
false
|
||||
);
|
||||
|
||||
// Chain with an end entity cert that has an inadequate size for EV, but
|
||||
// adequate size for DV
|
||||
intFullName = intOKName + "-" + rootOKName;
|
||||
eeFullName = eeNotOKName + "-" + intOKName + "-" + rootOKName;
|
||||
expectedNamesForOCSP = gEVExpected
|
||||
? [ intFullName,
|
||||
eeFullName ]
|
||||
: [ eeFullName ];
|
||||
await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
|
||||
[ intFullName ], eeFullName, false);
|
||||
expectedNamesForOCSP = gEVExpected ? [intFullName, eeFullName] : [eeFullName];
|
||||
await keySizeTestForEV(
|
||||
expectedNamesForOCSP,
|
||||
rootOKCertFileName,
|
||||
[intFullName],
|
||||
eeFullName,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
|
||||
Services.prefs.setIntPref("security.OCSP.enabled", 1);
|
||||
|
||||
let smallKeyEVRoot =
|
||||
constructCertFromFile("test_keysize_ev/ev_root_rsa_2040.pem");
|
||||
equal(smallKeyEVRoot.sha256Fingerprint,
|
||||
"40:AB:5D:A5:89:15:A9:4B:82:87:B8:A6:9A:84:B1:DB:" +
|
||||
"7A:9D:DB:B8:4E:E1:23:E3:C6:64:E7:50:DC:35:8C:68",
|
||||
"test sanity check: the small-key EV root must have the same " +
|
||||
"fingerprint as the corresponding entry in ExtendedValidation.cpp");
|
||||
let smallKeyEVRoot = constructCertFromFile(
|
||||
"test_keysize_ev/ev_root_rsa_2040.pem"
|
||||
);
|
||||
equal(
|
||||
smallKeyEVRoot.sha256Fingerprint,
|
||||
"40:AB:5D:A5:89:15:A9:4B:82:87:B8:A6:9A:84:B1:DB:" +
|
||||
"7A:9D:DB:B8:4E:E1:23:E3:C6:64:E7:50:DC:35:8C:68",
|
||||
"test sanity check: the small-key EV root must have the same " +
|
||||
"fingerprint as the corresponding entry in ExtendedValidation.cpp"
|
||||
);
|
||||
|
||||
await checkRSAChains(2040, 2048);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const certService = Cc["@mozilla.org/security/local-cert-service;1"]
|
||||
.getService(Ci.nsILocalCertService);
|
||||
const certService = Cc["@mozilla.org/security/local-cert-service;1"].getService(
|
||||
Ci.nsILocalCertService
|
||||
);
|
||||
|
||||
const gNickname = "local-cert-test";
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
|
|||
|
||||
function getCert() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let certService = Cc["@mozilla.org/security/local-cert-service;1"]
|
||||
.getService(Ci.nsILocalCertService);
|
||||
let certService = Cc[
|
||||
"@mozilla.org/security/local-cert-service;1"
|
||||
].getService(Ci.nsILocalCertService);
|
||||
certService.getOrCreateCert("beConservative-test", {
|
||||
handleCert: (c, rv) => {
|
||||
if (rv) {
|
||||
|
|
@ -44,21 +45,31 @@ class InputStreamCallback {
|
|||
available = stream.available();
|
||||
} catch (e) {
|
||||
// onInputStreamReady may fire when the stream has been closed.
|
||||
equal(e.result, Cr.NS_BASE_STREAM_CLOSED,
|
||||
"error should be NS_BASE_STREAM_CLOSED");
|
||||
equal(
|
||||
e.result,
|
||||
Cr.NS_BASE_STREAM_CLOSED,
|
||||
"error should be NS_BASE_STREAM_CLOSED"
|
||||
);
|
||||
}
|
||||
if (available > 0) {
|
||||
let request = NetUtil.readInputStreamToString(stream, available,
|
||||
{ charset: "utf8" });
|
||||
ok(request.startsWith("GET / HTTP/1.1\r\n"),
|
||||
"Should get a simple GET / HTTP/1.1 request");
|
||||
let response = "HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 2\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"\r\nOK";
|
||||
let request = NetUtil.readInputStreamToString(stream, available, {
|
||||
charset: "utf8",
|
||||
});
|
||||
ok(
|
||||
request.startsWith("GET / HTTP/1.1\r\n"),
|
||||
"Should get a simple GET / HTTP/1.1 request"
|
||||
);
|
||||
let response =
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 2\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"\r\nOK";
|
||||
let written = this.output.write(response, response.length);
|
||||
equal(written, response.length,
|
||||
"should have been able to write entire response");
|
||||
equal(
|
||||
written,
|
||||
response.length,
|
||||
"should have been able to write entire response"
|
||||
);
|
||||
}
|
||||
this.output.close();
|
||||
info("done with input stream ready");
|
||||
|
|
@ -93,7 +104,8 @@ class TLSServerSecurityObserver {
|
|||
|
||||
// We've set up everything needed for a successful request/response,
|
||||
// but calling logoutAndTeardown should cause the request to be cancelled.
|
||||
Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing)
|
||||
Cc["@mozilla.org/security/sdr;1"]
|
||||
.getService(Ci.nsISecretDecoderRing)
|
||||
.logoutAndTeardown();
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +113,7 @@ class TLSServerSecurityObserver {
|
|||
this.stopped = true;
|
||||
this.input.close();
|
||||
this.output.close();
|
||||
this.callbacks.forEach((callback) => {
|
||||
this.callbacks.forEach(callback => {
|
||||
callback.stop();
|
||||
});
|
||||
}
|
||||
|
|
@ -114,8 +126,9 @@ class ServerSocketListener {
|
|||
|
||||
onSocketAccepted(socket, transport) {
|
||||
info("accepted TLS client connection");
|
||||
let connectionInfo = transport.securityInfo
|
||||
.QueryInterface(Ci.nsITLSServerConnectionInfo);
|
||||
let connectionInfo = transport.securityInfo.QueryInterface(
|
||||
Ci.nsITLSServerConnectionInfo
|
||||
);
|
||||
let input = transport.openInputStream(0, 0, 0);
|
||||
let output = transport.openOutputStream(0, 0, 0);
|
||||
let securityObserver = new TLSServerSecurityObserver(input, output);
|
||||
|
|
@ -127,15 +140,16 @@ class ServerSocketListener {
|
|||
// listening, so this ensures we just drop those events.
|
||||
onStopListening() {
|
||||
info("onStopListening");
|
||||
this.securityObservers.forEach((observer) => {
|
||||
this.securityObservers.forEach(observer => {
|
||||
observer.stop();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getStartedServer(cert) {
|
||||
let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
|
||||
.createInstance(Ci.nsITLSServerSocket);
|
||||
let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance(
|
||||
Ci.nsITLSServerSocket
|
||||
);
|
||||
tlsServer.init(-1, true, -1);
|
||||
tlsServer.serverCert = cert;
|
||||
tlsServer.setSessionTickets(false);
|
||||
|
|
@ -146,12 +160,19 @@ function getStartedServer(cert) {
|
|||
const hostname = "example.com";
|
||||
|
||||
function storeCertOverride(port, cert) {
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
let overrideBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH;
|
||||
certOverrideService.rememberValidityOverride(hostname, port, cert,
|
||||
overrideBits, true);
|
||||
let certOverrideService = Cc[
|
||||
"@mozilla.org/security/certoverride;1"
|
||||
].getService(Ci.nsICertOverrideService);
|
||||
let overrideBits =
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED |
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH;
|
||||
certOverrideService.rememberValidityOverride(
|
||||
hostname,
|
||||
port,
|
||||
cert,
|
||||
overrideBits,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function startClient(port) {
|
||||
|
|
|
|||
|
|
@ -8,15 +8,19 @@
|
|||
// Tests that if a server does not send a complete certificate chain, we can
|
||||
// make use of cached intermediates to build a trust path.
|
||||
|
||||
const {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
const { TestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function run_certutil_on_directory(directory, args) {
|
||||
let envSvc = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let envSvc = Cc["@mozilla.org/process/environment;1"].getService(
|
||||
Ci.nsIEnvironment
|
||||
);
|
||||
let greBinDir = Services.dirsvc.get("GreBinD", Ci.nsIFile);
|
||||
envSvc.set("DYLD_LIBRARY_PATH", greBinDir.path);
|
||||
// TODO(bug 1107794): Android libraries are in /data/local/xpcb, but "GreBinD"
|
||||
|
|
@ -35,24 +39,32 @@ registerCleanupFunction(() => {
|
|||
let certDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
|
||||
certDir.append("bad_certs");
|
||||
Assert.ok(certDir.exists(), "bad_certs should exist");
|
||||
let args = [ "-D", "-n", "manually-added-missing-intermediate" ];
|
||||
let args = ["-D", "-n", "manually-added-missing-intermediate"];
|
||||
run_certutil_on_directory(certDir.path, args);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
// If we don't know about the intermediate, we'll get an unknown issuer error.
|
||||
add_connection_test("ee-from-missing-intermediate.example.com",
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
add_connection_test(
|
||||
"ee-from-missing-intermediate.example.com",
|
||||
SEC_ERROR_UNKNOWN_ISSUER
|
||||
);
|
||||
|
||||
// Make BadCertServer aware of the intermediate.
|
||||
add_test(() => {
|
||||
// NB: missing-intermediate.der won't be regenerated when
|
||||
// missing-intermediate.pem is. Hopefully by that time we can just use
|
||||
// missing-intermediate.pem directly.
|
||||
let args = [ "-A", "-n", "manually-added-missing-intermediate", "-i",
|
||||
"test_missing_intermediate/missing-intermediate.der", "-t",
|
||||
",," ];
|
||||
let args = [
|
||||
"-A",
|
||||
"-n",
|
||||
"manually-added-missing-intermediate",
|
||||
"-i",
|
||||
"test_missing_intermediate/missing-intermediate.der",
|
||||
"-t",
|
||||
",,",
|
||||
];
|
||||
let certDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
|
||||
certDir.append("bad_certs");
|
||||
Assert.ok(certDir.exists(), "bad_certs should exist");
|
||||
|
|
@ -63,12 +75,16 @@ function run_test() {
|
|||
// We have to start observing the topic before there's a chance it gets
|
||||
// emitted.
|
||||
add_test(() => {
|
||||
TestUtils.topicObserved("psm:intermediate-certs-cached").then(run_next_test);
|
||||
TestUtils.topicObserved("psm:intermediate-certs-cached").then(
|
||||
run_next_test
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
// Connect and cache the intermediate.
|
||||
add_connection_test("ee-from-missing-intermediate.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test(
|
||||
"ee-from-missing-intermediate.example.com",
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
// Add a dummy test so that the only way we advance from here is by observing
|
||||
// "psm:intermediate-certs-cached".
|
||||
|
|
@ -78,14 +94,16 @@ function run_test() {
|
|||
// will fail if we didn't.
|
||||
add_test(() => {
|
||||
// Here we have to use the name that gecko chooses to give it.
|
||||
let args = [ "-D", "-n", "Missing Intermediate" ];
|
||||
let args = ["-D", "-n", "Missing Intermediate"];
|
||||
run_certutil_on_directory(do_get_profile().path, args);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Since we cached the intermediate, this should succeed.
|
||||
add_connection_test("ee-from-missing-intermediate.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test(
|
||||
"ee-from-missing-intermediate.example.com",
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,26 +25,34 @@
|
|||
// existing hierarchy that has externally-imposed name constraints (DCISS).
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function certFromFile(name) {
|
||||
return constructCertFromFile(`test_name_constraints/${name}.pem`);
|
||||
}
|
||||
|
||||
function loadCertWithTrust(certName, trustString) {
|
||||
addCertFromFile(certdb, `test_name_constraints/${certName}.pem`,
|
||||
trustString);
|
||||
addCertFromFile(certdb, `test_name_constraints/${certName}.pem`, trustString);
|
||||
}
|
||||
|
||||
function checkCertNotInNameSpace(cert) {
|
||||
return checkCertErrorGeneric(certdb, cert, SEC_ERROR_CERT_NOT_IN_NAME_SPACE,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
SEC_ERROR_CERT_NOT_IN_NAME_SPACE,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
function checkCertInNameSpace(cert) {
|
||||
return checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
|
|||
|
|
@ -8,40 +8,46 @@
|
|||
// Tests to make sure that the certificate DB works with non-ASCII paths.
|
||||
|
||||
// Append a single quote and non-ASCII characters to the profile path.
|
||||
let env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(
|
||||
Ci.nsIEnvironment
|
||||
);
|
||||
let profd = env.get("XPCSHELL_TEST_PROFILE_DIR");
|
||||
let file = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsIFile);
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(profd);
|
||||
file.append("'÷1");
|
||||
env.set("XPCSHELL_TEST_PROFILE_DIR", file.path);
|
||||
|
||||
file = do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
Assert.ok(/[^\x20-\x7f]/.test(file.path), "the profile path should contain a non-ASCII character");
|
||||
Assert.ok(
|
||||
/[^\x20-\x7f]/.test(file.path),
|
||||
"the profile path should contain a non-ASCII character"
|
||||
);
|
||||
if (mozinfo.os == "win") {
|
||||
file.QueryInterface(Ci.nsILocalFileWin);
|
||||
Assert.ok(/[^\x20-\x7f]/.test(file.canonicalPath), "the profile short path should contain a non-ASCII character");
|
||||
Assert.ok(
|
||||
/[^\x20-\x7f]/.test(file.canonicalPath),
|
||||
"the profile short path should contain a non-ASCII character"
|
||||
);
|
||||
}
|
||||
|
||||
// Restore the original value.
|
||||
env.set("XPCSHELL_TEST_PROFILE_DIR", profd);
|
||||
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function load_cert(cert_name, trust_string) {
|
||||
let cert_filename = cert_name + ".pem";
|
||||
return addCertFromFile(certdb, "test_cert_trust/" + cert_filename,
|
||||
trust_string);
|
||||
return addCertFromFile(
|
||||
certdb,
|
||||
"test_cert_trust/" + cert_filename,
|
||||
trust_string
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
let certList = [
|
||||
"ca",
|
||||
"int",
|
||||
"ee",
|
||||
];
|
||||
let certList = ["ca", "int", "ee"];
|
||||
let loadedCerts = [];
|
||||
for (let certName of certList) {
|
||||
loadedCerts.push(load_cert(certName, ",,"));
|
||||
|
|
|
|||
|
|
@ -20,9 +20,13 @@ function run_test() {
|
|||
do_get_profile();
|
||||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
add_connection_test("nsCertTypeNotCritical.example.com", PRErrorCodeSuccess);
|
||||
add_connection_test("nsCertTypeCriticalWithExtKeyUsage.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_connection_test("nsCertTypeCritical.example.com",
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
|
||||
add_connection_test(
|
||||
"nsCertTypeCriticalWithExtKeyUsage.example.com",
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
add_connection_test(
|
||||
"nsCertTypeCritical.example.com",
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@ function fuzzyEqual(attributeName, dateString, expectedTime) {
|
|||
info(`${attributeName}: ${dateString}`);
|
||||
let absTimeDiff = Math.abs(expectedTime - Date.parse(dateString));
|
||||
const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
|
||||
lessOrEqual(absTimeDiff, ONE_DAY_IN_MS,
|
||||
`Time difference for ${attributeName} should be <= one day`);
|
||||
lessOrEqual(
|
||||
absTimeDiff,
|
||||
ONE_DAY_IN_MS,
|
||||
`Time difference for ${attributeName} should be <= one day`
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -20,10 +23,16 @@ function run_test() {
|
|||
const NOT_AFTER_IN_MS = 1388534400000;
|
||||
let cert = constructCertFromFile("bad_certs/expired-ee.pem");
|
||||
|
||||
equal(cert.validity.notBefore, NOT_BEFORE_IN_MS * 1000,
|
||||
"Actual and expected notBefore should be equal");
|
||||
equal(cert.validity.notAfter, NOT_AFTER_IN_MS * 1000,
|
||||
"Actual and expected notAfter should be equal");
|
||||
equal(
|
||||
cert.validity.notBefore,
|
||||
NOT_BEFORE_IN_MS * 1000,
|
||||
"Actual and expected notBefore should be equal"
|
||||
);
|
||||
equal(
|
||||
cert.validity.notAfter,
|
||||
NOT_AFTER_IN_MS * 1000,
|
||||
"Actual and expected notAfter should be equal"
|
||||
);
|
||||
|
||||
// The following tests rely on the implementation of nsIX509CertValidity
|
||||
// providing long formatted dates to work. If this is not true, a returned
|
||||
|
|
@ -34,16 +43,28 @@ function run_test() {
|
|||
// return a long formatted date even if it is asked to. This, combined with
|
||||
// the reason above is why the following tests are disabled on Android.
|
||||
if (AppConstants.platform != "android") {
|
||||
fuzzyEqual("notBeforeLocalTime", cert.validity.notBeforeLocalTime,
|
||||
NOT_BEFORE_IN_MS);
|
||||
fuzzyEqual("notBeforeLocalDay", cert.validity.notBeforeLocalDay,
|
||||
NOT_BEFORE_IN_MS);
|
||||
fuzzyEqual(
|
||||
"notBeforeLocalTime",
|
||||
cert.validity.notBeforeLocalTime,
|
||||
NOT_BEFORE_IN_MS
|
||||
);
|
||||
fuzzyEqual(
|
||||
"notBeforeLocalDay",
|
||||
cert.validity.notBeforeLocalDay,
|
||||
NOT_BEFORE_IN_MS
|
||||
);
|
||||
fuzzyEqual("notBeforeGMT", cert.validity.notBeforeGMT, NOT_BEFORE_IN_MS);
|
||||
|
||||
fuzzyEqual("notAfterLocalTime", cert.validity.notAfterLocalTime,
|
||||
NOT_AFTER_IN_MS);
|
||||
fuzzyEqual("notAfterLocalDay", cert.validity.notAfterLocalDay,
|
||||
NOT_AFTER_IN_MS);
|
||||
fuzzyEqual(
|
||||
"notAfterLocalTime",
|
||||
cert.validity.notAfterLocalTime,
|
||||
NOT_AFTER_IN_MS
|
||||
);
|
||||
fuzzyEqual(
|
||||
"notAfterLocalDay",
|
||||
cert.validity.notAfterLocalDay,
|
||||
NOT_AFTER_IN_MS
|
||||
);
|
||||
fuzzyEqual("notAfterGMT", cert.validity.notAfterGMT, NOT_AFTER_IN_MS);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,62 +7,90 @@
|
|||
// Checks that various nsIX509Cert attributes correctly handle UTF-8.
|
||||
|
||||
do_get_profile(); // Must be called before getting nsIX509CertDB
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
function run_test() {
|
||||
let cert = certDB.constructX509FromBase64(
|
||||
"MIIF3DCCBMSgAwIBAgIEAJiZbzANBgkqhkiG9w0BAQUFADCCAQ0xYTBfBgNVBAMM" +
|
||||
"WEkuQ0EgLSBRdWFsaWZpZWQgcm9vdCBjZXJ0aWZpY2F0ZSAoa3ZhbGlmaWtvdmFu" +
|
||||
"w70gY2VydGlmaWvDoXQgcG9za3l0b3ZhdGVsZSkgLSBQU0VVRE9OWU0xCzAJBgNV" +
|
||||
"BAYTAkNaMS8wLQYDVQQHDCZQb2R2aW5uw70gbWzDvW4gMjE3OC82LCAxOTAgMDAg" +
|
||||
"UHJhaGEgOTEsMCoGA1UECgwjUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRh" +
|
||||
"IGEucy4xPDA6BgNVBAsMM0FrcmVkaXRvdmFuw70gcG9za3l0b3ZhdGVsIGNlcnRp" +
|
||||
"ZmlrYcSNbsOtY2ggc2x1xb5lYjAeFw0wMjEyMTIxMzMzNDZaFw0wMzEyMTIxMzMz" +
|
||||
"NDZaMIIBFDELMAkGA1UEBhMCQ1oxHzAdBgNVBAMeFgBMAHUAZAEbAGsAIABSAGEB" +
|
||||
"YQBlAGsxGTAXBgNVBAgeEABWAHkAcwBvAQ0AaQBuAGExLzAtBgNVBAceJgBQAGEA" +
|
||||
"YwBvAHYALAAgAE4A4QBkAHIAYQF+AG4A7QAgADcANgA5MSUwIwYJKoZIhvcNAQkB" +
|
||||
"FhZsdWRlay5yYXNla0BjZW50cnVtLmN6MRMwEQYDVQQqHgoATAB1AGQBGwBrMQ0w" +
|
||||
"CwYDVQQrHgQATABSMR8wHQYDVQQpHhYATAB1AGQBGwBrACAAUgBhAWEAZQBrMRMw" +
|
||||
"EQYDVQQEHgoAUgBhAWEAZQBrMRcwFQYDVQQFEw5JQ0EgLSAxMDAwMzc2OTCBnzAN" +
|
||||
"BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxc7dGd0cNlHZ7tUUl5k30bfYlY3lnOD0" +
|
||||
"49JGbTXSt4jNFMRLj6s/777W3kcIdcIwdKxjQULBKgryDvZJ1DAWp2TwzhPDVYj3" +
|
||||
"sU4Niqb7mOUcp/4ckteUxGF6FmXtJR9+XHTuLZ+omF9HOUefheBKnXvZuqrLM16y" +
|
||||
"nbJn4sPwwdcCAwEAAaOCAbswggG3MCUGA1UdEQQeMBygGgYKKwMGAQQB3BkCAaAM" +
|
||||
"DAoxNzYyODk2ODgzMGkGA1UdHwRiMGAwHqAcoBqGGGh0dHA6Ly9xLmljYS5jei9x" +
|
||||
"aWNhLmNybDAeoBygGoYYaHR0cDovL2IuaWNhLmN6L3FpY2EuY3JsMB6gHKAahhho" +
|
||||
"dHRwOi8vci5pY2EuY3ovcWljYS5jcmwwHwYDVR0jBBgwFoAUK1oKfvvlDYUsZTBy" +
|
||||
"vGN701mca/UwHQYDVR0OBBYEFPAs70DB+LS0PnA6niPUfJ5wdQH5MIG4BgNVHSAE" +
|
||||
"gbAwga0wgaoGCysGAQQBs2EBAQQEMIGaMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3" +
|
||||
"LmljYS5jei9xY3AvY3BxcGljYTAyLnBkZjBnBggrBgEFBQcCAjBbGllUZW50byBj" +
|
||||
"ZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28gS3ZhbGlmaWtvdmFueSBjZXJ0aWZpa2F0" +
|
||||
"IHYgc291bGFkdSBzZSB6YWtvbmVtIDIyNy8yMDAwIFNiLjAYBggrBgEFBQcBAwQM" +
|
||||
"MAowCAYGBACORgEBMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQUFAAOCAQEA" +
|
||||
"v2V+nnYYMIgabmmgHx49CtlZIHdGS3TuWKXw130xFhbXDnNhEbx3alaskNsvjQQR" +
|
||||
"Lqs1ZwKy58yynse+eJYHqenmHDACpAfVpCF9PXC/mDarVsoQw7NTcUpsAFhSd/zT" +
|
||||
"v9jIf3twECyxx/RVzONVcob7nPePESHiKoG4FbtcuUh0wSHvCmTwRIQqPDCIuHcF" +
|
||||
"StSt3Jr9iXcbXEhe4mSccOZ8N+r7Rv3ncKcevlRl7uFfDKDTyd43SZeRS/7J8KRf" +
|
||||
"hD/h2nawrCFwc5gJW10aLJGFL/mcS7ViAIT9HCVk23j4TuBjsVmnZ0VKxB5edux+" +
|
||||
"LIEqtU428UVHZWU/I5ngLw==");
|
||||
"WEkuQ0EgLSBRdWFsaWZpZWQgcm9vdCBjZXJ0aWZpY2F0ZSAoa3ZhbGlmaWtvdmFu" +
|
||||
"w70gY2VydGlmaWvDoXQgcG9za3l0b3ZhdGVsZSkgLSBQU0VVRE9OWU0xCzAJBgNV" +
|
||||
"BAYTAkNaMS8wLQYDVQQHDCZQb2R2aW5uw70gbWzDvW4gMjE3OC82LCAxOTAgMDAg" +
|
||||
"UHJhaGEgOTEsMCoGA1UECgwjUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRh" +
|
||||
"IGEucy4xPDA6BgNVBAsMM0FrcmVkaXRvdmFuw70gcG9za3l0b3ZhdGVsIGNlcnRp" +
|
||||
"ZmlrYcSNbsOtY2ggc2x1xb5lYjAeFw0wMjEyMTIxMzMzNDZaFw0wMzEyMTIxMzMz" +
|
||||
"NDZaMIIBFDELMAkGA1UEBhMCQ1oxHzAdBgNVBAMeFgBMAHUAZAEbAGsAIABSAGEB" +
|
||||
"YQBlAGsxGTAXBgNVBAgeEABWAHkAcwBvAQ0AaQBuAGExLzAtBgNVBAceJgBQAGEA" +
|
||||
"YwBvAHYALAAgAE4A4QBkAHIAYQF+AG4A7QAgADcANgA5MSUwIwYJKoZIhvcNAQkB" +
|
||||
"FhZsdWRlay5yYXNla0BjZW50cnVtLmN6MRMwEQYDVQQqHgoATAB1AGQBGwBrMQ0w" +
|
||||
"CwYDVQQrHgQATABSMR8wHQYDVQQpHhYATAB1AGQBGwBrACAAUgBhAWEAZQBrMRMw" +
|
||||
"EQYDVQQEHgoAUgBhAWEAZQBrMRcwFQYDVQQFEw5JQ0EgLSAxMDAwMzc2OTCBnzAN" +
|
||||
"BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxc7dGd0cNlHZ7tUUl5k30bfYlY3lnOD0" +
|
||||
"49JGbTXSt4jNFMRLj6s/777W3kcIdcIwdKxjQULBKgryDvZJ1DAWp2TwzhPDVYj3" +
|
||||
"sU4Niqb7mOUcp/4ckteUxGF6FmXtJR9+XHTuLZ+omF9HOUefheBKnXvZuqrLM16y" +
|
||||
"nbJn4sPwwdcCAwEAAaOCAbswggG3MCUGA1UdEQQeMBygGgYKKwMGAQQB3BkCAaAM" +
|
||||
"DAoxNzYyODk2ODgzMGkGA1UdHwRiMGAwHqAcoBqGGGh0dHA6Ly9xLmljYS5jei9x" +
|
||||
"aWNhLmNybDAeoBygGoYYaHR0cDovL2IuaWNhLmN6L3FpY2EuY3JsMB6gHKAahhho" +
|
||||
"dHRwOi8vci5pY2EuY3ovcWljYS5jcmwwHwYDVR0jBBgwFoAUK1oKfvvlDYUsZTBy" +
|
||||
"vGN701mca/UwHQYDVR0OBBYEFPAs70DB+LS0PnA6niPUfJ5wdQH5MIG4BgNVHSAE" +
|
||||
"gbAwga0wgaoGCysGAQQBs2EBAQQEMIGaMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3" +
|
||||
"LmljYS5jei9xY3AvY3BxcGljYTAyLnBkZjBnBggrBgEFBQcCAjBbGllUZW50byBj" +
|
||||
"ZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28gS3ZhbGlmaWtvdmFueSBjZXJ0aWZpa2F0" +
|
||||
"IHYgc291bGFkdSBzZSB6YWtvbmVtIDIyNy8yMDAwIFNiLjAYBggrBgEFBQcBAwQM" +
|
||||
"MAowCAYGBACORgEBMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQUFAAOCAQEA" +
|
||||
"v2V+nnYYMIgabmmgHx49CtlZIHdGS3TuWKXw130xFhbXDnNhEbx3alaskNsvjQQR" +
|
||||
"Lqs1ZwKy58yynse+eJYHqenmHDACpAfVpCF9PXC/mDarVsoQw7NTcUpsAFhSd/zT" +
|
||||
"v9jIf3twECyxx/RVzONVcob7nPePESHiKoG4FbtcuUh0wSHvCmTwRIQqPDCIuHcF" +
|
||||
"StSt3Jr9iXcbXEhe4mSccOZ8N+r7Rv3ncKcevlRl7uFfDKDTyd43SZeRS/7J8KRf" +
|
||||
"hD/h2nawrCFwc5gJW10aLJGFL/mcS7ViAIT9HCVk23j4TuBjsVmnZ0VKxB5edux+" +
|
||||
"LIEqtU428UVHZWU/I5ngLw=="
|
||||
);
|
||||
|
||||
equal(cert.emailAddress, "ludek.rasek@centrum.cz",
|
||||
"Actual and expected emailAddress should match");
|
||||
equal(cert.subjectName, "serialNumber=ICA - 10003769,SN=Rašek,name=Luděk Rašek,initials=LR,givenName=Luděk,E=ludek.rasek@centrum.cz,L=\"Pacov, Nádražní 769\",ST=Vysočina,CN=Luděk Rašek,C=CZ",
|
||||
"Actual and expected subjectName should match");
|
||||
equal(cert.commonName, "Luděk Rašek",
|
||||
"Actual and expected commonName should match");
|
||||
equal(cert.organization, "",
|
||||
"Actual and expected organization should match");
|
||||
equal(cert.organizationalUnit, "",
|
||||
"Actual and expected organizationalUnit should match");
|
||||
equal(cert.displayName, "Luděk Rašek",
|
||||
"Actual and expected displayName should match");
|
||||
equal(cert.issuerName, "OU=Akreditovaný poskytovatel certifikačních služeb,O=První certifikační autorita a.s.,L=\"Podvinný mlýn 2178/6, 190 00 Praha 9\",C=CZ,CN=I.CA - Qualified root certificate (kvalifikovaný certifikát poskytovatele) - PSEUDONYM",
|
||||
"Actual and expected issuerName should match");
|
||||
equal(cert.issuerCommonName, "I.CA - Qualified root certificate (kvalifikovaný certifikát poskytovatele) - PSEUDONYM",
|
||||
"Actual and expected issuerCommonName should match");
|
||||
equal(cert.issuerOrganization, "První certifikační autorita a.s.",
|
||||
"Actual and expected issuerOrganization should match");
|
||||
equal(cert.issuerOrganizationUnit, "Akreditovaný poskytovatel certifikačních služeb",
|
||||
"Actual and expected issuerOrganizationUnit should match");
|
||||
equal(
|
||||
cert.emailAddress,
|
||||
"ludek.rasek@centrum.cz",
|
||||
"Actual and expected emailAddress should match"
|
||||
);
|
||||
equal(
|
||||
cert.subjectName,
|
||||
'serialNumber=ICA - 10003769,SN=Rašek,name=Luděk Rašek,initials=LR,givenName=Luděk,E=ludek.rasek@centrum.cz,L="Pacov, Nádražní 769",ST=Vysočina,CN=Luděk Rašek,C=CZ',
|
||||
"Actual and expected subjectName should match"
|
||||
);
|
||||
equal(
|
||||
cert.commonName,
|
||||
"Luděk Rašek",
|
||||
"Actual and expected commonName should match"
|
||||
);
|
||||
equal(cert.organization, "", "Actual and expected organization should match");
|
||||
equal(
|
||||
cert.organizationalUnit,
|
||||
"",
|
||||
"Actual and expected organizationalUnit should match"
|
||||
);
|
||||
equal(
|
||||
cert.displayName,
|
||||
"Luděk Rašek",
|
||||
"Actual and expected displayName should match"
|
||||
);
|
||||
equal(
|
||||
cert.issuerName,
|
||||
'OU=Akreditovaný poskytovatel certifikačních služeb,O=První certifikační autorita a.s.,L="Podvinný mlýn 2178/6, 190 00 Praha 9",C=CZ,CN=I.CA - Qualified root certificate (kvalifikovaný certifikát poskytovatele) - PSEUDONYM',
|
||||
"Actual and expected issuerName should match"
|
||||
);
|
||||
equal(
|
||||
cert.issuerCommonName,
|
||||
"I.CA - Qualified root certificate (kvalifikovaný certifikát poskytovatele) - PSEUDONYM",
|
||||
"Actual and expected issuerCommonName should match"
|
||||
);
|
||||
equal(
|
||||
cert.issuerOrganization,
|
||||
"První certifikační autorita a.s.",
|
||||
"Actual and expected issuerOrganization should match"
|
||||
);
|
||||
equal(
|
||||
cert.issuerOrganizationUnit,
|
||||
"Akreditovaný poskytovatel certifikačních služeb",
|
||||
"Actual and expected issuerOrganizationUnit should match"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,24 +10,28 @@
|
|||
|
||||
function startAsyncNSSOperation(certdb, appFile) {
|
||||
return new Promise((resolve, reject) => {
|
||||
certdb.openSignedAppFileAsync(Ci.nsIX509CertDB.AppXPCShellRoot, appFile,
|
||||
certdb.openSignedAppFileAsync(
|
||||
Ci.nsIX509CertDB.AppXPCShellRoot,
|
||||
appFile,
|
||||
function(rv, aZipReader, aSignerCert) {
|
||||
// rv will either indicate success (if NSS hasn't been shut down yet) or
|
||||
// it will be some error code that varies depending on when NSS got shut
|
||||
// down. As such, there's nothing really to check here. Just resolve the
|
||||
// promise to continue execution.
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
do_get_profile();
|
||||
let psm = Cc["@mozilla.org/psm;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.QueryInterface(Ci.nsIObserver);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
.getService(Ci.nsISupports)
|
||||
.QueryInterface(Ci.nsIObserver);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
let appFile = do_get_file("test_signed_apps/app_mf-1_sf-1_p7-1.zip");
|
||||
|
||||
let promises = [];
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function respondWithSHA1OCSP(request, response) {
|
|||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "application/ocsp-response");
|
||||
|
||||
let args = [ ["good-delegated", "default-ee", "delegatedSHA1Signer", 0 ] ];
|
||||
let args = [["good-delegated", "default-ee", "delegatedSHA1Signer", 0]];
|
||||
let responses = generateOCSPResponses(args, "ocsp_certs");
|
||||
response.write(responses[0]);
|
||||
}
|
||||
|
|
@ -37,26 +37,41 @@ function respondWithError(request, response) {
|
|||
}
|
||||
|
||||
function generateGoodOCSPResponse(thisUpdateSkew) {
|
||||
let args = [ ["good", "default-ee", "unused", thisUpdateSkew ] ];
|
||||
let args = [["good", "default-ee", "unused", thisUpdateSkew]];
|
||||
let responses = generateOCSPResponses(args, "ocsp_certs");
|
||||
return responses[0];
|
||||
}
|
||||
|
||||
function add_ocsp_test(aHost, aExpectedResult, aResponses, aMessage,
|
||||
aOriginAttributes) {
|
||||
add_connection_test(aHost, aExpectedResult,
|
||||
function() {
|
||||
clearSessionCache();
|
||||
gFetchCount = 0;
|
||||
gResponsePattern = aResponses;
|
||||
gMessage = aMessage;
|
||||
},
|
||||
function() {
|
||||
// check the number of requests matches the size of aResponses
|
||||
equal(gFetchCount, aResponses.length,
|
||||
"should have made " + aResponses.length +
|
||||
" OCSP request" + (aResponses.length == 1 ? "" : "s"));
|
||||
}, null, aOriginAttributes);
|
||||
function add_ocsp_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
aResponses,
|
||||
aMessage,
|
||||
aOriginAttributes
|
||||
) {
|
||||
add_connection_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
function() {
|
||||
clearSessionCache();
|
||||
gFetchCount = 0;
|
||||
gResponsePattern = aResponses;
|
||||
gMessage = aMessage;
|
||||
},
|
||||
function() {
|
||||
// check the number of requests matches the size of aResponses
|
||||
equal(
|
||||
gFetchCount,
|
||||
aResponses.length,
|
||||
"should have made " +
|
||||
aResponses.length +
|
||||
" OCSP request" +
|
||||
(aResponses.length == 1 ? "" : "s")
|
||||
);
|
||||
},
|
||||
null,
|
||||
aOriginAttributes
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -79,7 +94,9 @@ function run_test() {
|
|||
|
||||
add_tests();
|
||||
|
||||
add_test(function() { ocspResponder.stop(run_next_test); });
|
||||
add_test(function() {
|
||||
ocspResponder.stop(run_next_test);
|
||||
});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
|
|
@ -89,13 +106,19 @@ function add_tests() {
|
|||
// infrastructure, the certificate we encounter is valid for a very long
|
||||
// time, so we have to define a "short lifetime" as something very long.
|
||||
add_test(function() {
|
||||
Services.prefs.setIntPref("security.pki.cert_short_lifetime_in_days",
|
||||
12000);
|
||||
Services.prefs.setIntPref(
|
||||
"security.pki.cert_short_lifetime_in_days",
|
||||
12000
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
|
||||
"expected zero OCSP requests for a short-lived certificate");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[],
|
||||
"expected zero OCSP requests for a short-lived certificate"
|
||||
);
|
||||
|
||||
add_test(function() {
|
||||
Services.prefs.setIntPref("security.pki.cert_short_lifetime_in_days", 100);
|
||||
|
|
@ -105,9 +128,12 @@ function add_tests() {
|
|||
// If a "short lifetime" is something more reasonable, ensure that we do OCSP
|
||||
// fetching for this long-lived certificate.
|
||||
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithError],
|
||||
"expected one OCSP request for a long-lived certificate");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithError],
|
||||
"expected one OCSP request for a long-lived certificate"
|
||||
);
|
||||
add_test(function() {
|
||||
Services.prefs.clearUserPref("security.pki.cert_short_lifetime_in_days");
|
||||
run_next_test();
|
||||
|
|
@ -115,30 +141,38 @@ function add_tests() {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Reset state
|
||||
add_test(function() { clearOCSPCache(); run_next_test(); });
|
||||
add_test(function() {
|
||||
clearOCSPCache();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// This test assumes that OCSPStaplingServer uses the same cert for
|
||||
// ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com.
|
||||
|
||||
// Get an Unknown response for the *.example.com cert and put it in the
|
||||
// OCSP cache.
|
||||
add_ocsp_test("ocsp-stapling-unknown.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT, [],
|
||||
"Stapled Unknown response -> a fetch should not have been" +
|
||||
" attempted");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unknown.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
[],
|
||||
"Stapled Unknown response -> a fetch should not have been" + " attempted"
|
||||
);
|
||||
|
||||
// A failure to retrieve an OCSP response must result in the cached Unknown
|
||||
// response being recognized and honored.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
[
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
],
|
||||
"No stapled response -> a fetch should have been attempted");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
[
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
],
|
||||
"No stapled response -> a fetch should have been attempted"
|
||||
);
|
||||
|
||||
// A valid Good response from the OCSP responder must override the cached
|
||||
// Unknown response.
|
||||
|
|
@ -151,42 +185,57 @@ function add_tests() {
|
|||
gGoodOCSPResponse = generateGoodOCSPResponse(1200);
|
||||
run_next_test();
|
||||
});
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"Cached Unknown response, no stapled response -> a fetch" +
|
||||
" should have been attempted");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"Cached Unknown response, no stapled response -> a fetch" +
|
||||
" should have been attempted"
|
||||
);
|
||||
|
||||
// The Good response retrieved from the previous fetch must have replaced
|
||||
// the Unknown response in the cache, resulting in the catched Good response
|
||||
// being returned and no fetch.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[],
|
||||
"Cached Good response -> a fetch should not have been" +
|
||||
" attempted");
|
||||
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[],
|
||||
"Cached Good response -> a fetch should not have been" + " attempted"
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Reset state
|
||||
add_test(function() { clearOCSPCache(); run_next_test(); });
|
||||
add_test(function() {
|
||||
clearOCSPCache();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// A failure to retrieve an OCSP response will result in an error entry being
|
||||
// added to the cache.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithError],
|
||||
"No stapled response -> a fetch should have been attempted");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithError],
|
||||
"No stapled response -> a fetch should have been attempted"
|
||||
);
|
||||
|
||||
// The error entry will prevent a fetch from happening for a while.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
|
||||
"Noted OCSP server failure -> a fetch should not have been" +
|
||||
" attempted");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[],
|
||||
"Noted OCSP server failure -> a fetch should not have been" + " attempted"
|
||||
);
|
||||
|
||||
// The error entry must not prevent a stapled OCSP response from being
|
||||
// honored.
|
||||
add_ocsp_test("ocsp-stapling-revoked.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE, [],
|
||||
"Stapled Revoked response -> a fetch should not have been" +
|
||||
" attempted");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-revoked.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
[],
|
||||
"Stapled Revoked response -> a fetch should not have been" + " attempted"
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -200,9 +249,12 @@ function add_tests() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithSHA1OCSP],
|
||||
"signing cert is good (though sha1) - should succeed");
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithSHA1OCSP],
|
||||
"signing cert is good (though sha1) - should succeed"
|
||||
);
|
||||
|
||||
add_test(function() {
|
||||
Services.prefs.setBoolPref("security.OCSP.require", false);
|
||||
|
|
@ -212,13 +264,17 @@ function add_tests() {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Reset state
|
||||
add_test(function() { clearOCSPCache(); run_next_test(); });
|
||||
add_test(function() {
|
||||
clearOCSPCache();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// This test makes sure that OCSP cache are isolated by firstPartyDomain.
|
||||
|
||||
let gObservedCnt = 0;
|
||||
let protocolProxyService = Cc["@mozilla.org/network/protocol-proxy-service;1"]
|
||||
.getService(Ci.nsIProtocolProxyService);
|
||||
let protocolProxyService = Cc[
|
||||
"@mozilla.org/network/protocol-proxy-service;1"
|
||||
].getService(Ci.nsIProtocolProxyService);
|
||||
|
||||
// Observe all channels and make sure the firstPartyDomain in their loadInfo's
|
||||
// origin attributes are aFirstPartyDomain.
|
||||
|
|
@ -230,8 +286,11 @@ function add_tests() {
|
|||
// We have the channel; provide it to the callback.
|
||||
if (aChannel.originalURI.spec == "http://localhost:8888/") {
|
||||
gObservedCnt++;
|
||||
equal(aChannel.loadInfo.originAttributes.firstPartyDomain,
|
||||
aFirstPartyDomain, "firstPartyDomain should match");
|
||||
equal(
|
||||
aChannel.loadInfo.originAttributes.firstPartyDomain,
|
||||
aFirstPartyDomain,
|
||||
"firstPartyDomain should match"
|
||||
);
|
||||
}
|
||||
// Pass on aProxy unmodified.
|
||||
aCallback.onProxyFilterResult(aProxy);
|
||||
|
|
@ -249,16 +308,24 @@ function add_tests() {
|
|||
});
|
||||
|
||||
// A good OCSP response will be cached.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"No stapled response (firstPartyDomain = foo.com) -> a fetch " +
|
||||
"should have been attempted", { firstPartyDomain: "foo.com" });
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"No stapled response (firstPartyDomain = foo.com) -> a fetch " +
|
||||
"should have been attempted",
|
||||
{ firstPartyDomain: "foo.com" }
|
||||
);
|
||||
|
||||
// The cache will prevent a fetch from happening.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
|
||||
"Noted OCSP server failure (firstPartyDomain = foo.com) -> a " +
|
||||
"fetch should not have been attempted",
|
||||
{ firstPartyDomain: "foo.com" });
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[],
|
||||
"Noted OCSP server failure (firstPartyDomain = foo.com) -> a " +
|
||||
"fetch should not have been attempted",
|
||||
{ firstPartyDomain: "foo.com" }
|
||||
);
|
||||
|
||||
add_test(function() {
|
||||
stopObservingChannels();
|
||||
|
|
@ -273,10 +340,14 @@ function add_tests() {
|
|||
});
|
||||
|
||||
// But using a different firstPartyDomain should result in a fetch.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"No stapled response (firstPartyDomain = bar.com) -> a fetch " +
|
||||
"should have been attempted", { firstPartyDomain: "bar.com" });
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"No stapled response (firstPartyDomain = bar.com) -> a fetch " +
|
||||
"should have been attempted",
|
||||
{ firstPartyDomain: "bar.com" }
|
||||
);
|
||||
|
||||
add_test(function() {
|
||||
stopObservingChannels();
|
||||
|
|
@ -288,30 +359,48 @@ function add_tests() {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Reset state
|
||||
add_test(function() { clearOCSPCache(); run_next_test(); });
|
||||
add_test(function() {
|
||||
clearOCSPCache();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Test that the OCSP cache is not isolated by userContextId.
|
||||
|
||||
// A good OCSP response will be cached.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"No stapled response (userContextId = 1) -> a fetch " +
|
||||
"should have been attempted", { userContextId: 1 });
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[respondWithGoodOCSP],
|
||||
"No stapled response (userContextId = 1) -> a fetch " +
|
||||
"should have been attempted",
|
||||
{ userContextId: 1 }
|
||||
);
|
||||
|
||||
// The cache will prevent a fetch from happening.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
|
||||
"Noted OCSP server failure (userContextId = 1) -> a " +
|
||||
"fetch should not have been attempted",
|
||||
{ userContextId: 1 });
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[],
|
||||
"Noted OCSP server failure (userContextId = 1) -> a " +
|
||||
"fetch should not have been attempted",
|
||||
{ userContextId: 1 }
|
||||
);
|
||||
|
||||
// Fetching is prevented even if in a different userContextId.
|
||||
add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
|
||||
"Noted OCSP server failure (userContextId = 2) -> a " +
|
||||
"fetch should not have been attempted",
|
||||
{ userContextId: 2 });
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
[],
|
||||
"Noted OCSP server failure (userContextId = 2) -> a " +
|
||||
"fetch should not have been attempted",
|
||||
{ userContextId: 2 }
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Reset state
|
||||
add_test(function() { clearOCSPCache(); run_next_test(); });
|
||||
add_test(function() {
|
||||
clearOCSPCache();
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
// behavior.
|
||||
|
||||
do_get_profile(); // Must be called before getting nsIX509CertDB
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const SERVER_PORT = 8888;
|
||||
|
||||
|
|
@ -25,8 +26,13 @@ function getFailingOCSPResponder() {
|
|||
}
|
||||
|
||||
function getOCSPResponder(expectedCertNames) {
|
||||
return startOCSPResponder(SERVER_PORT, "www.example.com", "test_ev_certs",
|
||||
expectedCertNames, []);
|
||||
return startOCSPResponder(
|
||||
SERVER_PORT,
|
||||
"www.example.com",
|
||||
"test_ev_certs",
|
||||
expectedCertNames,
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
// Tests that in ocspOff mode, OCSP fetches are never done.
|
||||
|
|
@ -37,15 +43,23 @@ async function testOff() {
|
|||
// EV chains should verify successfully but never get EV status.
|
||||
clearOCSPCache();
|
||||
let ocspResponder = getFailingOCSPResponder();
|
||||
await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"),
|
||||
certificateUsageSSLServer, false);
|
||||
await checkEVStatus(
|
||||
gCertDB,
|
||||
certFromFile("test-oid-path-ee"),
|
||||
certificateUsageSSLServer,
|
||||
false
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
|
||||
// A DV chain should verify successfully.
|
||||
clearOCSPCache();
|
||||
ocspResponder = getFailingOCSPResponder();
|
||||
await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
|
||||
PRErrorCodeSuccess, certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
gCertDB,
|
||||
certFromFile("non-ev-root-path-ee"),
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
}
|
||||
|
||||
|
|
@ -57,19 +71,29 @@ async function testOn() {
|
|||
// If a successful OCSP response is fetched, then an EV chain should verify
|
||||
// successfully and get EV status as well.
|
||||
clearOCSPCache();
|
||||
let ocspResponder =
|
||||
getOCSPResponder(gEVExpected ? ["test-oid-path-int", "test-oid-path-ee"]
|
||||
: ["test-oid-path-ee"]);
|
||||
await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"),
|
||||
certificateUsageSSLServer, gEVExpected);
|
||||
let ocspResponder = getOCSPResponder(
|
||||
gEVExpected
|
||||
? ["test-oid-path-int", "test-oid-path-ee"]
|
||||
: ["test-oid-path-ee"]
|
||||
);
|
||||
await checkEVStatus(
|
||||
gCertDB,
|
||||
certFromFile("test-oid-path-ee"),
|
||||
certificateUsageSSLServer,
|
||||
gEVExpected
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
|
||||
// If a successful OCSP response is fetched, then a DV chain should verify
|
||||
// successfully.
|
||||
clearOCSPCache();
|
||||
ocspResponder = getOCSPResponder(["non-ev-root-path-ee"]);
|
||||
await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
|
||||
PRErrorCodeSuccess, certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
gCertDB,
|
||||
certFromFile("non-ev-root-path-ee"),
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
}
|
||||
|
||||
|
|
@ -82,17 +106,25 @@ async function testEVOnly() {
|
|||
// successfully and get EV status as well.
|
||||
clearOCSPCache();
|
||||
let ocspResponder = gEVExpected
|
||||
? getOCSPResponder(["test-oid-path-int", "test-oid-path-ee"])
|
||||
: getFailingOCSPResponder();
|
||||
await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"),
|
||||
certificateUsageSSLServer, gEVExpected);
|
||||
? getOCSPResponder(["test-oid-path-int", "test-oid-path-ee"])
|
||||
: getFailingOCSPResponder();
|
||||
await checkEVStatus(
|
||||
gCertDB,
|
||||
certFromFile("test-oid-path-ee"),
|
||||
certificateUsageSSLServer,
|
||||
gEVExpected
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
|
||||
// A DV chain should verify successfully even without doing OCSP fetches.
|
||||
clearOCSPCache();
|
||||
ocspResponder = getFailingOCSPResponder();
|
||||
await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
|
||||
PRErrorCodeSuccess, certificateUsageSSLServer);
|
||||
await checkCertErrorGeneric(
|
||||
gCertDB,
|
||||
certFromFile("non-ev-root-path-ee"),
|
||||
PRErrorCodeSuccess,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,88 +10,152 @@
|
|||
|
||||
var gExpectOCSPRequest;
|
||||
|
||||
function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled,
|
||||
aExpectOCSPRequest = false) {
|
||||
add_connection_test(aHost, aExpectedResult,
|
||||
function() {
|
||||
gExpectOCSPRequest = aExpectOCSPRequest;
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling",
|
||||
aStaplingEnabled);
|
||||
});
|
||||
function add_ocsp_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
aStaplingEnabled,
|
||||
aExpectOCSPRequest = false
|
||||
) {
|
||||
add_connection_test(aHost, aExpectedResult, function() {
|
||||
gExpectOCSPRequest = aExpectOCSPRequest;
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
Services.prefs.setBoolPref(
|
||||
"security.ssl.enable_ocsp_stapling",
|
||||
aStaplingEnabled
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function add_tests() {
|
||||
// ensure that the chain is checked for required features in children:
|
||||
// First a case where intermediate and ee both have the extension
|
||||
add_ocsp_test("ocsp-stapling-must-staple-ee-with-must-staple-int.example.com",
|
||||
PRErrorCodeSuccess, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-ee-with-must-staple-int.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true
|
||||
);
|
||||
|
||||
add_test(() => {
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
|
||||
Services.prefs.setBoolPref("security.cert_pinning.process_headers_from_non_builtin_roots", true);
|
||||
let uri = Services.io.newURI("https://ocsp-stapling-must-staple-ee-with-must-staple-int.example.com");
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
true
|
||||
);
|
||||
let uri = Services.io.newURI(
|
||||
"https://ocsp-stapling-must-staple-ee-with-must-staple-int.example.com"
|
||||
);
|
||||
let keyHash = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
let backupKeyHash = "KHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN=";
|
||||
let header = `max-age=1000; pin-sha256="${keyHash}"; pin-sha256="${backupKeyHash}"`;
|
||||
let ssservice = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
let ssservice = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
let secInfo = new FakeTransportSecurityInfo();
|
||||
secInfo.serverCert = constructCertFromFile("ocsp_certs/must-staple-ee-with-must-staple-int.pem");
|
||||
ssservice.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri, header, secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
ok(ssservice.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"ocsp-stapling-must-staple-ee-with-must-staple-int.example.com should have HPKP set");
|
||||
secInfo.serverCert = constructCertFromFile(
|
||||
"ocsp_certs/must-staple-ee-with-must-staple-int.pem"
|
||||
);
|
||||
ssservice.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
header,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
ok(
|
||||
ssservice.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"ocsp-stapling-must-staple-ee-with-must-staple-int.example.com should have HPKP set"
|
||||
);
|
||||
|
||||
// Clear accumulated state.
|
||||
ssservice.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
Services.prefs.clearUserPref("security.cert_pinning.process_headers_from_non_builtin_roots");
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
);
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Next, a case where it's present in the intermediate, not the ee
|
||||
add_ocsp_test("ocsp-stapling-plain-ee-with-must-staple-int.example.com",
|
||||
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-plain-ee-with-must-staple-int.example.com",
|
||||
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
true
|
||||
);
|
||||
|
||||
// We disable OCSP stapling in the next two tests so we can perform checks
|
||||
// on TLS Features in the chain without needing to support the TLS
|
||||
// extension values used.
|
||||
// Test an issuer with multiple TLS features in matched in the EE
|
||||
add_ocsp_test("multi-tls-feature-good.example.com",
|
||||
PRErrorCodeSuccess, false);
|
||||
add_ocsp_test(
|
||||
"multi-tls-feature-good.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false
|
||||
);
|
||||
|
||||
// Finally, an issuer with multiple TLS features not matched by the EE.
|
||||
add_ocsp_test("multi-tls-feature-bad.example.com",
|
||||
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING, false);
|
||||
add_ocsp_test(
|
||||
"multi-tls-feature-bad.example.com",
|
||||
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
false
|
||||
);
|
||||
|
||||
// Now a bunch of operations with only a must-staple ee
|
||||
add_ocsp_test("ocsp-stapling-must-staple.example.com",
|
||||
PRErrorCodeSuccess, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-must-staple-revoked.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-revoked.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-must-staple-missing.example.com",
|
||||
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-missing.example.com",
|
||||
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-must-staple-empty.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-empty.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-must-staple-missing.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-missing.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
// If the stapled response is expired, we will try to fetch a new one.
|
||||
// If that fails, we should report the original error.
|
||||
add_ocsp_test("ocsp-stapling-must-staple-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
true,
|
||||
true
|
||||
);
|
||||
// Similarly with a "try server later" response.
|
||||
add_ocsp_test("ocsp-stapling-must-staple-try-later.example.com",
|
||||
SEC_ERROR_OCSP_TRY_SERVER_LATER, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-try-later.example.com",
|
||||
SEC_ERROR_OCSP_TRY_SERVER_LATER,
|
||||
true,
|
||||
true
|
||||
);
|
||||
// And again with an invalid OCSP response signing certificate.
|
||||
add_ocsp_test("ocsp-stapling-must-staple-invalid-signer.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-invalid-signer.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
// check that disabling must-staple works
|
||||
add_test(function() {
|
||||
|
|
@ -100,8 +164,12 @@ function add_tests() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
add_ocsp_test("ocsp-stapling-must-staple-missing.example.com",
|
||||
PRErrorCodeSuccess, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-missing.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -114,10 +182,12 @@ function run_test() {
|
|||
Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000);
|
||||
|
||||
let fakeOCSPResponder = new HttpServer();
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
|
||||
ok(gExpectOCSPRequest,
|
||||
"Should be getting an OCSP request only when expected");
|
||||
ok(
|
||||
gExpectOCSPRequest,
|
||||
"Should be getting an OCSP request only when expected"
|
||||
);
|
||||
});
|
||||
fakeOCSPResponder.start(8888);
|
||||
|
||||
|
|
@ -125,7 +195,7 @@ function run_test() {
|
|||
|
||||
add_tests();
|
||||
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
fakeOCSPResponder.stop(run_next_test);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ function run_test() {
|
|||
let goodOCSPResponse = ocspResponses[0];
|
||||
|
||||
let ocspResponder = new HttpServer();
|
||||
ocspResponder.registerPrefixHandler("/", function (request, response) {
|
||||
ocspResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "application/ocsp-response");
|
||||
response.write(goodOCSPResponse);
|
||||
|
|
@ -35,20 +35,32 @@ function run_test() {
|
|||
// upgrade the OCSP request to HTTPS. We specifically prevent this. This
|
||||
// test demonstrates that our implementation is correct in this regard.
|
||||
add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess);
|
||||
add_test(function () { run_next_test(); });
|
||||
add_test(function() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function () { ocspResponder.stop(run_next_test); });
|
||||
add_test(function() {
|
||||
ocspResponder.stop(run_next_test);
|
||||
});
|
||||
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
let uri = Services.io.newURI("http://localhost");
|
||||
let secInfo = new FakeTransportSecurityInfo();
|
||||
SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
|
||||
"max-age=10000", secInfo, 0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST);
|
||||
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"Domain for the OCSP AIA URI should be considered a HSTS host, otherwise" +
|
||||
" we wouldn't be testing what we think we're testing");
|
||||
SSService.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
uri,
|
||||
"max-age=10000",
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
ok(
|
||||
SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
|
||||
"Domain for the OCSP AIA URI should be considered a HSTS host, otherwise" +
|
||||
" we wouldn't be testing what we think we're testing"
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,16 +11,25 @@
|
|||
// was in a private context.
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const SERVER_PORT = 8888;
|
||||
|
||||
function start_ocsp_responder(expectedCertNames, expectedPaths,
|
||||
expectedMethods) {
|
||||
return startOCSPResponder(SERVER_PORT, "www.example.com",
|
||||
"test_ocsp_fetch_method", expectedCertNames,
|
||||
expectedPaths, expectedMethods);
|
||||
function start_ocsp_responder(
|
||||
expectedCertNames,
|
||||
expectedPaths,
|
||||
expectedMethods
|
||||
) {
|
||||
return startOCSPResponder(
|
||||
SERVER_PORT,
|
||||
"www.example.com",
|
||||
"test_ocsp_fetch_method",
|
||||
expectedCertNames,
|
||||
expectedPaths,
|
||||
expectedMethods
|
||||
);
|
||||
}
|
||||
|
||||
function add_flush_cache() {
|
||||
|
|
@ -29,7 +38,8 @@ function add_flush_cache() {
|
|||
// observer that has ever been passed to flush. To prevent multiple calls to
|
||||
// run_next_test, keep track of if this observer has already called it.
|
||||
let observed = false;
|
||||
let observer = { observe: () => {
|
||||
let observer = {
|
||||
observe: () => {
|
||||
if (!observed) {
|
||||
observed = true;
|
||||
run_next_test();
|
||||
|
|
@ -52,15 +62,28 @@ function add_ocsp_necko_cache_test(loadContext, shouldFindEntry) {
|
|||
add_test(() => {
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
responder = startOCSPResponder(SERVER_PORT, "localhost", "ocsp_certs",
|
||||
["default-ee"], [], [], [],
|
||||
[["Cache-Control", "max-age: 1000"]]);
|
||||
responder = startOCSPResponder(
|
||||
SERVER_PORT,
|
||||
"localhost",
|
||||
"ocsp_certs",
|
||||
["default-ee"],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[["Cache-Control", "max-age: 1000"]]
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Prepare a connection that will cause an OCSP request.
|
||||
add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
null, null, null, loadContext.originAttributes);
|
||||
add_connection_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
loadContext.originAttributes
|
||||
);
|
||||
|
||||
add_flush_cache();
|
||||
|
||||
|
|
@ -70,15 +93,29 @@ function add_ocsp_necko_cache_test(loadContext, shouldFindEntry) {
|
|||
let foundEntry = false;
|
||||
let visitor = {
|
||||
onCacheStorageInfo() {},
|
||||
onCacheEntryInfo(aURI, aIdEnhance, aDataSize, aFetchCount,
|
||||
aLastModifiedTime, aExpirationTime, aPinned, aInfo) {
|
||||
Assert.equal(aURI.spec, "http://localhost:8888/",
|
||||
"expected OCSP request URI should match");
|
||||
onCacheEntryInfo(
|
||||
aURI,
|
||||
aIdEnhance,
|
||||
aDataSize,
|
||||
aFetchCount,
|
||||
aLastModifiedTime,
|
||||
aExpirationTime,
|
||||
aPinned,
|
||||
aInfo
|
||||
) {
|
||||
Assert.equal(
|
||||
aURI.spec,
|
||||
"http://localhost:8888/",
|
||||
"expected OCSP request URI should match"
|
||||
);
|
||||
foundEntry = true;
|
||||
},
|
||||
onCacheEntryVisitCompleted() {
|
||||
Assert.equal(foundEntry, shouldFindEntry,
|
||||
"should only find a cached entry if we're expecting one");
|
||||
Assert.equal(
|
||||
foundEntry,
|
||||
shouldFindEntry,
|
||||
"should only find a cached entry if we're expecting one"
|
||||
);
|
||||
run_next_test();
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI(["nsICacheStorageVisitor"]),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function run_test() {
|
|||
gOCSPResponse = ocspResponses[0];
|
||||
|
||||
let ocspResponder = new HttpServer();
|
||||
ocspResponder.registerPrefixHandler("/", function (request, response) {
|
||||
ocspResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "application/ocsp-response");
|
||||
response.write(gOCSPResponse);
|
||||
|
|
@ -38,19 +38,28 @@ function run_test() {
|
|||
|
||||
add_tests();
|
||||
|
||||
add_test(function () { ocspResponder.stop(run_next_test); });
|
||||
add_test(function() {
|
||||
ocspResponder.stop(run_next_test);
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function add_tests() {
|
||||
add_connection_test("ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_BAD_SIGNATURE);
|
||||
add_connection_test("ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_BAD_SIGNATURE);
|
||||
add_test(function () {
|
||||
equal(gOCSPRequestCount, 1,
|
||||
"OCSP request count should be 1 due to OCSP response caching");
|
||||
add_connection_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_BAD_SIGNATURE
|
||||
);
|
||||
add_connection_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_BAD_SIGNATURE
|
||||
);
|
||||
add_test(function() {
|
||||
equal(
|
||||
gOCSPRequestCount,
|
||||
1,
|
||||
"OCSP request count should be 1 due to OCSP response caching"
|
||||
);
|
||||
gOCSPRequestCount = 0;
|
||||
// Now set the OCSP responder to reply with 200 OK but empty content.
|
||||
gOCSPResponse = "";
|
||||
|
|
@ -58,6 +67,8 @@ function add_tests() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
add_connection_test("ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE);
|
||||
add_connection_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,109 +10,224 @@
|
|||
|
||||
var gExpectOCSPRequest;
|
||||
|
||||
function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled,
|
||||
aExpectOCSPRequest = false) {
|
||||
add_connection_test(aHost, aExpectedResult,
|
||||
function() {
|
||||
gExpectOCSPRequest = aExpectOCSPRequest;
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling",
|
||||
aStaplingEnabled);
|
||||
});
|
||||
function add_ocsp_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
aStaplingEnabled,
|
||||
aExpectOCSPRequest = false
|
||||
) {
|
||||
add_connection_test(aHost, aExpectedResult, function() {
|
||||
gExpectOCSPRequest = aExpectOCSPRequest;
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
Services.prefs.setBoolPref(
|
||||
"security.ssl.enable_ocsp_stapling",
|
||||
aStaplingEnabled
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function add_tests() {
|
||||
// In the absence of OCSP stapling, these should actually all work.
|
||||
add_ocsp_test("ocsp-stapling-good.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-revoked.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-good-other-ca.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-malformed.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-srverr.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-trylater.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-needssig.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-unauthorized.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-unknown.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-good-other.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-critical-extension.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-noncritical-extension.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test("ocsp-stapling-empty-extensions.example.com",
|
||||
PRErrorCodeSuccess, false, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-good.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-revoked.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-good-other-ca.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-malformed.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-srverr.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-trylater.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-needssig.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unauthorized.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unknown.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-good-other.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired-fresh-ca.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-skip-responseBytes.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-critical-extension.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-noncritical-extension.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-empty-extensions.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
// Now test OCSP stapling
|
||||
// The following error codes are defined in security/nss/lib/util/SECerrs.h
|
||||
|
||||
add_ocsp_test("ocsp-stapling-good.example.com", PRErrorCodeSuccess, true);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-revoked.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-revoked.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
true
|
||||
);
|
||||
|
||||
// This stapled response is from a CA that is untrusted and did not issue
|
||||
// the server's certificate.
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
let otherTestCA = constructCertFromFile("ocsp_certs/other-test-ca.pem");
|
||||
add_test(function() {
|
||||
certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.UNTRUSTED);
|
||||
certDB.setCertTrust(
|
||||
otherTestCA,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.UNTRUSTED
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
add_ocsp_test("ocsp-stapling-good-other-ca.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-good-other-ca.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
// The stapled response is from a CA that is trusted but did not issue the
|
||||
// server's certificate.
|
||||
add_test(function() {
|
||||
certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL);
|
||||
certDB.setCertTrust(
|
||||
otherTestCA,
|
||||
Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.TRUSTED_SSL
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
// TODO(bug 979055): When using ByName instead of ByKey, the error here is
|
||||
// SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE. We should be testing both cases.
|
||||
add_ocsp_test("ocsp-stapling-good-other-ca.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-good-other-ca.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
// TODO: Test the case where the signing cert can't be found at all, which
|
||||
// will result in SEC_ERROR_BAD_DATABASE in the NSS classic case.
|
||||
|
||||
add_ocsp_test("ocsp-stapling-malformed.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_REQUEST, true);
|
||||
add_ocsp_test("ocsp-stapling-srverr.example.com",
|
||||
SEC_ERROR_OCSP_SERVER_ERROR, true);
|
||||
add_ocsp_test("ocsp-stapling-trylater.example.com",
|
||||
SEC_ERROR_OCSP_TRY_SERVER_LATER, true, true);
|
||||
add_ocsp_test("ocsp-stapling-needssig.example.com",
|
||||
SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, true);
|
||||
add_ocsp_test("ocsp-stapling-unauthorized.example.com",
|
||||
SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, true);
|
||||
add_ocsp_test("ocsp-stapling-unknown.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT, true);
|
||||
add_ocsp_test("ocsp-stapling-good-other.example.com",
|
||||
MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-malformed.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_REQUEST,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-srverr.example.com",
|
||||
SEC_ERROR_OCSP_SERVER_ERROR,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-trylater.example.com",
|
||||
SEC_ERROR_OCSP_TRY_SERVER_LATER,
|
||||
true,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-needssig.example.com",
|
||||
SEC_ERROR_OCSP_REQUEST_NEEDS_SIG,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unauthorized.example.com",
|
||||
SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unknown.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-good-other.example.com",
|
||||
MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING,
|
||||
true
|
||||
);
|
||||
// If the server doesn't staple an OCSP response, we continue as normal
|
||||
// (this means that even though stapling is enabled, we expect an OCSP
|
||||
// request).
|
||||
add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
|
||||
add_connection_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
function() {
|
||||
gExpectOCSPRequest = true;
|
||||
clearOCSPCache();
|
||||
|
|
@ -120,36 +235,81 @@ function add_tests() {
|
|||
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
|
||||
}
|
||||
);
|
||||
add_ocsp_test("ocsp-stapling-empty.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-empty.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-skip-responseBytes.example.com",
|
||||
SEC_ERROR_OCSP_MALFORMED_RESPONSE,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-critical-extension.example.com",
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, true);
|
||||
add_ocsp_test("ocsp-stapling-noncritical-extension.example.com",
|
||||
PRErrorCodeSuccess, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-critical-extension.example.com",
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-noncritical-extension.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true
|
||||
);
|
||||
// TODO(bug 997994): Disallow empty Extensions in responses
|
||||
add_ocsp_test("ocsp-stapling-empty-extensions.example.com",
|
||||
PRErrorCodeSuccess, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-empty-extensions.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("ocsp-stapling-delegated-included.example.com",
|
||||
PRErrorCodeSuccess, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-included-last.example.com",
|
||||
PRErrorCodeSuccess, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-missing.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-missing-multiple.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-no-extKeyUsage.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-from-intermediate.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-keyUsage-crlSigning.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test("ocsp-stapling-delegated-wrong-extKeyUsage.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-included.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-included-last.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-missing.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-missing-multiple.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-no-extKeyUsage.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-from-intermediate.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-keyUsage-crlSigning.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-delegated-wrong-extKeyUsage.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
// ocsp-stapling-expired.example.com and
|
||||
// ocsp-stapling-expired-fresh-ca.example.com are handled in
|
||||
|
|
@ -157,27 +317,49 @@ function add_tests() {
|
|||
|
||||
// Check that OCSP responder certificates with key sizes below 1024 bits are
|
||||
// rejected, even when the main certificate chain keys are at least 1024 bits.
|
||||
add_ocsp_test("keysize-ocsp-delegated.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true, true);
|
||||
add_ocsp_test(
|
||||
"keysize-ocsp-delegated.example.com",
|
||||
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
add_ocsp_test("revoked-ca-cert-used-as-end-entity.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE, true);
|
||||
add_ocsp_test(
|
||||
"revoked-ca-cert-used-as-end-entity.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function check_ocsp_stapling_telemetry() {
|
||||
let histogram = Services.telemetry
|
||||
.getHistogramById("SSL_OCSP_STAPLING")
|
||||
.snapshot();
|
||||
equal(histogram.values[0], 0,
|
||||
"Should have 0 connections for unused histogram bucket 0");
|
||||
equal(histogram.values[1], 5,
|
||||
"Actual and expected connections with a good response should match");
|
||||
equal(histogram.values[2], 18,
|
||||
"Actual and expected connections with no stapled response should match");
|
||||
equal(histogram.values[3] || 0, 0,
|
||||
"Actual and expected connections with an expired response should match");
|
||||
equal(histogram.values[4], 21,
|
||||
"Actual and expected connections with bad responses should match");
|
||||
.getHistogramById("SSL_OCSP_STAPLING")
|
||||
.snapshot();
|
||||
equal(
|
||||
histogram.values[0],
|
||||
0,
|
||||
"Should have 0 connections for unused histogram bucket 0"
|
||||
);
|
||||
equal(
|
||||
histogram.values[1],
|
||||
5,
|
||||
"Actual and expected connections with a good response should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[2],
|
||||
18,
|
||||
"Actual and expected connections with no stapled response should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[3] || 0,
|
||||
0,
|
||||
"Actual and expected connections with an expired response should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[4],
|
||||
21,
|
||||
"Actual and expected connections with bad responses should match"
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
|
|
@ -190,10 +372,12 @@ function run_test() {
|
|||
Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000);
|
||||
|
||||
let fakeOCSPResponder = new HttpServer();
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
|
||||
ok(gExpectOCSPRequest,
|
||||
"Should be getting an OCSP request only when expected");
|
||||
ok(
|
||||
gExpectOCSPRequest,
|
||||
"Should be getting an OCSP request only when expected"
|
||||
);
|
||||
});
|
||||
fakeOCSPResponder.start(8888);
|
||||
|
||||
|
|
@ -201,7 +385,7 @@ function run_test() {
|
|||
|
||||
add_tests();
|
||||
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
fakeOCSPResponder.stop(check_ocsp_stapling_telemetry);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,18 @@
|
|||
// this to "try later" responses and responses where the signing certificate
|
||||
// doesn't verify successfully.
|
||||
|
||||
|
||||
var gCurrentOCSPResponse = null;
|
||||
var gOCSPRequestCount = 0;
|
||||
|
||||
function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe,
|
||||
aExpectedRequestCount) {
|
||||
add_connection_test(aHost, aExpectedResult,
|
||||
function add_ocsp_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
aOCSPResponseToServe,
|
||||
aExpectedRequestCount
|
||||
) {
|
||||
add_connection_test(
|
||||
aHost,
|
||||
aExpectedResult,
|
||||
function() {
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
|
|
@ -30,10 +35,16 @@ function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe,
|
|||
gOCSPRequestCount = 0;
|
||||
},
|
||||
function() {
|
||||
equal(gOCSPRequestCount, aExpectedRequestCount,
|
||||
"Should have made " + aExpectedRequestCount +
|
||||
" fallback OCSP request" + (aExpectedRequestCount == 1 ? "" : "s"));
|
||||
});
|
||||
equal(
|
||||
gOCSPRequestCount,
|
||||
aExpectedRequestCount,
|
||||
"Should have made " +
|
||||
aExpectedRequestCount +
|
||||
" fallback OCSP request" +
|
||||
(aExpectedRequestCount == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
do_get_profile();
|
||||
|
|
@ -44,13 +55,14 @@ Services.prefs.setIntPref("security.OCSP.enabled", 1);
|
|||
// bump the timeout and hopefully avoid these failures.
|
||||
Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000);
|
||||
Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
|
||||
var args = [["good", "default-ee", "unused", 0],
|
||||
["expiredresponse", "default-ee", "unused", 0],
|
||||
["oldvalidperiod", "default-ee", "unused", 0],
|
||||
["revoked", "default-ee", "unused", 0],
|
||||
["unknown", "default-ee", "unused", 0],
|
||||
["good", "must-staple-ee", "unused", 0],
|
||||
];
|
||||
var args = [
|
||||
["good", "default-ee", "unused", 0],
|
||||
["expiredresponse", "default-ee", "unused", 0],
|
||||
["oldvalidperiod", "default-ee", "unused", 0],
|
||||
["revoked", "default-ee", "unused", 0],
|
||||
["unknown", "default-ee", "unused", 0],
|
||||
["good", "must-staple-ee", "unused", 0],
|
||||
];
|
||||
var ocspResponses = generateOCSPResponses(args, "ocsp_certs");
|
||||
// Fresh response, certificate is good.
|
||||
var ocspResponseGood = ocspResponses[0];
|
||||
|
|
@ -97,82 +109,150 @@ function run_test() {
|
|||
// For ocsp-stapling-expired-fresh-ca.example.com, the OCSP stapling
|
||||
// server staples an OCSP response with a recent signature but with an
|
||||
// out-of-date validity period. The certificate has not expired.
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com", PRErrorCodeSuccess,
|
||||
ocspResponseGood, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", PRErrorCodeSuccess,
|
||||
ocspResponseGood, willNotRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGood,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired-fresh-ca.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGood,
|
||||
willNotRetry
|
||||
);
|
||||
// if we can't fetch a more recent response when
|
||||
// given an expired stapled response, we terminate the connection.
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
expiredOCSPResponseGood, willRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
expiredOCSPResponseGood, willRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
oldValidityPeriodOCSPResponseGood, willRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
oldValidityPeriodOCSPResponseGood, willRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
null, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
null, willNotRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
expiredOCSPResponseGood,
|
||||
willRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
expiredOCSPResponseGood,
|
||||
willRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
oldValidityPeriodOCSPResponseGood,
|
||||
willRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
oldValidityPeriodOCSPResponseGood,
|
||||
willRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
null,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_OLD_RESPONSE,
|
||||
null,
|
||||
willNotRetry
|
||||
);
|
||||
// Of course, if the newer response indicates Revoked or Unknown,
|
||||
// that status must be returned.
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
ocspResponseRevoked, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
ocspResponseRevoked, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
ocspResponseUnknown, willRetry);
|
||||
add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
ocspResponseUnknown, willRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
ocspResponseRevoked,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
ocspResponseRevoked,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
ocspResponseUnknown,
|
||||
willRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-expired-fresh-ca.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
ocspResponseUnknown,
|
||||
willRetry
|
||||
);
|
||||
|
||||
// If the response is expired but indicates Revoked or Unknown and a
|
||||
// newer status can't be fetched, the Revoked or Unknown status will
|
||||
// be returned.
|
||||
add_ocsp_test("ocsp-stapling-revoked-old.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
null, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-unknown-old.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
null, willNotRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-revoked-old.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
null,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unknown-old.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
null,
|
||||
willNotRetry
|
||||
);
|
||||
// If the response is expired but indicates Revoked or Unknown and
|
||||
// a newer status can be fetched and successfully verified, this
|
||||
// should result in a successful certificate verification.
|
||||
add_ocsp_test("ocsp-stapling-revoked-old.example.com", PRErrorCodeSuccess,
|
||||
ocspResponseGood, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-unknown-old.example.com", PRErrorCodeSuccess,
|
||||
ocspResponseGood, willNotRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-revoked-old.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGood,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unknown-old.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGood,
|
||||
willNotRetry
|
||||
);
|
||||
// If a newer status can be fetched but it fails to verify, the
|
||||
// Revoked or Unknown status of the expired stapled response
|
||||
// should be returned.
|
||||
add_ocsp_test("ocsp-stapling-revoked-old.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
expiredOCSPResponseGood, willRetry);
|
||||
add_ocsp_test("ocsp-stapling-unknown-old.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
expiredOCSPResponseGood, willRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-revoked-old.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
expiredOCSPResponseGood,
|
||||
willRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-unknown-old.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
expiredOCSPResponseGood,
|
||||
willRetry
|
||||
);
|
||||
|
||||
// These tests are verifying that an valid but very old response
|
||||
// is rejected as a valid stapled response, requiring a fetch
|
||||
// from the ocsp responder.
|
||||
add_ocsp_test("ocsp-stapling-ancient-valid.example.com", PRErrorCodeSuccess,
|
||||
ocspResponseGood, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
ocspResponseRevoked, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
ocspResponseUnknown, willRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-ancient-valid.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGood,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-ancient-valid.example.com",
|
||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
||||
ocspResponseRevoked,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-ancient-valid.example.com",
|
||||
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
||||
ocspResponseUnknown,
|
||||
willRetry
|
||||
);
|
||||
|
||||
// Test how OCSP-must-staple (i.e. TLS feature) interacts with stapled OCSP
|
||||
// responses that don't successfully verify.
|
||||
|
|
@ -180,31 +260,60 @@ function run_test() {
|
|||
// should all fail because a satisfactory stapled OCSP response is not
|
||||
// present, but for compatibility reasons we fall back to active OCSP fetching
|
||||
// in these situations. If the fetch succeeds, then connection succeeds.
|
||||
add_ocsp_test("ocsp-stapling-must-staple-expired.example.com",
|
||||
PRErrorCodeSuccess, ocspResponseGoodMustStaple, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-must-staple-try-later.example.com",
|
||||
PRErrorCodeSuccess, ocspResponseGoodMustStaple, willNotRetry);
|
||||
add_ocsp_test("ocsp-stapling-must-staple-invalid-signer.example.com",
|
||||
PRErrorCodeSuccess, ocspResponseGoodMustStaple, willNotRetry);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-expired.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGoodMustStaple,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-try-later.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGoodMustStaple,
|
||||
willNotRetry
|
||||
);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-must-staple-invalid-signer.example.com",
|
||||
PRErrorCodeSuccess,
|
||||
ocspResponseGoodMustStaple,
|
||||
willNotRetry
|
||||
);
|
||||
|
||||
add_test(function () { ocspResponder.stop(run_next_test); });
|
||||
add_test(function() {
|
||||
ocspResponder.stop(run_next_test);
|
||||
});
|
||||
add_test(check_ocsp_stapling_telemetry);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function check_ocsp_stapling_telemetry() {
|
||||
let histogram = Services.telemetry
|
||||
.getHistogramById("SSL_OCSP_STAPLING")
|
||||
.snapshot();
|
||||
equal(histogram.values[0] || 0, 0,
|
||||
"Should have 0 connections for unused histogram bucket 0");
|
||||
equal(histogram.values[1] || 0, 0,
|
||||
"Actual and expected connections with a good response should match");
|
||||
equal(histogram.values[2] || 0, 0,
|
||||
"Actual and expected connections with no stapled response should match");
|
||||
equal(histogram.values[3], 22,
|
||||
"Actual and expected connections with an expired response should match");
|
||||
equal(histogram.values[4], 2,
|
||||
"Actual and expected connections with bad responses should match");
|
||||
.getHistogramById("SSL_OCSP_STAPLING")
|
||||
.snapshot();
|
||||
equal(
|
||||
histogram.values[0] || 0,
|
||||
0,
|
||||
"Should have 0 connections for unused histogram bucket 0"
|
||||
);
|
||||
equal(
|
||||
histogram.values[1] || 0,
|
||||
0,
|
||||
"Actual and expected connections with a good response should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[2] || 0,
|
||||
0,
|
||||
"Actual and expected connections with no stapled response should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[3],
|
||||
22,
|
||||
"Actual and expected connections with an expired response should match"
|
||||
);
|
||||
equal(
|
||||
histogram.values[4],
|
||||
2,
|
||||
"Actual and expected connections with bad responses should match"
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,10 @@
|
|||
var gOCSPRequestCount = 0;
|
||||
|
||||
function add_ocsp_test(aHost, aExpectedResult) {
|
||||
add_connection_test(aHost, aExpectedResult,
|
||||
function() {
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
});
|
||||
add_connection_test(aHost, aExpectedResult, function() {
|
||||
clearOCSPCache();
|
||||
clearSessionCache();
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
@ -33,10 +32,14 @@ function run_test() {
|
|||
|
||||
add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
|
||||
|
||||
add_ocsp_test("ocsp-stapling-with-intermediate.example.com",
|
||||
PRErrorCodeSuccess);
|
||||
add_ocsp_test(
|
||||
"ocsp-stapling-with-intermediate.example.com",
|
||||
PRErrorCodeSuccess
|
||||
);
|
||||
|
||||
add_test(function () { ocspResponder.stop(run_next_test); });
|
||||
add_test(function() {
|
||||
ocspResponder.stop(run_next_test);
|
||||
});
|
||||
add_test(function() {
|
||||
equal(gOCSPRequestCount, 0, "No OCSP requests should have been made");
|
||||
run_next_test();
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ function run_test() {
|
|||
|
||||
add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
|
||||
|
||||
let socket = Cc["@mozilla.org/network/server-socket;1"]
|
||||
.createInstance(Ci.nsIServerSocket);
|
||||
let socket = Cc["@mozilla.org/network/server-socket;1"].createInstance(
|
||||
Ci.nsIServerSocket
|
||||
);
|
||||
socket.init(8888, true, -1);
|
||||
socket.asyncListen(gSocketListener);
|
||||
|
||||
|
|
@ -43,22 +44,27 @@ function run_test() {
|
|||
add_one_test(true, "security.OCSP.timeoutMilliseconds.hard", 10000);
|
||||
add_one_test(true, "security.OCSP.timeoutMilliseconds.hard", 15000);
|
||||
|
||||
add_test(function() { socket.close(); run_next_test(); });
|
||||
add_test(function() {
|
||||
socket.close();
|
||||
run_next_test();
|
||||
});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function add_one_test(useHardFail, timeoutPrefName, timeoutMilliseconds) {
|
||||
let startTime;
|
||||
add_test(function () {
|
||||
add_test(function() {
|
||||
Services.prefs.setBoolPref("security.OCSP.require", useHardFail);
|
||||
Services.prefs.setIntPref(timeoutPrefName, timeoutMilliseconds);
|
||||
startTime = new Date();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_connection_test("ocsp-stapling-none.example.com", useHardFail
|
||||
? SEC_ERROR_OCSP_SERVER_ERROR
|
||||
: PRErrorCodeSuccess, clearSessionCache);
|
||||
add_connection_test(
|
||||
"ocsp-stapling-none.example.com",
|
||||
useHardFail ? SEC_ERROR_OCSP_SERVER_ERROR : PRErrorCodeSuccess,
|
||||
clearSessionCache
|
||||
);
|
||||
|
||||
add_test(function() {
|
||||
let endTime = new Date();
|
||||
|
|
@ -71,15 +77,19 @@ function add_one_test(useHardFail, timeoutPrefName, timeoutMilliseconds) {
|
|||
// prevent intermittent failures (this only appeared to be a problem on
|
||||
// Windows XP). See Bug 1121117.
|
||||
const FUZZ_MS = 300;
|
||||
ok(timeDifference + FUZZ_MS > timeoutMilliseconds,
|
||||
`OCSP timeout should be ~${timeoutMilliseconds}s for ` +
|
||||
`${useHardFail ? "hard" : "soft"}-fail`);
|
||||
ok(
|
||||
timeDifference + FUZZ_MS > timeoutMilliseconds,
|
||||
`OCSP timeout should be ~${timeoutMilliseconds}s for ` +
|
||||
`${useHardFail ? "hard" : "soft"}-fail`
|
||||
);
|
||||
// Make sure we didn't wait too long.
|
||||
// (Unfortunately, we probably can't have a tight upper bound on
|
||||
// how long is too long for this test, because we might be running
|
||||
// on slow hardware.)
|
||||
ok(timeDifference < 60000,
|
||||
"Automatic OCSP timeout shouldn't be more than 60s");
|
||||
ok(
|
||||
timeDifference < 60000,
|
||||
"Automatic OCSP timeout shouldn't be more than 60s"
|
||||
);
|
||||
|
||||
// Reset state
|
||||
clearOCSPCache();
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@
|
|||
// the caller.
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
|
||||
const SERVER_PORT = 8888;
|
||||
|
||||
|
|
@ -20,14 +21,23 @@ function failingOCSPResponder() {
|
|||
}
|
||||
|
||||
function start_ocsp_responder(expectedCertNames, expectedPaths) {
|
||||
return startOCSPResponder(SERVER_PORT, "www.example.com",
|
||||
"test_ocsp_url", expectedCertNames, expectedPaths);
|
||||
return startOCSPResponder(
|
||||
SERVER_PORT,
|
||||
"www.example.com",
|
||||
"test_ocsp_url",
|
||||
expectedCertNames,
|
||||
expectedPaths
|
||||
);
|
||||
}
|
||||
|
||||
function check_cert_err(cert_name, expected_error) {
|
||||
let cert = constructCertFromFile("test_ocsp_url/" + cert_name + ".pem");
|
||||
return checkCertErrorGeneric(certdb, cert, expected_error,
|
||||
certificateUsageSSLServer);
|
||||
return checkCertErrorGeneric(
|
||||
certdb,
|
||||
cert,
|
||||
expected_error,
|
||||
certificateUsageSSLServer
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
@ -37,8 +47,7 @@ add_task(async function() {
|
|||
// Enabled so that we can force ocsp failure responses.
|
||||
Services.prefs.setBoolPref("security.OCSP.require", true);
|
||||
|
||||
Services.prefs.setCharPref("network.dns.localDomains",
|
||||
"www.example.com");
|
||||
Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
|
||||
Services.prefs.setIntPref("security.OCSP.enabled", 1);
|
||||
|
||||
// Note: We don't test the case of a well-formed HTTP URL with an empty port
|
||||
|
|
@ -87,7 +96,10 @@ add_task(async function() {
|
|||
|
||||
clearOCSPCache();
|
||||
ocspResponder = failingOCSPResponder();
|
||||
await check_cert_err("no-scheme-host-port", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
|
||||
await check_cert_err(
|
||||
"no-scheme-host-port",
|
||||
SEC_ERROR_CERT_BAD_ACCESS_LOCATION
|
||||
);
|
||||
await stopOCSPResponder(ocspResponder);
|
||||
|
||||
clearOCSPCache();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue