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:
Victor Porof 2019-07-05 10:57:28 +02:00
parent 77c95c13f4
commit 858f3b554b
148 changed files with 12291 additions and 6121 deletions

View file

@ -45,7 +45,6 @@ module.exports = {
"overrides": [{
"files": [
"devtools/**",
"security/**",
"services/**",
"servo/**",
"startupcache/**",

View file

@ -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/**

View file

@ -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();

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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");
}

View file

@ -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");

View file

@ -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.

View file

@ -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
);
}
/**

View file

@ -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]) {

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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();

View file

@ -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")
);
}
}

View file

@ -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;
}

View file

@ -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"];

View file

@ -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`);
}

View file

@ -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();
}

View file

@ -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();
});
});

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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"
);
});

View file

@ -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"
);
});

View file

@ -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"
);
});

View file

@ -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"
);
});

View file

@ -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"
);
});

View file

@ -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);
}

View file

@ -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;
}
);
}

View file

@ -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();

View file

@ -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");

View file

@ -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("");
}
/**

View file

@ -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();
}

View file

@ -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
);
});

View file

@ -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
);
}
});

View file

@ -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.");
}
);

View file

@ -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
)
);
});

View file

@ -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`);

View file

@ -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";

View file

@ -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");
}

View file

@ -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"
);
}

View file

@ -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() {

View file

@ -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"
);
}

View file

@ -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"
);
}
);

View file

@ -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])
)
);
}

View file

@ -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

View file

@ -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() {

View file

@ -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"
);
});

View file

@ -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" +

View file

@ -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.

View file

@ -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]
);
}
}
});

View file

@ -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);
});

View file

@ -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();
});

View file

@ -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);
});

View file

@ -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");
}

View file

@ -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"
);
});

View file

@ -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();
}

View file

@ -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);
}
);

View file

@ -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);
}
);

View file

@ -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");
}
);

View file

@ -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"
);
}

View file

@ -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
);
});

View file

@ -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"
);
}

View file

@ -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);

View file

@ -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"
);
}

View file

@ -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) {

View file

@ -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)"
);
});

View file

@ -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();
}

View file

@ -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() {

View file

@ -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);
});

View file

@ -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");
});

View file

@ -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)"
);
}
});

View file

@ -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
);
});
}

View file

@ -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"
);
}

View file

@ -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
);

View file

@ -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
);
});

View file

@ -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");

View file

@ -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);
});

View file

@ -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() {

View file

@ -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);
});

View file

@ -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";

View file

@ -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) {

View file

@ -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();
}

View file

@ -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() {

View file

@ -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, ",,"));

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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"
);
}

View file

@ -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 = [];

View file

@ -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();
});
}

View file

@ -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);
}

View file

@ -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);
});

View file

@ -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();
}

View file

@ -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"]),

View file

@ -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
);
}

View file

@ -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);
});

View file

@ -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();
}

View file

@ -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();

View file

@ -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();

View file

@ -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