Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2020-04-03 09:57:28 +08:00
commit 4ecaa49dd0
102 changed files with 772 additions and 102069 deletions

View file

@ -47,6 +47,12 @@ ifndef MOZ_PROFILE_USE
# We need to explicitly put BUILD_BACKEND_FILES here otherwise the rule in
# rules.mk doesn't run early enough.
$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status $(BUILD_BACKEND_FILES)
# While our mozbuild backend has some kind of crazy install_manfests junk to
# try and make this not have to happen, we actually want dist/bin to be
# completely removed regardless.
default alldep all::
$(RM) -r $(DIST)/bin
ifndef JS_STANDALONE
ifdef COMPILE_ENVIRONMENT
$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status

View file

@ -6,11 +6,10 @@ with an ESR-52 fork point.
In addition to further development based on the Mozilla upstream code, and
selective cherry-picking of directly-applicable patches, this repository has its
own development and holds the base for a future platform to be used by XUL
own development and holds the base for a maintained platform to be used by XUL
applications.
This repository will contain at least one application to demonstrate and make use
of the platform: The Basilisk web browser, a close twin to Mozilla's Firefox.
For a list of active projects making use of the Unified XUL Platform, checkout http://thereisonlyxul.org/.
## Additional documentation
@ -29,7 +28,8 @@ owners. For more details, please see the notifications in the respective directo
### Foundation and maintainership
This repository has been founded and is maintained by Moonchild (M.C. Straver).
If you fork this repository to perform your own work on it, please consider
offering improvement patches upstream to its origin to mutually improve the
platform and build a future for XUL.
This repository has been founded by Moonchild (M.C. Straver) and is maintained by him
and other community members.
If you fork this repository to perform your own work on it, please consider offering
improvement patches upstream to its origin to mutually improve the platform and build
a future for XUL.

View file

@ -1651,7 +1651,7 @@ BrowserGlue.prototype = {
},
_migrateUI: function() {
const UI_VERSION = 42;
const UI_VERSION = 43;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
let currentUIVersion;
@ -1972,6 +1972,19 @@ BrowserGlue.prototype = {
OS.File.remove(backupFile.path, {ignoreAbsent: true}).catch(ex => Cu.reportError(ex));
}
if (currentUIVersion < 43) {
if (Services.prefs.prefHasUserValue("layers.acceleration.disabled")) {
let HWADisabled = Services.prefs.getBoolPref("layers.acceleration.disabled");
Services.prefs.setBoolPref("layers.acceleration.enabled", !HWADisabled);
Services.prefs.setBoolPref("gfx.direct2d.disabled", HWADisabled);
}
if (Services.prefs.getBoolPref("layers.acceleration.force-enabled", false)) {
Services.prefs.setBoolPref("layers.acceleration.force", true);
}
Services.prefs.clearUserPref("layers.acceleration.disabled");
Services.prefs.clearUserPref("layers.acceleration.force-enabled");
}
// Update the migration version.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},

View file

@ -217,9 +217,9 @@ var gAdvancedPane = {
updateHardwareAcceleration: function()
{
if (AppConstants.platform = "win") {
var fromPref = document.getElementById("layers.acceleration.disabled");
var fromPref = document.getElementById("layers.acceleration.enabled");
var toPref = document.getElementById("gfx.direct2d.disabled");
toPref.value = fromPref.value;
toPref.value = !fromPref.value;
}
},

View file

@ -34,10 +34,9 @@
<preference id="general.smoothScroll"
name="general.smoothScroll"
type="bool"/>
<preference id="layers.acceleration.disabled"
name="layers.acceleration.disabled"
type="bool"
inverted="true"/>
<preference id="layers.acceleration.enabled"
name="layers.acceleration.enabled"
type="bool"/>
#ifdef XP_WIN
<preference id="gfx.direct2d.disabled"
name="gfx.direct2d.disabled"
@ -177,7 +176,7 @@
<checkbox id="allowHWAccel"
label="&allowHWAccel.label;"
accesskey="&allowHWAccel.accesskey;"
preference="layers.acceleration.disabled"/>
preference="layers.acceleration.enabled"/>
<checkbox id="checkSpelling"
label="&checkSpelling.label;"
accesskey="&checkSpelling.accesskey;"

View file

@ -949,6 +949,9 @@ pref("security.alternate_certificate_error_page", "certerror");
// Whether to start the private browsing mode at application startup
pref("browser.privatebrowsing.autostart", false);
// Whether to immediately open the bookmark edit panel for new bookmarks
pref("browser.bookmarks.editDialog.showForNewBookmarks", false);
// Don't try to alter this pref, it'll be reset the next time you use the
// bookmarking dialog
pref("browser.bookmarks.editDialog.firstEditField", "namePicker");

View file

@ -25,11 +25,7 @@ var gGestureSupport = {
* True to add/init listeners and false to remove/uninit
*/
init: function(aAddListener) {
// Bug 863514 - Make gesture support work in electrolysis
if (gMultiProcessBrowser)
return;
const gestureEvents = ["SwipeGestureStart",
const gestureEvents = ["SwipeGestureMayStart", "SwipeGestureStart",
"SwipeGestureUpdate", "SwipeGestureEnd", "SwipeGesture",
"MagnifyGestureStart", "MagnifyGestureUpdate", "MagnifyGesture",
"RotateGestureStart", "RotateGestureUpdate", "RotateGesture",
@ -38,8 +34,9 @@ var gGestureSupport = {
let addRemove = aAddListener ? window.addEventListener :
window.removeEventListener;
gestureEvents.forEach(function(event) addRemove("Moz" + event, this, true),
this);
for (let event of gestureEvents) {
addRemove("Moz" + event, this, true);
}
},
/**
@ -57,13 +54,18 @@ var gGestureSupport = {
}
// Create a preference object with some defaults
let def = function(aThreshold, aLatched)
let def = (aThreshold, aLatched) =>
({ threshold: aThreshold, latched: !!aLatched });
switch (aEvent.type) {
case "MozSwipeGestureMayStart":
if (this._shouldDoSwipeGesture(aEvent)) {
aEvent.preventDefault();
}
break;
case "MozSwipeGestureStart":
aEvent.preventDefault();
this._setupSwipeGesture(aEvent);
this._setupSwipeGesture();
break;
case "MozSwipeGestureUpdate":
aEvent.preventDefault();
@ -175,14 +177,17 @@ var gGestureSupport = {
},
/**
* Sets up the history swipe animations for a swipe gesture event, if enabled.
* Checks whether we want to start a swipe for aEvent and sets
* aEvent.allowedDirections to the right values.
*
* @param aEvent
* The swipe gesture start event.
* The swipe gesture "MayStart" event.
* @return true if we're willing to start a swipe for this event, false
* otherwise.
*/
_setupSwipeGesture: function(aEvent) {
_shouldDoSwipeGesture: function(aEvent) {
if (!this._swipeNavigatesHistory(aEvent))
return;
return false;
let canGoBack = gHistorySwipeAnimation.canGoBack();
let canGoForward = gHistorySwipeAnimation.canGoForward();
@ -195,7 +200,20 @@ var gGestureSupport = {
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
aEvent.DIRECTION_LEFT;
gHistorySwipeAnimation.startAnimation();
return true;
},
/**
* Sets up swipe gestures. This includes setting up swipe animations for the
* gesture, if enabled.
*
* @param aEvent
* The swipe gesture start event.
* @return true if swipe gestures could successfully be set up, false
* othwerwise.
*/
_setupSwipeGesture: function() {
gHistorySwipeAnimation.startAnimation(false);
this._doUpdate = function(aEvent) {
gHistorySwipeAnimation.updateAnimation(aEvent.delta);
@ -491,10 +509,6 @@ var gGestureSupport = {
* image
*/
restoreRotationState: function() {
// Bug 863514 - Make gesture support work in electrolysis
if (gMultiProcessBrowser)
return;
if (!(content.document instanceof ImageDocument))
return;
@ -546,8 +560,7 @@ var gHistorySwipeAnimation = {
return;
this.active = false;
this.isLTR = document.documentElement.mozMatchesSelector(
":-moz-locale-dir(ltr)");
this.isLTR = document.documentElement.matches(":-moz-locale-dir(ltr)");
this._trackedSnapshots = [];
this._historyIndex = -1;
this._boxWidth = -1;
@ -561,6 +574,7 @@ var gHistorySwipeAnimation = {
gBrowser.addEventListener("pagehide", this, false);
gBrowser.addEventListener("pageshow", this, false);
gBrowser.addEventListener("popstate", this, false);
gBrowser.addEventListener("DOMModalDialogClosed", this, false);
gBrowser.tabContainer.addEventListener("TabClose", this, false);
}
},
@ -572,6 +586,7 @@ var gHistorySwipeAnimation = {
gBrowser.removeEventListener("pagehide", this, false);
gBrowser.removeEventListener("pageshow", this, false);
gBrowser.removeEventListener("popstate", this, false);
gBrowser.removeEventListener("DOMModalDialogClosed", this, false);
gBrowser.tabContainer.removeEventListener("TabClose", this, false);
this.active = false;
@ -609,6 +624,7 @@ var gHistorySwipeAnimation = {
*/
stopAnimation: function() {
gHistorySwipeAnimation._removeBoxes();
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
},
/**
@ -643,7 +659,6 @@ var gHistorySwipeAnimation = {
else {
if (aVal < -1)
aVal = -1; // Cap value to avoid sliding the page further than allowed.
// The intention is to go forward. If there is a page to go forward to,
// it should slide in from the right (LTR) or left (RTL).
// Otherwise, the current page should slide to the left (LTR) or
@ -651,9 +666,10 @@ var gHistorySwipeAnimation = {
// For the backdrop to be visible in that case, the previous page needs
// to be hidden (if it exists).
if (this._canGoForward) {
this._nextBox.collapsed = false;
let offset = this.isLTR ? 1 : -1;
this._positionBox(this._curBox, 0);
this._positionBox(this._nextBox, offset + aVal); // aVal is negative
this._positionBox(this._nextBox, offset + aVal); // aval is negative
}
else {
this._prevBox.collapsed = true;
@ -669,25 +685,34 @@ var gHistorySwipeAnimation = {
* An event to process.
*/
handleEvent: function(aEvent) {
let browser = gBrowser.selectedBrowser;
switch (aEvent.type) {
case "TabClose":
let browser = gBrowser.getBrowserForTab(aEvent.target);
this._removeTrackedSnapshot(-1, browser);
let browserForTab = gBrowser.getBrowserForTab(aEvent.target);
this._removeTrackedSnapshot(-1, browserForTab);
break;
case "DOMModalDialogClosed":
this.stopAnimation();
break;
case "pageshow":
case "popstate":
if (this.isAnimationRunning()) {
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
break;
if (aEvent.target == browser.contentDocument) {
this.stopAnimation();
}
break;
case "popstate":
if (aEvent.target == browser.contentDocument.defaultView) {
this.stopAnimation();
}
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
break;
case "pagehide":
if (aEvent.target == gBrowser.selectedBrowser.contentDocument) {
// Take a snapshot of a page whenever it's about to be navigated away
// from.
this._takeSnapshot();
if (aEvent.target == browser.contentDocument) {
// Take and compress a snapshot of a page whenever it's about to be
// navigated away from. We already have a snapshot of the page if an
// animation is running, so we're left with compressing it.
if (!this.isAnimationRunning()) {
this._takeSnapshot();
}
this._compressSnapshotAtCurrentIndex();
}
break;
}
@ -776,9 +801,10 @@ var gHistorySwipeAnimation = {
* |this|.
*/
_navigateToHistoryIndex: function() {
if (this._doesIndexExistInHistory(this._historyIndex)) {
if (this._doesIndexExistInHistory(this._historyIndex))
gBrowser.webNavigation.gotoIndex(this._historyIndex);
}
else
this.stopAnimation();
},
/**
@ -866,27 +892,48 @@ var gHistorySwipeAnimation = {
*/
_positionBox: function(aBox, aPosition) {
aBox.style.transform = "translateX(" + this._boxWidth * aPosition + "px)";
let transform = "";
aBox.style.transform = transform;
},
/**
* Verifies that we're ready to take snapshots based on the global pref and
* the current index in history.
*
* @return true if we're ready to take snapshots, false otherwise.
*/
_readyToTakeSnapshots: function() {
if ((this._maxSnapshots < 1) ||
(gBrowser.webNavigation.sessionHistory.index < 0)) {
return false;
}
return true;
},
/**
* Takes a snapshot of the page the browser is currently on.
*/
_takeSnapshot: function() {
if ((this._maxSnapshots < 1) ||
(gBrowser.webNavigation.sessionHistory.index < 0))
if (!this._readyToTakeSnapshots()) {
return;
}
let canvas = null;
let browser = gBrowser.selectedBrowser;
let r = browser.getBoundingClientRect();
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
"canvas");
canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
"canvas");
canvas.mozOpaque = true;
canvas.width = r.width;
canvas.height = r.height;
let scale = window.devicePixelRatio;
canvas.width = r.width * scale;
canvas.height = r.height * scale;
let ctx = canvas.getContext("2d");
let zoom = browser.markupDocumentViewer.fullZoom;
let zoom = browser.markupDocumentViewer.fullZoom * scale;
ctx.scale(zoom, zoom);
ctx.drawWindow(browser.contentWindow, 0, 0, r.width, r.height, "white",
ctx.drawWindow(browser.contentWindow,
0, 0, canvas.width / zoom, canvas.height / zoom, "white",
ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
@ -925,11 +972,34 @@ var gHistorySwipeAnimation = {
// Temporarily store the canvas as the compressed snapshot.
// This avoids a blank page if the user swipes quickly
// between pages before the compression could complete.
snapshots[currIndex] = aCanvas;
snapshots[currIndex] = {
image: aCanvas,
scale: window.devicePixelRatio
};
},
/**
* Compresses the HTMLCanvasElement that's stored at the current history
* index in the snapshot array and stores the compressed image in its place.
*/
_compressSnapshotAtCurrentIndex:
function() {
if (!this._readyToTakeSnapshots()) {
// We didn't take a snapshot earlier because we weren't ready to, so
// there's nothing to compress.
return;
}
let browser = gBrowser.selectedBrowser;
let snapshots = browser.snapshots;
let currIndex = browser.webNavigation.sessionHistory.index;
// Kick off snapshot compression.
aCanvas.toBlob(function(aBlob) {
snapshots[currIndex] = aBlob;
let canvas = snapshots[currIndex].image;
canvas.toBlob(function(aBlob) {
if (snapshots[currIndex]) {
snapshots[currIndex].image = aBlob;
}
}, "image/png"
);
},
@ -980,6 +1050,7 @@ var gHistorySwipeAnimation = {
while (arr.length > this._maxSnapshots) {
let lastElem = arr[arr.length - 1];
delete lastElem.browser.snapshots[lastElem.index].image;
delete lastElem.browser.snapshots[lastElem.index];
arr.splice(-1, 1);
}
@ -1004,12 +1075,42 @@ var gHistorySwipeAnimation = {
return aBlob;
let img = new Image();
let url = URL.createObjectURL(aBlob);
img.onload = function() {
URL.revokeObjectURL(url);
};
img.src = url;
return img;
let url = "";
try {
url = URL.createObjectURL(aBlob);
img.onload = function() {
URL.revokeObjectURL(url);
};
}
finally {
img.src = url;
return img;
}
},
/**
* Scales the background of a given box element (which uses a given snapshot
* as background) based on a given scale factor.
* @param aSnapshot
* The snapshot that is used as background of aBox.
* @param aScale
* The scale factor to use.
* @param aBox
* The box element that uses aSnapshot as background.
*/
_scaleSnapshot: function(aSnapshot, aScale, aBox) {
if (aSnapshot && aScale != 1 && aBox) {
if (aSnapshot instanceof HTMLCanvasElement) {
aBox.style.backgroundSize =
aSnapshot.width / aScale + "px " + aSnapshot.height / aScale + "px";
} else {
// snapshot is instanceof HTMLImageElement
aSnapshot.addEventListener("load", function() {
aBox.style.backgroundSize =
aSnapshot.width / aScale + "px " + aSnapshot.height / aScale + "px";
});
}
}
},
/**
@ -1024,12 +1125,17 @@ var gHistorySwipeAnimation = {
_installCurrentPageSnapshot:
function(aCanvas) {
let currSnapshot = aCanvas;
let scale = window.devicePixelRatio;
if (!currSnapshot) {
let snapshots = gBrowser.selectedBrowser.snapshots || {};
let currIndex = this._historyIndex;
if (currIndex in snapshots)
currSnapshot = this._convertToImg(snapshots[currIndex]);
if (currIndex in snapshots) {
currSnapshot = this._convertToImg(snapshots[currIndex].image);
scale = snapshots[currIndex].scale;
}
}
this._scaleSnapshot(currSnapshot, scale, this._curBox ? this._curBox :
null);
document.mozSetImageElement("historySwipeAnimationCurrentPageSnapshot",
currSnapshot);
},
@ -1044,15 +1150,21 @@ var gHistorySwipeAnimation = {
let currIndex = this._historyIndex;
let prevIndex = currIndex - 1;
let prevSnapshot = null;
if (prevIndex in snapshots)
prevSnapshot = this._convertToImg(snapshots[prevIndex]);
if (prevIndex in snapshots) {
prevSnapshot = this._convertToImg(snapshots[prevIndex].image);
this._scaleSnapshot(prevSnapshot, snapshots[prevIndex].scale,
this._prevBox);
}
document.mozSetImageElement("historySwipeAnimationPreviousPageSnapshot",
prevSnapshot);
let nextIndex = currIndex + 1;
let nextSnapshot = null;
if (nextIndex in snapshots)
nextSnapshot = this._convertToImg(snapshots[nextIndex]);
if (nextIndex in snapshots) {
nextSnapshot = this._convertToImg(snapshots[nextIndex].image);
this._scaleSnapshot(nextSnapshot, snapshots[nextIndex].scale,
this._nextBox);
}
document.mozSetImageElement("historySwipeAnimationNextPageSnapshot",
nextSnapshot);
},

View file

@ -14,6 +14,10 @@ var StarUI = {
return document.getElementById(aID);
},
get showForNewBookmarks() {
return Services.prefs.getBoolPref("browser.bookmarks.editDialog.showForNewBookmarks", false);
},
// Edit-bookmark panel
get panel() {
delete this.panel;
@ -1261,7 +1265,8 @@ var BookmarkingUI = {
}
// Ignore clicks on the star if we are updating its state.
if (!this._pendingStmt) {
PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0);
PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0 ||
StarUI.showForNewBookmarks);
}
},

View file

@ -238,9 +238,9 @@ BrowserGlue.prototype = {
this._onPlacesShutdown();
break;
case "idle":
if ((this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) &&
this._shouldBackupBookmarks())
if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) {
this._backupBookmarks();
}
break;
case "distribution-customization-complete":
Services.obs.removeObserver(this, "distribution-customization-complete");
@ -941,8 +941,7 @@ BrowserGlue.prototype = {
Services.prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks");
if (restoreDefaultBookmarks) {
// Ensure that we already have a bookmarks backup for today.
if (this._shouldBackupBookmarks())
yield this._backupBookmarks();
yield this._backupBookmarks();
importBookmarks = true;
}
} catch(ex) {}
@ -1088,22 +1087,19 @@ BrowserGlue.prototype = {
}
let waitingForBackupToComplete = true;
if (this._shouldBackupBookmarks()) {
waitingForBackupToComplete = false;
this._backupBookmarks().then(
function onSuccess() {
waitingForBackupToComplete = true;
},
function onFailure() {
Cu.reportError("Unable to backup bookmarks.");
waitingForBackupToComplete = true;
}
);
}
this._backupBookmarks().then(
function onSuccess() {
waitingForBackupToComplete = false;
},
function onFailure() {
Cu.reportError("Unable to backup bookmarks.");
waitingForBackupToComplete = false;
}
);
// Backup bookmarks to bookmarks.html to support apps that depend
// on the legacy format.
let waitingForHTMLExportToComplete = true;
let waitingForHTMLExportToComplete = false;
// If this fails to get the preference value, we don't export.
if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) {
// Exceptionally, since this is a non-default setting and HTML format is
@ -1112,51 +1108,44 @@ BrowserGlue.prototype = {
// spin the event loop on shutdown until we include a watchdog to prevent
// potential hangs (bug 518683). The asynchronous shutdown operations
// will then be handled by a shutdown service (bug 435058).
waitingForHTMLExportToComplete = false;
waitingForHTMLExportToComplete = true;
BookmarkHTMLUtils.exportToFile(BookmarkHTMLUtils.defaultPath).then(
function onSuccess() {
waitingForHTMLExportToComplete = true;
waitingForHTMLExportToComplete = false;
},
function onFailure() {
Cu.reportError("Unable to auto export html.");
waitingForHTMLExportToComplete = true;
waitingForHTMLExportToComplete = false;
}
);
}
// The events loop should spin at least once because waitingForBackupToComplete
// is true before checking whether backup should be made.
let thread = Services.tm.currentThread;
while (!waitingForBackupToComplete || !waitingForHTMLExportToComplete) {
while (waitingForBackupToComplete || waitingForHTMLExportToComplete) {
thread.processNextEvent(true);
}
},
/**
* Determine whether to backup bookmarks or not.
* @return true if bookmarks should be backed up, false if not.
*/
_shouldBackupBookmarks: function() {
let lastBackupFile = PlacesBackups.getMostRecent();
// Should backup bookmarks if there are no backups or the maximum interval between
// backups elapsed.
return (!lastBackupFile ||
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL);
},
/**
* Backup bookmarks.
*/
_backupBookmarks: function() {
return Task.spawn(function() {
// Backup bookmarks if there are no backups or the maximum interval between
// backups elapsed.
let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
try {
maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
}
catch(ex) { /* Use default. */ }
let lastBackupFile = yield PlacesBackups.getMostRecentBackup();
// Should backup bookmarks if there are no backups or the maximum
// interval between backups elapsed.
if (!lastBackupFile ||
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) {
let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
try {
maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
}
catch(ex) { /* Use default. */ }
yield PlacesBackups.create(maxBackups); // Don't force creation.
yield PlacesBackups.create(maxBackups); // Don't force creation.
}
});
},
@ -1198,7 +1187,7 @@ BrowserGlue.prototype = {
},
_migrateUI: function() {
const UI_VERSION = 22;
const UI_VERSION = 23;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
let currentUIVersion = 0;
try {
@ -1453,9 +1442,9 @@ BrowserGlue.prototype = {
}
}
if (currentUIVersion < 22) {
if (currentUIVersion < 23) {
if (Services.prefs.prefHasUserValue("layers.acceleration.disabled")) {
let HWADisabled = Service.prefs.getBoolPref("layers.acceleration.disabled");
let HWADisabled = Services.prefs.getBoolPref("layers.acceleration.disabled");
Services.prefs.setBoolPref("layers.acceleration.enabled", !HWADisabled);
Services.prefs.setBoolPref("gfx.direct2d.disabled", HWADisabled);
}

View file

@ -159,8 +159,8 @@ var gAdvancedPane = {
{
#ifdef XP_WIN
var fromPref = document.getElementById("layers.acceleration.enabled");
var toPref = document.getElementById("gfx.direct2d.disabled");
toPref.value = !fromPref.value;
var toPref = document.getElementById("gfx.direct2d.enabled");
toPref.value = fromPref.value;
#endif
this.updateHWADisplay();
},

View file

@ -33,8 +33,9 @@
<preference id="general.smoothScroll" name="general.smoothScroll" type="bool"/>
<preference id="layers.acceleration.enabled" name="layers.acceleration.enabled" type="bool"
onchange="gAdvancedPane.updateHardwareAcceleration()"/>
<preference id="layers.acceleration.force" name="layers.acceleration.force" type="bool"/>
#ifdef XP_WIN
<preference id="gfx.direct2d.disabled" name="gfx.direct2d.disabled" type="bool" inverted="true"/>
<preference id="gfx.direct2d.enabled" name="gfx.direct2d.disabled" type="bool" inverted="true"/>
#endif
<preference id="layout.spellcheckDefault" name="layout.spellcheckDefault" type="int"/>

View file

@ -46,10 +46,7 @@
<preference id="network.stricttransportsecurity.enabled"
name="network.stricttransportsecurity.enabled"
type="bool"/>
<preference id="security.cert_pinning.hpkp.enabled"
name="security.cert_pinning.hpkp.enabled"
type="bool"/>
<!-- Opportunistic Encryption -->
<preference id="network.http.upgrade-insecure-requests"
@ -147,10 +144,6 @@
label="&enableHSTS.label;"
accesskey="&enableHSTS.accesskey;"
preference="network.stricttransportsecurity.enabled" />
<checkbox id="enableHPKP"
label="&enableHPKP.label;"
accesskey="&enableHPKP.accesskey;"
preference="security.cert_pinning.hpkp.enabled"/>
</vbox>
</groupbox>

View file

@ -1 +1 @@
28.9.0a1
28.9.1a1

View file

@ -37,8 +37,6 @@
<!ENTITY SecProto.label "Security Protocols">
<!ENTITY enableHSTS.label "Enable Strict Transport Security (HSTS)">
<!ENTITY enableHSTS.accesskey "S">
<!ENTITY enableHPKP.label "Enable Certificate Key Pinning (HPKP)">
<!ENTITY enableHPKP.accesskey "C">
<!ENTITY OpEnc.label "Opportunistic Encryption (OE)">
<!ENTITY enableUIROpEnc.label "Enable Upgrade Insecure Requests">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

View file

@ -68,6 +68,21 @@
background-image: linear-gradient(rgba(32,32,32,.8), rgba(32,32,32,0));
}
/* Blend the topmost toolbar with the titlebar */
#main-window[tabsontop=false]:not([privatebrowsingmode=temporary]) #nav-bar:not(:-moz-lwtheme),
#main-window[tabsontop=true]:not([privatebrowsingmode=temporary]) #TabsToolbar:not(:-moz-lwtheme) {
-moz-appearance: toolbar;
}
#main-window[tabsontop=false][privatebrowsingmode=temporary] #nav-bar:not(:-moz-lwtheme),
#main-window[tabsontop=true][privatebrowsingmode=temporary] #TabsToolbar:not(:-moz-lwtheme) {
background-color: transparent;
}
#main-window[tabsontop=false][privatebrowsingmode=temporary] #nav-bar:not(:-moz-lwtheme) {
border-bottom: 1px solid rgba(26,26,26,0.2);
}
#personal-bookmarks {
min-height: 24px;
}
@ -96,10 +111,6 @@
-moz-appearance: -moz-window-button-box;
}
#main-window[sizemode="maximized"] #titlebar-buttonbox {
-moz-appearance: -moz-window-button-box-maximized;
}
.titlebar-placeholder[type="appmenu-button"] {
margin-left: 4px;
}
@ -639,8 +650,8 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
@conditionalForwardWithUrlbar@ > #forward-button > .toolbarbutton-icon {
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path);
-moz-margin-start: -6px !important;
clip-path: url(chrome://browser/content/browser.xul#osx-keyhole-forward-clip-path);
-moz-margin-start: -9px !important;
border-left-style: none;
border-radius: 0;
padding-left: 7px;

View file

@ -60,7 +60,7 @@ browser.jar:
skin/classic/browser/privatebrowsing-light.png
skin/classic/browser/privatebrowsing-dark.png
skin/classic/browser/reload-stop-go.png
skin/classic/browser/Search-glass.png
skin/classic/browser/Search.png
skin/classic/browser/searchbar.css
skin/classic/browser/searchbar-dropdown-arrow.png
skin/classic/browser/Secure24.png

View file

@ -57,9 +57,9 @@
}
.search-go-button {
padding: 1px;
list-style-image: url("chrome://browser/skin/Search-glass.png");
-moz-image-region: rect(0px 16px 16px 0px);
padding: 2px 1px;
opacity: .4;
list-style-image: url("chrome://browser/skin/Search.png");
}
.search-go-button:-moz-locale-dir(rtl) {
@ -67,11 +67,11 @@
}
.search-go-button:hover {
-moz-image-region: rect(0px 32px 16px 16px);
opacity: .6;
}
.search-go-button:hover:active {
-moz-image-region: rect(0px, 48px, 16px, 32px);
opacity: .8;
}
.searchbar-engine-menuitem[selected="true"] > .menu-iconic-text {

View file

@ -842,6 +842,13 @@ EOF
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
*:MINGW32_NT*:*)
if [ "$PLATFORM" = "X64" ]; then
echo x86_64-pc-mingw32
else
echo ${UNAME_MACHINE}-pc-mingw32
fi
exit ;;
*:MINGW64*:*)
echo ${UNAME_MACHINE}-pc-mingw64
exit ;;

View file

@ -224,6 +224,7 @@ def old_configure_options(*options):
'--enable-require-all-d3dc-versions',
'--enable-safe-browsing',
'--enable-sandbox',
'--enable-security-sqlstore',
'--enable-signmar',
'--enable-simulator',
'--enable-small-chunk-size',

View file

@ -9828,7 +9828,7 @@ var Debugger =
var host = httpActivity.hostname;
info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
info.hpkp = false;
} else {
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo", "Could not get HSTS/HPKP status as hostname is not available.");
info.hsts = false;

View file

@ -668,7 +668,8 @@ var NetworkHelper = {
let host = httpActivity.hostname;
info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
// HPKP is no longer supported.
info.hpkp = false;
} else {
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
"Could not get HSTS/HPKP status as hostname is not available.");

View file

@ -4943,13 +4943,11 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
error.AssignLiteral("nssBadCert");
// If this is an HTTP Strict Transport Security host or a pinned host
// and the certificate is bad, don't allow overrides (RFC 6797 section
// 12.1, HPKP draft spec section 2.6).
// If this is an HTTP Strict Transport Security host, don't allow
// overrides (RFC 6797 section 12.1).
uint32_t flags =
UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
bool isStsHost = false;
bool isPinnedHost = false;
if (XRE_IsParentProcess()) {
nsCOMPtr<nsISiteSecurityService> sss =
do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
@ -4957,9 +4955,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
flags, nullptr, &isStsHost);
NS_ENSURE_SUCCESS(rv, rv);
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
flags, nullptr, &isPinnedHost);
NS_ENSURE_SUCCESS(rv, rv);
} else {
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
@ -4967,8 +4962,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
SerializeURI(aURI, uri);
cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
&isStsHost);
cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
&isPinnedHost);
}
if (Preferences::GetBool(
@ -4976,11 +4969,9 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
cssClass.AssignLiteral("expertBadCert");
}
// HSTS/pinning takes precedence over the expert bad cert pref. We
// HSTS takes precedence over the expert bad cert pref. We
// never want to show the "Add Exception" button for these sites.
// In the future we should differentiate between an HSTS host and a
// pinned host and display a more informative message to the user.
if (isStsHost || isPinnedHost) {
if (isStsHost) {
cssClass.AssignLiteral("badStsCert");
}

View file

@ -16,6 +16,7 @@ def generateLine(propName, extendedAttrs):
return " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
propName)
def generate(output, idlFilename, preprocessorHeader):
print(idlFilename)
cpp = list(buildconfig.substs['CPP'])
cpp += shellutil.split(buildconfig.substs['ACDEFINES'])
cpp.append(preprocessorHeader)

View file

@ -269,6 +269,7 @@ class WebIDLCodegenManager(LoggingMixin):
# Generate bindings from .webidl files.
for filename in sorted(changed_inputs):
basename = mozpath.basename(filename)
print basename
result.inputs.add(filename)
written, deps = self._generate_build_files_for_webidl(filename)
result.created |= written[0]

View file

@ -2351,18 +2351,16 @@ nsWebBrowserPersist::EndDownload(nsresult aResult)
{
mPersistResult = aResult;
}
// mCompleted needs to be set before issuing the stop notification.
// (Bug 1224437)
mCompleted = true;
#ifdef MOZ_JSDOWNLOADS
// State stop notification
if (mProgressListener) {
mProgressListener->OnStateChange(nullptr, nullptr,
nsIWebProgressListener::STATE_STOP
| nsIWebProgressListener::STATE_IS_NETWORK, mPersistResult);
}
#endif
// Do file cleanup if required
if (NS_FAILED(aResult) && (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE))

View file

@ -85,7 +85,7 @@
#elif defined(__ppc__) || defined(__powerpc__)
#define ARCH_CPU_PPC 1
#define ARCH_CPU_32_BITS 1
#elif defined(__sparc64__)
#elif defined(__sparc__) && defined(__arch64__)
#define ARCH_CPU_SPARC 1
#define ARCH_CPU_64_BITS 1
#elif defined(__sparc__)

View file

@ -55,7 +55,7 @@ namespace {
static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
inline XPCShellEnvironment*
Environment(Handle<JSObject*> global)
Environment(JS::Handle<JSObject*> global)
{
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {

View file

@ -423,7 +423,7 @@ MapMemoryAt(void* desired, size_t length, int prot = PROT_READ | PROT_WRITE,
// possibly be correct on AMD64, but for Solaris/illumos it is.
{
#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__) || (defined(__sun) && defined(__x86_64__))
#if defined(__ia64__) || defined(__aarch64__) || (defined(__sun) && defined(__x86_64__)) || (defined(__sparc__) && defined(__arch64__) && (defined(__NetBSD__) || defined(__linux__)))
MOZ_ASSERT((0xffff800000000000ULL & (uintptr_t(desired) + length - 1)) == 0);
#endif
void* region = mmap(desired, length, prot, flags, fd, offset);
@ -446,7 +446,7 @@ static inline void*
MapMemory(size_t length, int prot = PROT_READ | PROT_WRITE,
int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0)
{
#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__))
#if defined(__ia64__) || (defined(__sparc__) && defined(__arch64__) && defined(__NetBSD__))
/*
* The JS engine assumes that all allocated pointers have their high 17 bits clear,
* which ia64's mmap doesn't support directly. However, we can emulate it by passing
@ -473,7 +473,7 @@ MapMemory(size_t length, int prot = PROT_READ | PROT_WRITE,
return nullptr;
}
return region;
#elif defined(__aarch64__) || (defined(__sun) && defined(__x86_64__))
#elif defined(__aarch64__) || (defined(__sun) && defined(__x86_64__)) || (defined(__sparc__) && defined(__arch64__) && defined(__linux__))
/*
* There might be similar virtual address issue on arm64 which depends on
* hardware and kernel configurations. But the work around is slightly

View file

@ -302,7 +302,8 @@ void unmapPages(void* p, size_t size) { }
void*
mapMemoryAt(void* desired, size_t length)
{
#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__)
#if defined(__ia64__) || defined(__aarch64__) || \
(defined(__sparc__) && defined(__arch64__) && (defined(__NetBSD__) || defined(__linux__)))
MOZ_RELEASE_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0);
#endif
void* region = mmap(desired, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
@ -324,7 +325,7 @@ mapMemory(size_t length)
int fd = -1;
off_t offset = 0;
// The test code must be aligned with the implementation in gc/Memory.cpp.
#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__))
#if defined(__ia64__) || (defined(__sparc__) && defined(__arch64__) && defined(__NetBSD__))
void* region = mmap((void*)0x0000070000000000, length, prot, flags, fd, offset);
if (region == MAP_FAILED)
return nullptr;
@ -334,7 +335,7 @@ mapMemory(size_t length)
return nullptr;
}
return region;
#elif defined(__aarch64__)
#elif defined(__aarch64__) || (defined(__sparc__) && defined(__arch64__) && defined(__linux__))
const uintptr_t start = UINT64_C(0x0000070000000000);
const uintptr_t end = UINT64_C(0x0000800000000000);
const uintptr_t step = js::gc::ChunkSize;

View file

@ -129,7 +129,7 @@
#define ARCH_CPU_PPC 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_BIG_ENDIAN 1
#elif defined(__sparc64__)
#elif defined(__sparc__) && defined(__arch64__)
#define ARCH_CPU_SPARC_FAMILY 1
#define ARCH_CPU_SPARC 1
#define ARCH_CPU_64_BITS 1

View file

@ -61,7 +61,7 @@
#define WEBRTC_ARCH_BIG_ENDIAN
#define WEBRTC_BIG_ENDIAN
#endif
#elif defined(__sparc64__)
#elif defined(__sparc__) && defined(__arch64__)
#define WEBRTC_ARCH_SPARC 1
#define WEBRTC_ARCH_64_BITS 1
#define WEBRTC_ARCH_BIG_ENDIAN

View file

@ -1971,7 +1971,7 @@ static void *
pages_map(void *addr, size_t size)
{
void *ret;
#if defined(__ia64__)
#if defined(__ia64__) || (defined(__sparc__) && defined(__arch64__) && defined(__linux__))
/*
* The JS engine assumes that all allocated pointers have their high 17 bits clear,
* which ia64's mmap doesn't support directly. However, we can emulate it by passing
@ -1992,6 +1992,28 @@ pages_map(void *addr, size_t size)
}
#endif
#if defined(__sparc__) && defined(__arch64__) && defined(__linux__)
const uintptr_t start = 0x0000070000000000ULL;
const uintptr_t end = 0x0000800000000000ULL;
/* Copied from js/src/gc/Memory.cpp and adapted for this source */
uintptr_t hint;
void* region = MAP_FAILED;
for (hint = start; region == MAP_FAILED && hint + size <= end; hint += chunksize) {
region = mmap((void*)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (region != MAP_FAILED) {
if (((size_t) region + (size - 1)) & 0xffff800000000000) {
if (munmap(region, size)) {
MOZ_ASSERT(errno == ENOMEM);
}
region = MAP_FAILED;
}
}
}
ret = region;
#else
/*
* We don't use MAP_FIXED here, because it can cause the *replacement*
* of existing mappings, and we only want to create new mappings.
@ -2000,10 +2022,11 @@ pages_map(void *addr, size_t size)
MAP_PRIVATE | MAP_ANON, -1, 0);
assert(ret != NULL);
#endif
if (ret == MAP_FAILED) {
ret = NULL;
}
#if defined(__ia64__)
#if defined(__ia64__) || (defined(__sparc__) && defined(__arch64__) && defined(__linux__))
/*
* If the allocated memory doesn't have its upper 17 bits clear, consider it
* as out of memory.
@ -2036,7 +2059,7 @@ pages_map(void *addr, size_t size)
MozTagAnonymousMemory(ret, size, "jemalloc");
}
#if defined(__ia64__)
#if defined(__ia64__) || (defined(__sparc__) && defined(__arch64__) && defined(__linux__))
assert(ret == NULL || (!check_placement && ret != NULL)
|| (check_placement && ret == addr));
#else

View file

@ -2037,8 +2037,6 @@ pref("network.proxy.autoconfig_retry_interval_max", 300); // 5 minutes
// Master switch for HSTS usage (security <-> privacy tradeoff)
pref("network.stricttransportsecurity.enabled", true);
// Use the HSTS preload list by default
pref("network.stricttransportsecurity.preloadlist", true);
// Use JS mDNS as a fallback
pref("network.mdns.use_js_fallback", false);

View file

@ -120,27 +120,6 @@ pref("security.webauth.u2f_enable_usbtoken", false);
// OCSP must-staple
pref("security.ssl.enable_ocsp_must_staple", true);
// HPKP settings
// Enable pinning checks by default.
pref("security.cert_pinning.enforcement_level", 2);
// Do not process hpkp headers rooted by not built in roots by default.
// This is to prevent accidental pinning from MITM devices and is used
// for tests.
pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
// Impose a maximum age on HPKP headers, to avoid sites getting permanently
// blacking themselves out by setting a bad pin. (60 days by default)
// https://tools.ietf.org/html/rfc7469#section-4.1
pref("security.cert_pinning.max_max_age_seconds", 5184000);
// Controls whether or not HPKP (the HTTP Public Key Pinning header) is enabled.
// If true, the header is processed and collected HPKP information is consulted
// when looking for pinning information.
// If false, the header is not processed and collected HPKP information is not
// consulted when looking for pinning information. Preloaded pins are not
// affected by this preference.
// Default: false
pref("security.cert_pinning.hpkp.enabled", false);
// If a request is mixed-content, send an HSTS priming request to attempt to
// see if it is available over HTTPS.
pref("security.mixed_content.send_hsts_priming", true);

View file

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef XP_WIN
#define UA_SPARE_PLATFORM
#endif
"use strict";
this.EXPORTED_SYMBOLS = [ "UserAgentOverrides" ];
@ -18,9 +22,14 @@ const PREF_OVERRIDES_ENABLED = "general.useragent.site_specific_overrides";
const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"]
.getService(Ci.nsIHttpProtocolHandler)
.userAgent;
const OS_SLICE = Cc["@mozilla.org/network/protocol;1?name=http"]
const OSCPU = Cc["@mozilla.org/network/protocol;1?name=http"]
.getService(Ci.nsIHttpProtocolHandler)
.oscpu;
#ifndef UA_SPARE_PLATFORM
const PLATFORM = Cc["@mozilla.org/network/protocol;1?name=http"]
.getService(Ci.nsIHttpProtocolHandler)
.oscpu + ";";
.platform;
#endif
const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250;
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
@ -37,12 +46,20 @@ var gOverrideFunctions = [
function (aHttpChannel) { return UserAgentOverrides.getOverrideForURI(aHttpChannel.URI); }
];
var gBuiltUAs = new Map;
var gOSSlice;
this.UserAgentOverrides = {
init: function uao_init() {
if (gInitialized)
return;
gOSSlice = OSCPU + ";";
#ifndef UA_SPARE_PLATFORM
if (PLATFORM != "") {
gOSSlice = PLATFORM + "; " + gOSSlice;
}
#endif
gPrefBranch = Services.prefs.getBranch("general.useragent.override.");
gPrefBranch.addObserver("", buildOverrides, false);
@ -151,7 +168,7 @@ function getUserAgentFromOverride(override)
if (search && replace) {
userAgent = DEFAULT_UA.replace(new RegExp(search, "g"), replace);
} else {
userAgent = override.replace(/%OS_SLICE%/g, OS_SLICE);
userAgent = override.replace(/%OS_SLICE%/g, gOSSlice);
}
gBuiltUAs.set(override, userAgent);
return userAgent;

View file

@ -99,9 +99,9 @@ IPDL_SOURCES += [
'PHttpChannel.ipdl',
]
EXTRA_JS_MODULES += ['UserAgentOverrides.jsm']
EXTRA_JS_MODULES += ['UserAgentUpdates.jsm']
EXTRA_PP_JS_MODULES += ['UserAgentUpdates.jsm']
EXTRA_PP_JS_MODULES += ['UserAgentOverrides.jsm']
include('/ipc/chromium/chromium-config.mozbuild')

View file

@ -1530,7 +1530,7 @@ GetPKPConsoleErrorTag(uint32_t failureResult, nsAString& consoleErrorTag)
}
/**
* Process a single security header. Only two types are supported: HSTS and HPKP.
* Process a single security header. Only one type is supported: HSTS.
*/
nsresult
nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
@ -1542,9 +1542,6 @@ nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
case nsISiteSecurityService::HEADER_HSTS:
atom = nsHttp::ResolveAtom("Strict-Transport-Security");
break;
case nsISiteSecurityService::HEADER_HPKP:
atom = nsHttp::ResolveAtom("Public-Key-Pins");
break;
default:
NS_NOTREACHED("Invalid security header type");
return NS_ERROR_FAILURE;
@ -1568,10 +1565,6 @@ nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
consoleErrorCategory = NS_LITERAL_STRING("Invalid HSTS Headers");
break;
case nsISiteSecurityService::HEADER_HPKP:
GetPKPConsoleErrorTag(failureResult, consoleErrorTag);
consoleErrorCategory = NS_LITERAL_STRING("Invalid HPKP Headers");
break;
default:
return NS_ERROR_FAILURE;
}
@ -1641,10 +1634,6 @@ nsHttpChannel::ProcessSecurityHeaders()
sslStatus, flags);
NS_ENSURE_SUCCESS(rv, rv);
rv = ProcessSingleSecurityHeader(nsISiteSecurityService::HEADER_HPKP,
sslStatus, flags);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

View file

@ -2165,6 +2165,7 @@ MOZ_JETPACK=1
MOZ_DEVTOOLS_SERVER=1
MOZ_DEVTOOLS=
MOZ_PLACES=1
MOZ_SECURITY_SQLSTORE=
MOZ_SERVICES_HEALTHREPORT=1
MOZ_SERVICES_SYNC=1
MOZ_USERINFO=1
@ -2725,6 +2726,24 @@ fi
AC_SUBST(NSS_DISABLE_DBM)
dnl =========================================================
dnl = NSS SQL storage format
dnl =========================================================
MOZ_ARG_ENABLE_BOOL(security-sqlstore,
[ --enable-security-sqlstore Enable the use of SQL storage for NSS],
MOZ_SECURITY_SQLSTORE=1,
MOZ_SECURITY_SQLSTORE=)
if test -n "$NSS_DISABLE_DBM" -a -z "$MOZ_SECURITY_SQLSTORE"; then
AC_MSG_ERROR([DBM storage support is required if not using NSS SQL storage])
fi
if test -n "$MOZ_SECURITY_SQLSTORE"; then
AC_DEFINE(MOZ_SECURITY_SQLSTORE)
fi
AC_SUBST(MOZ_SECURITY_SQLSTORE)
dnl =========================================================
dnl = Don't fold mailnews related comps into libXUL
dnl =========================================================

View file

@ -541,21 +541,6 @@ class Build(MachCommandBase):
# as when doing OSX Universal builds)
pass
# Check if there are any unpreprocessed files in '@MOZ_OBJDIR@/dist/bin'
# See python/mozbuild/mozbuild/preprocessor.py#L293-L309 for the list of directives
# We skip if, ifdef, ifndef, else, elif, elifdef and elifndef, because they are never used alone
#
# The original version of this script only worked with GNU grep because of the --include flag.
# Not a problem in and of itself, except that it didn't take TOOLCHAIN_PREFIX and simply assumed
# all operating systems use GNU grep as the system grep (often it's called ggrep or something).
# This script is a bit slower, but should do the same thing on all Unix platforms.
grepcmd = 'find ' + self.topobjdir + '/dist/bin' + ' -name \'\*.{css,dtd,html,js,jsm,xhtml,xml,xul,manifest,properties,rdf}\' ' + '| xargs grep -E "^(#|%)(define|endif|error|expand|filter|include|literal|undef|unfilter)" '\
+ '| awk "/\.css:%/ || (!/\.css/ && /:#/)"'
grepresult = subprocess.Popen(grepcmd, stdout=subprocess.PIPE, shell=True).communicate()[0]
if grepresult:
print('\nERROR: preprocessor was not applied to the following files:\n\n' + grepresult)
return status
@Command('configure', category='build',

View file

@ -12,7 +12,6 @@
#include "NSSErrorsService.h"
#include "OCSPRequestor.h"
#include "OCSPVerificationTrustDomain.h"
#include "PublicKeyPinningService.h"
#include "cert.h"
#include "certdb.h"
#include "mozilla/Assertions.h"
@ -862,24 +861,6 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
if (rv != Success) {
return rv;
}
bool skipPinningChecksBecauseOfMITMMode =
(!isBuiltInRoot && mPinningMode == CertVerifier::pinningAllowUserCAMITM);
// If mHostname isn't set, we're not verifying in the context of a TLS
// handshake, so don't verify HPKP in those cases.
if (mHostname && (mPinningMode != CertVerifier::pinningDisabled) &&
!skipPinningChecksBecauseOfMITMMode) {
bool enforceTestMode =
(mPinningMode == CertVerifier::pinningEnforceTestMode);
bool chainHasValidPins;
nsresult nsrv = PublicKeyPinningService::ChainHasValidPins(
certList, mHostname, time, enforceTestMode, chainHasValidPins);
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
if (!chainHasValidPins) {
return Result::ERROR_KEY_PINNING_FAILURE;
}
}
mBuiltChain = Move(certList);
@ -1102,7 +1083,12 @@ InitializeNSS(const nsACString& dir, bool readOnly, bool loadPKCS11Modules)
flags |= NSS_INIT_NOMODDB;
}
nsAutoCString dbTypeAndDirectory;
#ifdef MOZ_SECURITY_SQLSTORE
// Not strictly necessary with current NSS versions, but can't hurt to be explicit.
dbTypeAndDirectory.Append("sql:");
#else
dbTypeAndDirectory.Append("dbm:");
#endif
dbTypeAndDirectory.Append(dir);
return ::NSS_Initialize(dbTypeAndDirectory.get(), "", "", SECMOD_DB, flags);
}

View file

@ -1,333 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PublicKeyPinningService.h"
#include "mozilla/Base64.h"
#include "mozilla/Casting.h"
#include "mozilla/Logging.h"
#include "nsISiteSecurityService.h"
#include "nsServiceManagerUtils.h"
#include "nsSiteSecurityService.h"
#include "nssb64.h"
#include "pkix/pkixtypes.h"
#include "seccomon.h"
#include "sechash.h"
#include "StaticHPKPins.h" // autogenerated by genHPKPStaticpins.js
using namespace mozilla;
using namespace mozilla::pkix;
using namespace mozilla::psm;
LazyLogModule gPublicKeyPinningLog("PublicKeyPinningService");
/**
Computes in the location specified by base64Out the SHA256 digest
of the DER Encoded subject Public Key Info for the given cert
*/
static nsresult
GetBase64HashSPKI(const CERTCertificate* cert, nsACString& hashSPKIDigest)
{
hashSPKIDigest.Truncate();
Digest digest;
nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert->derPublicKey.data,
cert->derPublicKey.len);
if (NS_FAILED(rv)) {
return rv;
}
return Base64Encode(nsDependentCSubstring(
BitwiseCast<char*, unsigned char*>(digest.get().data),
digest.get().len),
hashSPKIDigest);
}
/*
* Sets certMatchesPinset to true if a given cert matches any fingerprints from
* the given pinset or the dynamicFingerprints array, or to false otherwise.
*/
static nsresult
EvalCert(const CERTCertificate* cert, const StaticFingerprints* fingerprints,
const nsTArray<nsCString>* dynamicFingerprints,
/*out*/ bool& certMatchesPinset)
{
certMatchesPinset = false;
if (!fingerprints && !dynamicFingerprints) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: No hashes found\n"));
return NS_ERROR_INVALID_ARG;
}
nsAutoCString base64Out;
nsresult rv = GetBase64HashSPKI(cert, base64Out);
if (NS_FAILED(rv)) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: GetBase64HashSPKI failed!\n"));
return rv;
}
if (fingerprints) {
for (size_t i = 0; i < fingerprints->size; i++) {
if (base64Out.Equals(fingerprints->data[i])) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: found pin base_64 ='%s'\n", base64Out.get()));
certMatchesPinset = true;
return NS_OK;
}
}
}
if (dynamicFingerprints) {
for (size_t i = 0; i < dynamicFingerprints->Length(); i++) {
if (base64Out.Equals((*dynamicFingerprints)[i])) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: found pin base_64 ='%s'\n", base64Out.get()));
certMatchesPinset = true;
return NS_OK;
}
}
}
return NS_OK;
}
/*
* Sets certListIntersectsPinset to true if a given chain matches any
* fingerprints from the given static fingerprints or the
* dynamicFingerprints array, or to false otherwise.
*/
static nsresult
EvalChain(const UniqueCERTCertList& certList,
const StaticFingerprints* fingerprints,
const nsTArray<nsCString>* dynamicFingerprints,
/*out*/ bool& certListIntersectsPinset)
{
certListIntersectsPinset = false;
CERTCertificate* currentCert;
if (!fingerprints && !dynamicFingerprints) {
MOZ_ASSERT(false, "Must pass in at least one type of pinset");
return NS_ERROR_FAILURE;
}
CERTCertListNode* node;
for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
node = CERT_LIST_NEXT(node)) {
currentCert = node->cert;
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: certArray subject: '%s'\n", currentCert->subjectName));
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: certArray issuer: '%s'\n", currentCert->issuerName));
nsresult rv = EvalCert(currentCert, fingerprints, dynamicFingerprints,
certListIntersectsPinset);
if (NS_FAILED(rv)) {
return rv;
}
if (certListIntersectsPinset) {
return NS_OK;
}
}
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug, ("pkpin: no matches found\n"));
return NS_OK;
}
/**
Comparator for the is public key pinned host.
*/
static int
TransportSecurityPreloadCompare(const void* key, const void* entry) {
auto keyStr = static_cast<const char*>(key);
auto preloadEntry = static_cast<const TransportSecurityPreload*>(entry);
return strcmp(keyStr, preloadEntry->mHost);
}
nsresult
PublicKeyPinningService::ChainMatchesPinset(const UniqueCERTCertList& certList,
const nsTArray<nsCString>& aSHA256keys,
/*out*/ bool& chainMatchesPinset)
{
return EvalChain(certList, nullptr, &aSHA256keys, chainMatchesPinset);
}
// Returns via one of the output parameters the most relevant pinning
// information that is valid for the given host at the given time.
// Dynamic pins are prioritized over static pins.
static nsresult
FindPinningInformation(const char* hostname, mozilla::pkix::Time time,
/*out*/ nsTArray<nsCString>& dynamicFingerprints,
/*out*/ TransportSecurityPreload*& staticFingerprints)
{
if (!hostname || hostname[0] == 0) {
return NS_ERROR_INVALID_ARG;
}
staticFingerprints = nullptr;
dynamicFingerprints.Clear();
nsCOMPtr<nsISiteSecurityService> sssService =
do_GetService(NS_SSSERVICE_CONTRACTID);
if (!sssService) {
return NS_ERROR_FAILURE;
}
TransportSecurityPreload* foundEntry = nullptr;
char* evalHost = const_cast<char*>(hostname);
char* evalPart;
// Notice how the (xx = strchr) prevents pins for unqualified domain names.
while (!foundEntry && (evalPart = strchr(evalHost, '.'))) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Querying pinsets for host: '%s'\n", evalHost));
// Attempt dynamic pins first
nsresult rv;
bool found;
bool includeSubdomains;
nsTArray<nsCString> pinArray;
rv = sssService->GetKeyPinsForHostname(evalHost, time, pinArray,
&includeSubdomains, &found);
if (NS_FAILED(rv)) {
return rv;
}
if (found && (evalHost == hostname || includeSubdomains)) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Found dyn match for host: '%s'\n", evalHost));
dynamicFingerprints = pinArray;
return NS_OK;
}
foundEntry = (TransportSecurityPreload *)bsearch(evalHost,
kPublicKeyPinningPreloadList,
sizeof(kPublicKeyPinningPreloadList) / sizeof(TransportSecurityPreload),
sizeof(TransportSecurityPreload),
TransportSecurityPreloadCompare);
if (foundEntry) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Found pinset for host: '%s'\n", evalHost));
if (evalHost != hostname) {
if (!foundEntry->mIncludeSubdomains) {
// Does not apply to this host, continue iterating
foundEntry = nullptr;
}
}
} else {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Didn't find pinset for host: '%s'\n", evalHost));
}
// Add one for '.'
evalHost = evalPart + 1;
}
if (foundEntry && foundEntry->pinset) {
if (time > TimeFromEpochInSeconds(kPreloadPKPinsExpirationTime /
PR_USEC_PER_SEC)) {
return NS_OK;
}
staticFingerprints = foundEntry;
}
return NS_OK;
}
// Returns true via the output parameter if the given certificate list meets
// pinning requirements for the given host at the given time. It must be the
// case that either there is an intersection between the set of hashes of
// subject public key info data in the list and the most relevant non-expired
// pinset for the host or there is no pinning information for the host.
static nsresult
CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname,
bool enforceTestMode, mozilla::pkix::Time time,
/*out*/ bool& chainHasValidPins)
{
chainHasValidPins = false;
if (!certList) {
return NS_ERROR_INVALID_ARG;
}
if (!hostname || hostname[0] == 0) {
return NS_ERROR_INVALID_ARG;
}
nsTArray<nsCString> dynamicFingerprints;
TransportSecurityPreload* staticFingerprints = nullptr;
nsresult rv = FindPinningInformation(hostname, time, dynamicFingerprints,
staticFingerprints);
// If we have no pinning information, the certificate chain trivially
// validates with respect to pinning.
if (dynamicFingerprints.Length() == 0 && !staticFingerprints) {
chainHasValidPins = true;
return NS_OK;
}
if (dynamicFingerprints.Length() > 0) {
return EvalChain(certList, nullptr, &dynamicFingerprints, chainHasValidPins);
}
if (staticFingerprints) {
bool enforceTestModeResult;
rv = EvalChain(certList, staticFingerprints->pinset, nullptr,
enforceTestModeResult);
if (NS_FAILED(rv)) {
return rv;
}
chainHasValidPins = enforceTestModeResult;
if (staticFingerprints->mTestMode) {
if (!enforceTestMode) {
chainHasValidPins = true;
}
}
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Pin check %s for %s host '%s' (mode=%s)\n",
enforceTestModeResult ? "passed" : "failed",
staticFingerprints->mIsMoz ? "mozilla" : "non-mozilla",
hostname, staticFingerprints->mTestMode ? "test" : "production"));
}
return NS_OK;
}
nsresult
PublicKeyPinningService::ChainHasValidPins(const UniqueCERTCertList& certList,
const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& chainHasValidPins)
{
chainHasValidPins = false;
if (!certList) {
return NS_ERROR_INVALID_ARG;
}
if (!hostname || hostname[0] == 0) {
return NS_ERROR_INVALID_ARG;
}
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
return CheckPinsForHostname(certList, canonicalizedHostname.get(),
enforceTestMode, time, chainHasValidPins);
}
nsresult
PublicKeyPinningService::HostHasPins(const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& hostHasPins)
{
hostHasPins = false;
nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
nsTArray<nsCString> dynamicFingerprints;
TransportSecurityPreload* staticFingerprints = nullptr;
nsresult rv = FindPinningInformation(canonicalizedHostname.get(), time,
dynamicFingerprints, staticFingerprints);
if (NS_FAILED(rv)) {
return rv;
}
if (dynamicFingerprints.Length() > 0) {
hostHasPins = true;
} else if (staticFingerprints) {
hostHasPins = !staticFingerprints->mTestMode || enforceTestMode;
}
return NS_OK;
}
nsAutoCString
PublicKeyPinningService::CanonicalizeHostname(const char* hostname)
{
nsAutoCString canonicalizedHostname(hostname);
ToLowerCase(canonicalizedHostname);
while (canonicalizedHostname.Length() > 0 &&
canonicalizedHostname.Last() == '.') {
canonicalizedHostname.Truncate(canonicalizedHostname.Length() - 1);
}
return canonicalizedHostname;
}

View file

@ -1,64 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PublicKeyPinningService_h
#define PublicKeyPinningService_h
#include "CertVerifier.h"
#include "ScopedNSSTypes.h"
#include "cert.h"
#include "nsString.h"
#include "nsTArray.h"
#include "pkix/Time.h"
namespace mozilla {
namespace psm {
class PublicKeyPinningService
{
public:
/**
* Sets chainHasValidPins to true if the given (host, certList) passes pinning
* checks, or to false otherwise. If the host is pinned, returns true via
* chainHasValidPins if one of the keys in the given certificate chain matches
* the pin set specified by the hostname. The certList's head is the EE cert
* and the tail is the trust anchor.
* Note: if an alt name is a wildcard, it won't necessarily find a pinset
* that would otherwise be valid for it
*/
static nsresult ChainHasValidPins(const UniqueCERTCertList& certList,
const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& chainHasValidPins);
/**
* Sets chainMatchesPinset to true if there is any intersection between the
* certificate list and the pins specified in the aSHA256keys array.
* Values passed in are assumed to be in base64 encoded form.
*/
static nsresult ChainMatchesPinset(const UniqueCERTCertList& certList,
const nsTArray<nsCString>& aSHA256keys,
/*out*/ bool& chainMatchesPinset);
/**
* Returns true via the output parameter hostHasPins if there is pinning
* information for the given host that is valid at the given time, and false
* otherwise.
*/
static nsresult HostHasPins(const char* hostname,
mozilla::pkix::Time time,
bool enforceTestMode,
/*out*/ bool& hostHasPins);
/**
* Given a hostname of potentially mixed case with potentially multiple
* trailing '.' (see bug 1118522), canonicalizes it to lowercase with no
* trailing '.'.
*/
static nsAutoCString CanonicalizeHostname(const char* hostname);
};
}} // namespace mozilla::psm
#endif // PublicKeyPinningService_h

View file

@ -425,11 +425,9 @@ CertErrorRunnable::CheckCertOverrides()
uint32_t remaining_display_errors = mCollectedErrors;
// If this is an HTTP Strict Transport Security host or a pinned host and the
// certificate is bad, don't allow overrides (RFC 6797 section 12.1,
// HPKP draft spec section 2.6).
// If this is an HTTP Strict Transport Security host, don't allow overrides
// RFC 6797 section 12.1.
bool strictTransportSecurityEnabled = false;
bool hasPinningInformation = false;
nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
if (!sss) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
@ -449,21 +447,10 @@ CertErrorRunnable::CheckCertOverrides()
return new SSLServerCertVerificationResult(mInfoObject,
mDefaultErrorCodeToReport);
}
nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HPKP,
mInfoObject->GetHostNameRaw(),
mProviderFlags,
nullptr,
&hasPinningInformation);
if (NS_FAILED(nsrv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p][%p] checking for HPKP failed\n", mFdForLogging, this));
return new SSLServerCertVerificationResult(mInfoObject,
mDefaultErrorCodeToReport);
}
if (!strictTransportSecurityEnabled && !hasPinningInformation) {
if (!strictTransportSecurityEnabled) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p][%p] no HSTS or HPKP - overrides allowed\n",
("[%p][%p] no HSTS - overrides allowed\n",
mFdForLogging, this));
nsCOMPtr<nsICertOverrideService> overrideService =
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
@ -497,7 +484,7 @@ CertErrorRunnable::CheckCertOverrides()
}
} else {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p][%p] HSTS or HPKP - no overrides allowed\n",
("[%p][%p] HSTS - no overrides allowed\n",
mFdForLogging, this));
}

View file

@ -1,712 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*****************************************************************************/
/* This is an automatically generated file. If you're not */
/* PublicKeyPinningService.cpp, you shouldn't be #including it. */
/*****************************************************************************/
#include <stdint.h>
/* AddTrust External Root */
static const char kAddTrust_External_RootFingerprint[] =
"lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=";
/* AddTrust Low-Value Services Root */
static const char kAddTrust_Low_Value_Services_RootFingerprint[] =
"BStocQfshOhzA4JFLsKidFF0XXSFpX1vRk4Np6G2ryo=";
/* AddTrust Public Services Root */
static const char kAddTrust_Public_Services_RootFingerprint[] =
"OGHXtpYfzbISBFb/b8LrdwSxp0G0vZM6g3b14ZFcppg=";
/* AddTrust Qualified Certificates Root */
static const char kAddTrust_Qualified_Certificates_RootFingerprint[] =
"xzr8Lrp3DQy8HuQfJStS6Kk9ErctzOwDHY2DnL+Bink=";
/* AffirmTrust Commercial */
static const char kAffirmTrust_CommercialFingerprint[] =
"bEZLmlsjOl6HTadlwm8EUBDS3c/0V5TwtMfkqvpQFJU=";
/* AffirmTrust Networking */
static const char kAffirmTrust_NetworkingFingerprint[] =
"lAcq0/WPcPkwmOWl9sBMlscQvYSdgxhJGa6Q64kK5AA=";
/* AffirmTrust Premium */
static const char kAffirmTrust_PremiumFingerprint[] =
"x/Q7TPW3FWgpT4IrU3YmBfbd0Vyt7Oc56eLDy6YenWc=";
/* AffirmTrust Premium ECC */
static const char kAffirmTrust_Premium_ECCFingerprint[] =
"MhmwkRT/SVo+tusAwu/qs0ACrl8KVsdnnqCHo/oDfk8=";
/* Baltimore CyberTrust Root */
static const char kBaltimore_CyberTrust_RootFingerprint[] =
"Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o=";
/* COMODO Certification Authority */
static const char kCOMODO_Certification_AuthorityFingerprint[] =
"AG1751Vd2CAmRCxPGieoDomhmJy4ezREjtIZTBgZbV4=";
/* COMODO ECC Certification Authority */
static const char kCOMODO_ECC_Certification_AuthorityFingerprint[] =
"58qRu/uxh4gFezqAcERupSkRYBlBAvfcw7mEjGPLnNU=";
/* COMODO RSA Certification Authority */
static const char kCOMODO_RSA_Certification_AuthorityFingerprint[] =
"grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=";
/* Comodo AAA Services root */
static const char kComodo_AAA_Services_rootFingerprint[] =
"vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=";
/* Comodo Secure Services root */
static const char kComodo_Secure_Services_rootFingerprint[] =
"RpHL/ehKa2BS3b4VK7DCFq4lqG5XR4E9vA8UfzOFcL4=";
/* Comodo Trusted Services root */
static const char kComodo_Trusted_Services_rootFingerprint[] =
"4tiR77c4ZpEF1TDeXtcuKyrD9KZweLU0mz/ayklvXrg=";
/* Cybertrust Global Root */
static const char kCybertrust_Global_RootFingerprint[] =
"foeCwVDOOVL4AuY2AjpdPpW7XWjjPoWtsroXgSXOvxU=";
/* DST Root CA X3 */
static const char kDST_Root_CA_X3Fingerprint[] =
"Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=";
/* DigiCert Assured ID Root CA */
static const char kDigiCert_Assured_ID_Root_CAFingerprint[] =
"I/Lt/z7ekCWanjD0Cvj5EqXls2lOaThEA0H2Bg4BT/o=";
/* DigiCert Assured ID Root G2 */
static const char kDigiCert_Assured_ID_Root_G2Fingerprint[] =
"8ca6Zwz8iOTfUpc8rkIPCgid1HQUT+WAbEIAZOFZEik=";
/* DigiCert Assured ID Root G3 */
static const char kDigiCert_Assured_ID_Root_G3Fingerprint[] =
"Fe7TOVlLME+M+Ee0dzcdjW/sYfTbKwGvWJ58U7Ncrkw=";
/* DigiCert Global Root CA */
static const char kDigiCert_Global_Root_CAFingerprint[] =
"r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=";
/* DigiCert Global Root G2 */
static const char kDigiCert_Global_Root_G2Fingerprint[] =
"i7WTqTvh0OioIruIfFR4kMPnBqrS2rdiVPl/s2uC/CY=";
/* DigiCert Global Root G3 */
static const char kDigiCert_Global_Root_G3Fingerprint[] =
"uUwZgwDOxcBXrQcntwu+kYFpkiVkOaezL0WYEZ3anJc=";
/* DigiCert High Assurance EV Root CA */
static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[] =
"WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=";
/* DigiCert Trusted Root G4 */
static const char kDigiCert_Trusted_Root_G4Fingerprint[] =
"Wd8xe/qfTwq3ylFNd3IpaqLHZbh2ZNCLluVzmeNkcpw=";
/* End Entity Test Cert */
static const char kEnd_Entity_Test_CertFingerprint[] =
"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
/* Entrust Root Certification Authority */
static const char kEntrust_Root_Certification_AuthorityFingerprint[] =
"bb+uANN7nNc/j7R95lkXrwDg3d9C286sIMF8AnXuIJU=";
/* Entrust Root Certification Authority - EC1 */
static const char kEntrust_Root_Certification_Authority___EC1Fingerprint[] =
"/qK31kX7pz11PB7Jp4cMQOH3sMVh6Se5hb9xGGbjbyI=";
/* Entrust Root Certification Authority - G2 */
static const char kEntrust_Root_Certification_Authority___G2Fingerprint[] =
"du6FkDdMcVQ3u8prumAo6t3i3G27uMP2EOhR8R0at/U=";
/* Entrust.net Premium 2048 Secure Server CA */
static const char kEntrust_net_Premium_2048_Secure_Server_CAFingerprint[] =
"HqPF5D7WbC2imDpCpKebHpBnhs6fG1hiFBmgBGOofTg=";
/* FacebookBackup */
static const char kFacebookBackupFingerprint[] =
"q4PO2G2cbkZhZ82+JgmRUyGMoAeozA+BSXVXQWB8XWQ=";
/* GOOGLE_PIN_COMODORSADomainValidationSecureServerCA */
static const char kGOOGLE_PIN_COMODORSADomainValidationSecureServerCAFingerprint[] =
"klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=";
/* GOOGLE_PIN_DigiCertECCSecureServerCA */
static const char kGOOGLE_PIN_DigiCertECCSecureServerCAFingerprint[] =
"PZXN3lRAy+8tBKk2Ox6F7jIlnzr2Yzmwqc3JnyfXoCw=";
/* GOOGLE_PIN_DigiCertSHA2HighAssuranceServerCA */
static const char kGOOGLE_PIN_DigiCertSHA2HighAssuranceServerCAFingerprint[] =
"k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws=";
/* GOOGLE_PIN_Entrust_SSL */
static const char kGOOGLE_PIN_Entrust_SSLFingerprint[] =
"nsxRNo6G40YPZsKV5JQt1TCA8nseQQr/LRqp1Oa8fnw=";
/* GOOGLE_PIN_GTECyberTrustGlobalRoot */
static const char kGOOGLE_PIN_GTECyberTrustGlobalRootFingerprint[] =
"EGn6R6CqT4z3ERscrqNl7q7RC//zJmDe9uBhS/rnCHU=";
/* GOOGLE_PIN_GoDaddySecure */
static const char kGOOGLE_PIN_GoDaddySecureFingerprint[] =
"MrZLZnJ6IGPkBm87lYywqu5Xal7O/ZUzmbuIdHMdlYc=";
/* GOOGLE_PIN_GoogleG2 */
static const char kGOOGLE_PIN_GoogleG2Fingerprint[] =
"7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=";
/* GOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4 */
static const char kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint[] =
"sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis=";
/* GOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3 */
static const char kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint[] =
"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=";
/* GOOGLE_PIN_RapidSSL */
static const char kGOOGLE_PIN_RapidSSLFingerprint[] =
"lT09gPUeQfbYrlxRtpsHrjDblj9Rpz+u7ajfCrg4qDM=";
/* GOOGLE_PIN_SymantecClass3EVG3 */
static const char kGOOGLE_PIN_SymantecClass3EVG3Fingerprint[] =
"gMxWOrX4PMQesK9qFNbYBxjBfjUvlkn/vN1n+L9lE5E=";
/* GOOGLE_PIN_UTNDATACorpSGC */
static const char kGOOGLE_PIN_UTNDATACorpSGCFingerprint[] =
"QAL80xHQczFWfnG82XHkYEjI3OjRZZcRdTs9qiommvo=";
/* GOOGLE_PIN_VeriSignClass1 */
static const char kGOOGLE_PIN_VeriSignClass1Fingerprint[] =
"LclHC+Y+9KzxvYKGCUArt7h72ZY4pkOTTohoLRvowwg=";
/* GOOGLE_PIN_VeriSignClass2_G2 */
static const char kGOOGLE_PIN_VeriSignClass2_G2Fingerprint[] =
"2oALgLKofTmeZvoZ1y/fSZg7R9jPMix8eVA6DH4o/q8=";
/* GOOGLE_PIN_VeriSignClass3_G2 */
static const char kGOOGLE_PIN_VeriSignClass3_G2Fingerprint[] =
"AjyBzOjnxk+pQtPBUEhwfTXZu1uH9PVExb8bxWQ68vo=";
/* GOOGLE_PIN_VeriSignClass4_G3 */
static const char kGOOGLE_PIN_VeriSignClass4_G3Fingerprint[] =
"VnuCEf0g09KD7gzXzgZyy52ZvFtIeljJ1U7Gf3fUqPU=";
/* GeoTrust Global CA */
static const char kGeoTrust_Global_CAFingerprint[] =
"h6801m+z8v3zbgkRHpq6L29Esgfzhj89C1SyUCOQmqU=";
/* GeoTrust Global CA 2 */
static const char kGeoTrust_Global_CA_2Fingerprint[] =
"F3VaXClfPS1y5vAxofB/QAxYi55YKyLxfq4xoVkNEYU=";
/* GeoTrust Primary Certification Authority */
static const char kGeoTrust_Primary_Certification_AuthorityFingerprint[] =
"SQVGZiOrQXi+kqxcvWWE96HhfydlLVqFr4lQTqI5qqo=";
/* GeoTrust Primary Certification Authority - G2 */
static const char kGeoTrust_Primary_Certification_Authority___G2Fingerprint[] =
"vPtEqrmtAhAVcGtBIep2HIHJ6IlnWQ9vlK50TciLePs=";
/* GeoTrust Primary Certification Authority - G3 */
static const char kGeoTrust_Primary_Certification_Authority___G3Fingerprint[] =
"q5hJUnat8eyv8o81xTBIeB5cFxjaucjmelBPT2pRMo8=";
/* GeoTrust Universal CA */
static const char kGeoTrust_Universal_CAFingerprint[] =
"lpkiXF3lLlbN0y3y6W0c/qWqPKC7Us2JM8I7XCdEOCA=";
/* GeoTrust Universal CA 2 */
static const char kGeoTrust_Universal_CA_2Fingerprint[] =
"fKoDRlEkWQxgHlZ+UhSOlSwM/+iQAFMP4NlbbVDqrkE=";
/* GlobalSign ECC Root CA - R4 */
static const char kGlobalSign_ECC_Root_CA___R4Fingerprint[] =
"CLOmM1/OXvSPjw5UOYbAf9GKOxImEp9hhku9W90fHMk=";
/* GlobalSign ECC Root CA - R5 */
static const char kGlobalSign_ECC_Root_CA___R5Fingerprint[] =
"fg6tdrtoGdwvVFEahDVPboswe53YIFjqbABPAdndpd8=";
/* GlobalSign Root CA */
static const char kGlobalSign_Root_CAFingerprint[] =
"K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q=";
/* GlobalSign Root CA - R2 */
static const char kGlobalSign_Root_CA___R2Fingerprint[] =
"iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0=";
/* GlobalSign Root CA - R3 */
static const char kGlobalSign_Root_CA___R3Fingerprint[] =
"cGuxAXyFXFkWm61cF4HPWX8S0srS9j0aSqN0k4AP+4A=";
/* Go Daddy Class 2 CA */
static const char kGo_Daddy_Class_2_CAFingerprint[] =
"VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=";
/* Go Daddy Root Certificate Authority - G2 */
static const char kGo_Daddy_Root_Certificate_Authority___G2Fingerprint[] =
"Ko8tivDrEjiY90yGasP6ZpBU4jwXvHqVvQI0GS3GNdA=";
/* GoogleBackup2048 */
static const char kGoogleBackup2048Fingerprint[] =
"IPMbDAjLVSGntGO3WP53X/zilCVndez5YJ2+vJvhJsA=";
/* SpiderOak2 */
static const char kSpiderOak2Fingerprint[] =
"7Y3UnxbffL8aFPXsOJBpGasgpDmngpIhAxGKdQRklQQ=";
/* SpiderOak3 */
static const char kSpiderOak3Fingerprint[] =
"LkER54vOdlygpTsbYvlpMq1CE/lDAG1AP9xmdtwvV2A=";
/* Starfield Class 2 CA */
static const char kStarfield_Class_2_CAFingerprint[] =
"FfFKxFycfaIz00eRZOgTf+Ne4POK6FgYPwhBDqgqxLQ=";
/* Starfield Root Certificate Authority - G2 */
static const char kStarfield_Root_Certificate_Authority___G2Fingerprint[] =
"gI1os/q0iEpflxrOfRBVDXqVoWN3Tz7Dav/7IT++THQ=";
/* Swehack */
static const char kSwehackFingerprint[] =
"FdaffE799rVb3oyAuhJ2mBW/XJwD07Uajb2G6YwSAEw=";
/* SwehackBackup */
static const char kSwehackBackupFingerprint[] =
"z6cuswA6E1vgFkCjUsbEYo0Lf3aP8M8YOvwkoiGzDCo=";
/* TestSPKI */
static const char kTestSPKIFingerprint[] =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
/* Tor1 */
static const char kTor1Fingerprint[] =
"bYz9JTDk89X3qu3fgswG+lBQso5vI0N1f0Rx4go4nLo=";
/* Tor2 */
static const char kTor2Fingerprint[] =
"xXCxhTdn7uxXneJSbQCqoAvuW3ZtQl2pDVTf2sewS8w=";
/* Tor3 */
static const char kTor3Fingerprint[] =
"CleC1qwUR8JPgH1nXvSe2VHxDe5/KfNs96EusbfSOfo=";
/* TumblrBackup */
static const char kTumblrBackupFingerprint[] =
"avlD96PLERV78IN1fD+ab5cupkUDD9wTZWJjHX6VC9w=";
/* Twitter1 */
static const char kTwitter1Fingerprint[] =
"vU9M48LzD/CF34wE5PPf4nBwRyosy06X21J0ap8yS5s=";
/* USERTrust ECC Certification Authority */
static const char kUSERTrust_ECC_Certification_AuthorityFingerprint[] =
"ICGRfpgmOUXIWcQ/HXPLQTkFPEFPoDyjvH7ohhQpjzs=";
/* USERTrust RSA Certification Authority */
static const char kUSERTrust_RSA_Certification_AuthorityFingerprint[] =
"x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=";
/* UTN USERFirst Email Root CA */
static const char kUTN_USERFirst_Email_Root_CAFingerprint[] =
"Laj56jRU0hFGRko/nQKNxMf7tXscUsc8KwVyovWZotM=";
/* UTN USERFirst Hardware Root CA */
static const char kUTN_USERFirst_Hardware_Root_CAFingerprint[] =
"TUDnr0MEoJ3of7+YliBMBVFB4/gJsv5zO7IxD9+YoWI=";
/* UTN USERFirst Object Root CA */
static const char kUTN_USERFirst_Object_Root_CAFingerprint[] =
"D+FMJksXu28NZT56cOs2Pb9UvhWAOe3a5cJXEd9IwQM=";
/* VeriSign Class 3 Public Primary Certification Authority - G4 */
static const char kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint[] =
"UZJDjsNp1+4M5x9cbbdflB779y5YRBcV6Z6rBMLIrO4=";
/* VeriSign Class 3 Public Primary Certification Authority - G5 */
static const char kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint[] =
"JbQbUG5JMJUoI6brnx0x3vZF6jilxsapbXGVfjhN8Fg=";
/* VeriSign Universal Root Certification Authority */
static const char kVeriSign_Universal_Root_Certification_AuthorityFingerprint[] =
"lnsM2T/O9/J84sJFdnrpsFp3awZJ+ZZbYpCWhGloaHI=";
/* Verisign Class 1 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint[] =
"IgduWu9Eu5pBaii30cRDItcFn2D+/6XK9sW+hEeJEwM=";
/* Verisign Class 2 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint[] =
"cAajgxHlj7GTSEIzIYIQxmEloOSoJq7VOaxWHfv72QM=";
/* Verisign Class 3 Public Primary Certification Authority - G3 */
static const char kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint[] =
"SVqWumuteCQHvVIaALrOZXuzVVVeS7f4FGxxu6V+es4=";
/* YahooBackup1 */
static const char kYahooBackup1Fingerprint[] =
"2fRAUXyxl4A1/XHrKNBmc8bTkzA7y4FB/GLJuNAzCqY=";
/* YahooBackup2 */
static const char kYahooBackup2Fingerprint[] =
"dolnbtzEBnELx/9lOEQ22e6OZO/QNb6VSSX2XHA3E7A=";
/* thawte Primary Root CA */
static const char kthawte_Primary_Root_CAFingerprint[] =
"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=";
/* thawte Primary Root CA - G2 */
static const char kthawte_Primary_Root_CA___G2Fingerprint[] =
"Z9xPMvoQ59AaeaBzqgyeAhLsL/w9d54Kp/nA8OHCyJM=";
/* thawte Primary Root CA - G3 */
static const char kthawte_Primary_Root_CA___G3Fingerprint[] =
"GQbGEk27Q4V40A4GbVBUxsN/D6YCjAVUXgmU7drshik=";
/* Pinsets are each an ordered list by the actual value of the fingerprint */
struct StaticFingerprints {
const size_t size;
const char* const* data;
};
/* PreloadedHPKPins.json pinsets */
static const char* const kPinset_google_root_pems_Data[] = {
kEntrust_Root_Certification_Authority___EC1Fingerprint,
kComodo_Trusted_Services_rootFingerprint,
kCOMODO_ECC_Certification_AuthorityFingerprint,
kDigiCert_Assured_ID_Root_G2Fingerprint,
kCOMODO_Certification_AuthorityFingerprint,
kAddTrust_Low_Value_Services_RootFingerprint,
kGlobalSign_ECC_Root_CA___R4Fingerprint,
kGeoTrust_Global_CA_2Fingerprint,
kDigiCert_Assured_ID_Root_G3Fingerprint,
kStarfield_Class_2_CAFingerprint,
kthawte_Primary_Root_CA___G3Fingerprint,
kthawte_Primary_Root_CAFingerprint,
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kUSERTrust_ECC_Certification_AuthorityFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGlobalSign_Root_CAFingerprint,
kGo_Daddy_Root_Certificate_Authority___G2Fingerprint,
kAffirmTrust_Premium_ECCFingerprint,
kAddTrust_Public_Services_RootFingerprint,
kComodo_Secure_Services_rootFingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kUTN_USERFirst_Hardware_Root_CAFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kGo_Daddy_Class_2_CAFingerprint,
kDigiCert_Trusted_Root_G4Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kthawte_Primary_Root_CA___G2Fingerprint,
kAffirmTrust_CommercialFingerprint,
kEntrust_Root_Certification_AuthorityFingerprint,
kGlobalSign_Root_CA___R3Fingerprint,
kEntrust_Root_Certification_Authority___G2Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGlobalSign_ECC_Root_CA___R5Fingerprint,
kCybertrust_Global_RootFingerprint,
kStarfield_Root_Certificate_Authority___G2Fingerprint,
kCOMODO_RSA_Certification_AuthorityFingerprint,
kGeoTrust_Global_CAFingerprint,
kDigiCert_Global_Root_G2Fingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
kAffirmTrust_NetworkingFingerprint,
kAddTrust_External_RootFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kDigiCert_Global_Root_G3Fingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kComodo_AAA_Services_rootFingerprint,
kAffirmTrust_PremiumFingerprint,
kUSERTrust_RSA_Certification_AuthorityFingerprint,
kAddTrust_Qualified_Certificates_RootFingerprint,
};
static const StaticFingerprints kPinset_google_root_pems = {
sizeof(kPinset_google_root_pems_Data) / sizeof(const char*),
kPinset_google_root_pems_Data
};
static const char* const kPinset_mozilla_Data[] = {
kGeoTrust_Global_CA_2Fingerprint,
kthawte_Primary_Root_CA___G3Fingerprint,
kthawte_Primary_Root_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kthawte_Primary_Root_CA___G2Fingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
};
static const StaticFingerprints kPinset_mozilla = {
sizeof(kPinset_mozilla_Data) / sizeof(const char*),
kPinset_mozilla_Data
};
static const char* const kPinset_mozilla_services_Data[] = {
kDigiCert_Global_Root_CAFingerprint,
};
static const StaticFingerprints kPinset_mozilla_services = {
sizeof(kPinset_mozilla_services_Data) / sizeof(const char*),
kPinset_mozilla_services_Data
};
static const char* const kPinset_mozilla_test_Data[] = {
kEnd_Entity_Test_CertFingerprint,
};
static const StaticFingerprints kPinset_mozilla_test = {
sizeof(kPinset_mozilla_test_Data) / sizeof(const char*),
kPinset_mozilla_test_Data
};
/* Chrome static pinsets */
static const char* const kPinset_test_Data[] = {
kTestSPKIFingerprint,
};
static const StaticFingerprints kPinset_test = {
sizeof(kPinset_test_Data) / sizeof(const char*),
kPinset_test_Data
};
static const char* const kPinset_google_Data[] = {
kGOOGLE_PIN_GoogleG2Fingerprint,
kGoogleBackup2048Fingerprint,
kGeoTrust_Global_CAFingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
};
static const StaticFingerprints kPinset_google = {
sizeof(kPinset_google_Data) / sizeof(const char*),
kPinset_google_Data
};
static const char* const kPinset_tor_Data[] = {
kTor3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint,
kTor1Fingerprint,
kGOOGLE_PIN_RapidSSLFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint,
kTor2Fingerprint,
};
static const StaticFingerprints kPinset_tor = {
sizeof(kPinset_tor_Data) / sizeof(const char*),
kPinset_tor_Data
};
static const char* const kPinset_twitterCom_Data[] = {
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kGOOGLE_PIN_VeriSignClass3_G2Fingerprint,
kGeoTrust_Global_CA_2Fingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGOOGLE_PIN_VeriSignClass1Fingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kGOOGLE_PIN_VeriSignClass4_G3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kTwitter1Fingerprint,
};
static const StaticFingerprints kPinset_twitterCom = {
sizeof(kPinset_twitterCom_Data) / sizeof(const char*),
kPinset_twitterCom_Data
};
static const char* const kPinset_twitterCDN_Data[] = {
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kComodo_Trusted_Services_rootFingerprint,
kCOMODO_Certification_AuthorityFingerprint,
kGOOGLE_PIN_VeriSignClass3_G2Fingerprint,
kAddTrust_Low_Value_Services_RootFingerprint,
kUTN_USERFirst_Object_Root_CAFingerprint,
kGOOGLE_PIN_GTECyberTrustGlobalRootFingerprint,
kGeoTrust_Global_CA_2Fingerprint,
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVerisign_Class_1_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kGlobalSign_Root_CAFingerprint,
kUTN_USERFirst_Email_Root_CAFingerprint,
kGOOGLE_PIN_VeriSignClass1Fingerprint,
kAddTrust_Public_Services_RootFingerprint,
kGOOGLE_PIN_UTNDATACorpSGCFingerprint,
kComodo_Secure_Services_rootFingerprint,
kGeoTrust_Primary_Certification_AuthorityFingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kUTN_USERFirst_Hardware_Root_CAFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kGOOGLE_PIN_VeriSignClass4_G3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kEntrust_Root_Certification_AuthorityFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGlobalSign_Root_CA___R3Fingerprint,
kEntrust_Root_Certification_Authority___G2Fingerprint,
kGeoTrust_Universal_CA_2Fingerprint,
kGeoTrust_Global_CAFingerprint,
kGlobalSign_Root_CA___R2Fingerprint,
kAddTrust_External_RootFingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kGeoTrust_Universal_CAFingerprint,
kGOOGLE_PIN_Entrust_SSLFingerprint,
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
kComodo_AAA_Services_rootFingerprint,
kTwitter1Fingerprint,
kAddTrust_Qualified_Certificates_RootFingerprint,
};
static const StaticFingerprints kPinset_twitterCDN = {
sizeof(kPinset_twitterCDN_Data) / sizeof(const char*),
kPinset_twitterCDN_Data
};
static const char* const kPinset_dropbox_Data[] = {
kEntrust_Root_Certification_Authority___EC1Fingerprint,
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kGo_Daddy_Root_Certificate_Authority___G2Fingerprint,
kGOOGLE_PIN_GoDaddySecureFingerprint,
kGo_Daddy_Class_2_CAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kEntrust_Root_Certification_AuthorityFingerprint,
kEntrust_Root_Certification_Authority___G2Fingerprint,
kDigiCert_Global_Root_CAFingerprint,
};
static const StaticFingerprints kPinset_dropbox = {
sizeof(kPinset_dropbox_Data) / sizeof(const char*),
kPinset_dropbox_Data
};
static const char* const kPinset_facebook_Data[] = {
kGOOGLE_PIN_DigiCertECCSecureServerCAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGOOGLE_PIN_SymantecClass3EVG3Fingerprint,
kFacebookBackupFingerprint,
};
static const StaticFingerprints kPinset_facebook = {
sizeof(kPinset_facebook_Data) / sizeof(const char*),
kPinset_facebook_Data
};
static const char* const kPinset_spideroak_Data[] = {
kSpiderOak2Fingerprint,
kSpiderOak3Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kGeoTrust_Global_CAFingerprint,
};
static const StaticFingerprints kPinset_spideroak = {
sizeof(kPinset_spideroak_Data) / sizeof(const char*),
kPinset_spideroak_Data
};
static const char* const kPinset_yahoo_Data[] = {
kYahooBackup1Fingerprint,
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kDigiCert_Trusted_Root_G4Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kYahooBackup2Fingerprint,
kDigiCert_Global_Root_G2Fingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kDigiCert_Global_Root_CAFingerprint,
kDigiCert_Global_Root_G3Fingerprint,
};
static const StaticFingerprints kPinset_yahoo = {
sizeof(kPinset_yahoo_Data) / sizeof(const char*),
kPinset_yahoo_Data
};
static const char* const kPinset_swehackCom_Data[] = {
kSwehackFingerprint,
kDST_Root_CA_X3Fingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint,
kGOOGLE_PIN_COMODORSADomainValidationSecureServerCAFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint,
kSwehackBackupFingerprint,
};
static const StaticFingerprints kPinset_swehackCom = {
sizeof(kPinset_swehackCom_Data) / sizeof(const char*),
kPinset_swehackCom_Data
};
static const char* const kPinset_ncsccs_Data[] = {
kCOMODO_ECC_Certification_AuthorityFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityPrimary_X1_X3Fingerprint,
kCOMODO_RSA_Certification_AuthorityFingerprint,
kAddTrust_External_RootFingerprint,
kDigiCert_Global_Root_CAFingerprint,
kGOOGLE_PIN_LetsEncryptAuthorityBackup_X2_X4Fingerprint,
};
static const StaticFingerprints kPinset_ncsccs = {
sizeof(kPinset_ncsccs_Data) / sizeof(const char*),
kPinset_ncsccs_Data
};
static const char* const kPinset_tumblr_Data[] = {
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kTumblrBackupFingerprint,
kGOOGLE_PIN_DigiCertSHA2HighAssuranceServerCAFingerprint,
};
static const StaticFingerprints kPinset_tumblr = {
sizeof(kPinset_tumblr_Data) / sizeof(const char*),
kPinset_tumblr_Data
};
/* Domainlist */
struct TransportSecurityPreload {
const char* mHost;
const bool mIncludeSubdomains;
const bool mTestMode;
const bool mIsMoz;
const int32_t mId;
const StaticFingerprints* pinset;
};
/* Sort hostnames for binary search. */
static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "exclude-subdomains.pinning.example.com", false, false, false, 0, &kPinset_mozilla_test },
{ "include-subdomains.pinning.example.com", true, false, false, -1, &kPinset_mozilla_test },
{ "test-mode.pinning.example.com", true, true, false, -1, &kPinset_mozilla_test },
};
// Pinning Preload List Length = 3;
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1609459199000000);

View file

@ -127,13 +127,11 @@ UNIFIED_SOURCES += [
'nsSecureBrowserUIImpl.cpp',
'nsSecurityHeaderParser.cpp',
'NSSErrorsService.cpp',
'nsSiteSecurityService.cpp',
'nsSSLSocketProvider.cpp',
'nsSSLStatus.cpp',
'nsTLSSocketProvider.cpp',
'PSMContentListener.cpp',
'PSMRunnable.cpp',
'PublicKeyPinningService.cpp',
'SecretDecoderRing.cpp',
'SharedSSLState.cpp',
'SSLServerCertVerification.cpp',
@ -141,6 +139,10 @@ UNIFIED_SOURCES += [
'WeakCryptoOverride.cpp',
]
# nsSiteSecurityService exceeded the obj file sections limit because of the
# HSTS preload list so it cannot be built in UNIFIED mode.
SOURCES += ['nsSiteSecurityService.cpp']
IPDL_SOURCES += [
'PPSMContentDownloader.ipdl',
]

View file

@ -23,11 +23,11 @@ namespace mozilla
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
[ref] native mozillaPkixTime(mozilla::pkix::Time);
[scriptable, uuid(233908bd-6741-4474-a6e1-f298c6ce9eaf)]
[scriptable, uuid(91ea3803-9c79-45d9-97bf-88bc80269236)]
interface nsISiteSecurityService : nsISupports
{
const uint32_t HEADER_HSTS = 0;
const uint32_t HEADER_HPKP = 1;
const uint32_t HEADER_HPKP = 1; /* no longer used */
const uint32_t HEADER_OMS = 2;
const uint32_t Success = 0;
@ -39,10 +39,10 @@ interface nsISiteSecurityService : nsISupports
const uint32_t ERROR_INVALID_MAX_AGE = 6;
const uint32_t ERROR_MULTIPLE_INCLUDE_SUBDOMAINS = 7;
const uint32_t ERROR_INVALID_INCLUDE_SUBDOMAINS = 8;
const uint32_t ERROR_INVALID_PIN = 9;
const uint32_t ERROR_MULTIPLE_REPORT_URIS = 10;
const uint32_t ERROR_PINSET_DOES_NOT_MATCH_CHAIN = 11;
const uint32_t ERROR_NO_BACKUP_PIN = 12;
const uint32_t ERROR_INVALID_PIN = 9; /* no longer used */
const uint32_t ERROR_MULTIPLE_REPORT_URIS = 10; /* no longer used */
const uint32_t ERROR_PINSET_DOES_NOT_MATCH_CHAIN = 11; /* no longer used */
const uint32_t ERROR_NO_BACKUP_PIN = 12; /* no longer used */
const uint32_t ERROR_COULD_NOT_SAVE_STATE = 13;
const uint32_t ERROR_ROOT_NOT_BUILT_IN = 14;
@ -106,13 +106,10 @@ interface nsISiteSecurityService : nsISupports
* @param aURI the URI of the target host
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
* @param force if set, forces no-HSTS state by writing a knockout value,
* overriding any preload list state
*/
void removeState(in uint32_t aType,
in nsIURI aURI,
in uint32_t aFlags,
[optional] in boolean force);
in uint32_t aFlags);
/**
* See isSecureURI
@ -153,47 +150,6 @@ interface nsISiteSecurityService : nsISupports
* settings.
*/
void clearAll();
/**
* Removes all preloaded security state.
*/
void clearPreloads();
/**
* Returns an array of sha256-hashed key pins for the given domain, if any.
* If these pins also apply to subdomains of the given domain,
* aIncludeSubdomains will be true. Pins returned are only for non-built-in
* pin entries.
*
* @param aHostname the hosname (punycode) to be queried about
* @param the time at which the pins should be valid. This is in
mozilla::pkix::Time which uses internally seconds since 0 AD.
* @param aPinArray the set of sha256-hashed key pins for the given domain
* @param aIncludeSubdomains true if the pins apply to subdomains of the
* given domain
*/
[noscript] boolean getKeyPinsForHostname(in string aHostname,
in mozillaPkixTime evalTime,
out nsCStringTArrayRef aPinArray,
out boolean aIncludeSubdomains);
/**
* Set public-key pins for a host. The resulting pins will be permanent
* and visible from private and non-private contexts. These pins replace
* any already set by this mechanism or those built-in to Gecko.
*
* @param aHost the hostname (punycode) that pins will apply to
* @param aIncludeSubdomains whether these pins also apply to subdomains
* @param aExpires the time this pin should expire (millis since epoch)
* @param aPinCount number of keys being pinnned
* @param aSha256Pins array of hashed key fingerprints (SHA-256, base64)
* @param aIsPreload are these key pins for a preload entry? (false by
* default)
*/
boolean setKeyPins(in string aHost, in boolean aIncludeSubdomains,
in int64_t aExpires, in unsigned long aPinCount,
[array, size_is(aPinCount)] in string aSha256Pins,
[optional] in boolean aIsPreload);
};
%{C++

View file

@ -12,6 +12,9 @@
#include "SharedSSLState.h"
#include "cert.h"
#include "certdb.h"
#ifdef MOZ_SECURITY_SQLSTORE
#include "mozStorageCID.h"
#endif
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "mozilla/Preferences.h"
@ -1703,16 +1706,25 @@ GetNSSProfilePath(nsAutoCString& aProfilePath)
}
#if defined(XP_WIN)
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
nsCOMPtr<nsILocalFileWin> profileFileWin(do_QueryInterface(profileFile));
if (!profileFileWin) {
MOZ_LOG(gPIPNSSLog, LogLevel::Error,
("Could not get nsILocalFileWin for profile directory.\n"));
return NS_ERROR_FAILURE;
}
rv = profileFileWin->GetNativeCanonicalPath(aProfilePath);
#ifdef MOZ_SECURITY_SQLSTORE
// SQLite always takes UTF-8 file paths regardless of the current system
// code page.
nsAutoString u16ProfilePath;
rv = profileFileWin->GetCanonicalPath(u16ProfilePath);
CopyUTF16toUTF8(u16ProfilePath, aProfilePath);
#else
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
rv = profileFileWin->GetNativeCanonicalPath(aProfilePath);
#endif
#else
// On non-Windows, just get the native profile path.
rv = profileFile->GetNativePath(aProfilePath);
#endif
@ -1970,6 +1982,14 @@ nsNSSComponent::Init()
return NS_ERROR_NOT_SAME_THREAD;
}
#ifdef MOZ_SECURITY_SQLSTORE
// To avoid an sqlite3_config race in NSS init, we require the storage service to get initialized first.
nsCOMPtr<nsISupports> storageService = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
if (!storageService) {
return NS_ERROR_NOT_AVAILABLE;
}
#endif
nsresult rv = NS_OK;
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -25,19 +25,9 @@
#include "mozilla/Logging.h"
#include "prnetdb.h"
#include "prprf.h"
#include "PublicKeyPinningService.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"
// A note about the preload list:
// When a site specifically disables HSTS by sending a header with
// 'max-age: 0', we keep a "knockout" value that means "we have no information
// regarding the HSTS state of this host" (any ancestor of "this host" can still
// influence its HSTS status via include subdomains, however).
// This prevents the preload list from overriding the site's current
// desired HSTS status.
#include "nsSTSPreloadList.inc"
using namespace mozilla;
using namespace mozilla::psm;
@ -95,124 +85,31 @@ SiteHSTSState::ToString(nsCString& aString)
aString.AppendInt(static_cast<uint32_t>(mHSTSIncludeSubdomains));
}
////////////////////////////////////////////////////////////////////////////////
static bool
stringIsBase64EncodingOf256bitValue(nsCString& encodedString) {
nsAutoCString binaryValue;
nsresult rv = mozilla::Base64Decode(encodedString, binaryValue);
if (NS_FAILED(rv)) {
return false;
}
if (binaryValue.Length() != SHA256_LENGTH) {
return false;
}
return true;
}
SiteHPKPState::SiteHPKPState()
: mExpireTime(0)
, mState(SecurityPropertyUnset)
, mIncludeSubdomains(false)
{
}
SiteHPKPState::SiteHPKPState(nsCString& aStateString)
: mExpireTime(0)
, mState(SecurityPropertyUnset)
, mIncludeSubdomains(false)
{
uint32_t hpkpState = 0;
uint32_t hpkpIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
const uint32_t MaxMergedHPKPPinSize = 1024;
char mergedHPKPins[MaxMergedHPKPPinSize];
memset(mergedHPKPins, 0, MaxMergedHPKPPinSize);
if (aStateString.Length() >= MaxMergedHPKPPinSize) {
SSSLOG(("SSS: Cannot parse PKPState string, too large\n"));
return;
}
int32_t matches = PR_sscanf(aStateString.get(), "%lld,%lu,%lu,%s",
&mExpireTime, &hpkpState,
&hpkpIncludeSubdomains, mergedHPKPins);
bool valid = (matches == 4 &&
(hpkpIncludeSubdomains == 0 || hpkpIncludeSubdomains == 1) &&
((SecurityPropertyState)hpkpState == SecurityPropertyUnset ||
(SecurityPropertyState)hpkpState == SecurityPropertySet ||
(SecurityPropertyState)hpkpState == SecurityPropertyKnockout));
SSSLOG(("SSS: loading SiteHPKPState matches=%d\n", matches));
const uint32_t SHA256Base64Len = 44;
if (valid && (SecurityPropertyState)hpkpState == SecurityPropertySet) {
// try to expand the merged PKPins
const char* cur = mergedHPKPins;
nsAutoCString pin;
uint32_t collectedLen = 0;
mergedHPKPins[MaxMergedHPKPPinSize - 1] = 0;
size_t totalLen = strlen(mergedHPKPins);
while (collectedLen + SHA256Base64Len <= totalLen) {
pin.Assign(cur, SHA256Base64Len);
if (stringIsBase64EncodingOf256bitValue(pin)) {
mSHA256keys.AppendElement(pin);
}
cur += SHA256Base64Len;
collectedLen += SHA256Base64Len;
}
if (mSHA256keys.IsEmpty()) {
valid = false;
}
}
if (valid) {
mState = (SecurityPropertyState)hpkpState;
mIncludeSubdomains = (hpkpIncludeSubdomains == 1);
} else {
SSSLOG(("%s is not a valid SiteHPKPState", aStateString.get()));
mExpireTime = 0;
mState = SecurityPropertyUnset;
mIncludeSubdomains = false;
if (!mSHA256keys.IsEmpty()) {
mSHA256keys.Clear();
}
}
}
SiteHPKPState::SiteHPKPState(PRTime aExpireTime,
SecurityPropertyState aState,
bool aIncludeSubdomains,
nsTArray<nsCString>& aSHA256keys)
: mExpireTime(aExpireTime)
, mState(aState)
, mIncludeSubdomains(aIncludeSubdomains)
, mSHA256keys(aSHA256keys)
{
}
void
SiteHPKPState::ToString(nsCString& aString)
{
aString.Truncate();
aString.AppendInt(mExpireTime);
aString.Append(',');
aString.AppendInt(mState);
aString.Append(',');
aString.AppendInt(static_cast<uint32_t>(mIncludeSubdomains));
aString.Append(',');
for (unsigned int i = 0; i < mSHA256keys.Length(); i++) {
aString.Append(mSHA256keys[i]);
}
}
////////////////////////////////////////////////////////////////////////////////
const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
static bool
HostIsIPAddress(const char *hostname)
{
PRNetAddr hostAddr;
return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
}
nsAutoCString CanonicalizeHostname(const char* hostname)
{
nsAutoCString canonicalizedHostname(hostname);
ToLowerCase(canonicalizedHostname);
while (canonicalizedHostname.Length() > 0 &&
canonicalizedHostname.Last() == '.') {
canonicalizedHostname.Truncate(canonicalizedHostname.Length() - 1);
}
return canonicalizedHostname;
}
nsSiteSecurityService::nsSiteSecurityService()
: mMaxMaxAge(kSixtyDaysInSeconds)
, mUsePreloadList(true)
, mUseStsService(true)
: mUseStsService(true)
, mPreloadListTimeOffset(0)
, mHPKPEnabled(false)
{
}
@ -233,48 +130,25 @@ nsSiteSecurityService::Init()
return NS_ERROR_NOT_SAME_THREAD;
}
mMaxMaxAge = mozilla::Preferences::GetInt(
"security.cert_pinning.max_max_age_seconds", kSixtyDaysInSeconds);
mozilla::Preferences::AddStrongObserver(this,
"security.cert_pinning.max_max_age_seconds");
mUsePreloadList = mozilla::Preferences::GetBool(
"network.stricttransportsecurity.preloadlist", true);
mozilla::Preferences::AddStrongObserver(this,
"network.stricttransportsecurity.preloadlist");
mHPKPEnabled = mozilla::Preferences::GetBool(
"security.cert_pinning.hpkp.enabled", false);
mozilla::Preferences::AddStrongObserver(this,
"security.cert_pinning.hpkp.enabled");
mUseStsService = mozilla::Preferences::GetBool(
"network.stricttransportsecurity.enabled", true);
mozilla::Preferences::AddStrongObserver(this,
"network.stricttransportsecurity.enabled");
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
mozilla::Preferences::AddStrongObserver(this,
"security.cert_pinning.process_headers_from_non_builtin_roots");
mPreloadListTimeOffset = mozilla::Preferences::GetInt(
"test.currentTimeOffsetSeconds", 0);
mozilla::Preferences::AddStrongObserver(this,
"test.currentTimeOffsetSeconds");
mSiteStateStorage =
mozilla::DataStorage::Get(NS_LITERAL_STRING("SiteSecurityServiceState.txt"));
mPreloadStateStorage =
mozilla::DataStorage::Get(NS_LITERAL_STRING("SecurityPreloadState.txt"));
bool storageWillPersist = false;
bool preloadStorageWillPersist = false;
nsresult rv = mSiteStateStorage->Init(storageWillPersist);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = mPreloadStateStorage->Init(preloadStorageWillPersist);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// This is not fatal. There are some cases where there won't be a
// profile directory (e.g. running xpcshell). There isn't the
// expectation that site information will be presisted in those cases.
if (!storageWillPersist || !preloadStorageWillPersist) {
if (!storageWillPersist) {
NS_WARNING("site security information will not be persisted");
}
@ -295,7 +169,7 @@ nsSiteSecurityService::GetHost(nsIURI* aURI, nsACString& aResult)
return rv;
}
aResult.Assign(PublicKeyPinningService::CanonicalizeHostname(host.get()));
aResult.Assign(CanonicalizeHostname(host.get()));
if (aResult.IsEmpty()) {
return NS_ERROR_UNEXPECTED;
}
@ -311,9 +185,6 @@ SetStorageKey(nsAutoCString& storageKey, nsCString& hostname, uint32_t aType)
case nsISiteSecurityService::HEADER_HSTS:
storageKey.AppendLiteral(":HSTS");
break;
case nsISiteSecurityService::HEADER_HPKP:
storageKey.AppendLiteral(":HPKP");
break;
default:
NS_ASSERTION(false, "SSS:SetStorageKey got invalid type");
}
@ -340,11 +211,9 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
return NS_OK;
}
// If max-age is zero, the host is no longer considered HSTS. If the host was
// preloaded, we store an entry indicating that this host is not HSTS, causing
// the preloaded information to be ignored.
// If max-age is zero, the host is no longer considered HSTS.
if (maxage == 0) {
return RemoveState(aType, aSourceURI, flags, true);
return RemoveState(aType, aSourceURI, flags);
}
MOZ_ASSERT((aHSTSState == SecurityPropertySet ||
@ -372,8 +241,7 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
}
NS_IMETHODIMP
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
uint32_t aFlags, bool force = false)
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
@ -381,8 +249,7 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
}
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
nsAutoCString hostname;
@ -393,34 +260,14 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
mozilla::DataStorageType storageType = isPrivate
? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent;
// If this host is in the preload list, we have to store a knockout entry
// if it's explicitly forced to not be HSTS anymore
if (force && GetPreloadListEntry(hostname.get())) {
SSSLOG(("SSS: storing knockout entry for %s", hostname.get()));
SiteHSTSState siteState(0, SecurityPropertyKnockout, false);
nsAutoCString stateString;
siteState.ToString(stateString);
nsAutoCString storageKey;
SetStorageKey(storageKey, hostname, aType);
rv = mSiteStateStorage->Put(storageKey, stateString, storageType);
NS_ENSURE_SUCCESS(rv, rv);
} else {
SSSLOG(("SSS: removing entry for %s", hostname.get()));
nsAutoCString storageKey;
SetStorageKey(storageKey, hostname, aType);
mSiteStateStorage->Remove(storageKey, storageType);
}
SSSLOG(("SSS: removing entry for %s", hostname.get()));
nsAutoCString storageKey;
SetStorageKey(storageKey, hostname, aType);
mSiteStateStorage->Remove(storageKey, storageType);
return NS_OK;
}
static bool
HostIsIPAddress(const char *hostname)
{
PRNetAddr hostAddr;
return (PR_StringToNetAddr(hostname, &hostAddr) == PR_SUCCESS);
}
NS_IMETHODIMP
nsSiteSecurityService::ProcessHeader(uint32_t aType,
nsIURI* aSourceURI,
@ -431,11 +278,6 @@ nsSiteSecurityService::ProcessHeader(uint32_t aType,
bool* aIncludeSubdomains,
uint32_t* aFailureResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ProcessHeader");
}
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
@ -457,11 +299,6 @@ nsSiteSecurityService::UnsafeProcessHeader(uint32_t aType,
bool* aIncludeSubdomains,
uint32_t* aFailureResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::UnsafeProcessHeader");
}
return ProcessHeaderInternal(aType, aSourceURI, aHeader, nullptr, aFlags,
aMaxAge, aIncludeSubdomains, aFailureResult);
}
@ -479,9 +316,8 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
// Only HSTS and HPKP are supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
if (aMaxAge != nullptr) {
@ -529,10 +365,6 @@ nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
aIncludeSubdomains, aFailureResult);
break;
case nsISiteSecurityService::HEADER_HPKP:
rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags, aMaxAge,
aIncludeSubdomains, aFailureResult);
break;
default:
MOZ_CRASH("unexpected header type");
}
@ -548,9 +380,6 @@ ParseSSSHeaders(uint32_t aType,
uint64_t& maxAge,
nsTArray<nsCString>& sha256keys)
{
// Strict transport security and Public Key Pinning have very similar
// Header formats.
// "Strict-Transport-Security" ":" OWS
// STS-d *( OWS ";" OWS STS-d OWS)
//
@ -562,26 +391,6 @@ ParseSSSHeaders(uint32_t aType,
// includeSubDomains = [ "includeSubDomains" ]
//
// "Public-Key-Pins ":" OWS
// PKP-d *( OWS ";" OWS PKP-d OWS)
//
// ; PKP directive
// PKP-d = maxAge / includeSubDomains / reportUri / pin-directive
//
// maxAge = "max-age" "=" delta-seconds v-ext
//
// includeSubDomains = [ "includeSubDomains" ]
//
// reportURi = "report-uri" "=" quoted-string
//
// pin-directive = "pin-" token "=" quoted-string
//
// the only valid token currently specified is sha256
// the quoted string for a pin directive is the base64 encoding
// of the hash of the public key of the fingerprint
//
// The order of the directives is not significant.
// All directives must appear only once.
// Directive names are case-insensitive.
// The entire header is invalid if a directive not conforming to the
@ -593,8 +402,6 @@ ParseSSSHeaders(uint32_t aType,
NS_NAMED_LITERAL_CSTRING(max_age_var, "max-age");
NS_NAMED_LITERAL_CSTRING(include_subd_var, "includesubdomains");
NS_NAMED_LITERAL_CSTRING(pin_sha256_var, "pin-sha256");
NS_NAMED_LITERAL_CSTRING(report_uri_var, "report-uri");
nsSecurityHeaderParser parser(aHeader);
nsresult rv = parser.Parse();
@ -649,29 +456,7 @@ ParseSSSHeaders(uint32_t aType,
directive->mValue.get()));
return nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS;
}
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
directive->mName.Length() == pin_sha256_var.Length() &&
directive->mName.EqualsIgnoreCase(pin_sha256_var.get(),
pin_sha256_var.Length())) {
SSSLOG(("SSS: found pinning entry '%s' length=%d",
directive->mValue.get(), directive->mValue.Length()));
if (!stringIsBase64EncodingOf256bitValue(directive->mValue)) {
return nsISiteSecurityService::ERROR_INVALID_PIN;
}
sha256keys.AppendElement(directive->mValue);
} else if (aType == nsISiteSecurityService::HEADER_HPKP &&
directive->mName.Length() == report_uri_var.Length() &&
directive->mName.EqualsIgnoreCase(report_uri_var.get(),
report_uri_var.Length())) {
// We don't support the report-uri yet, but to avoid unrecognized
// directive warnings, we still have to handle its presence
if (foundReportURI) {
SSSLOG(("SSS: found two report-uri directives"));
return nsISiteSecurityService::ERROR_MULTIPLE_REPORT_URIS;
}
SSSLOG(("SSS: found report-uri directive"));
foundReportURI = true;
} else {
} else {
SSSLOG(("SSS: ignoring unrecognized directive '%s'",
directive->mName.get()));
foundUnrecognizedDirective = true;
@ -680,194 +465,6 @@ ParseSSSHeaders(uint32_t aType,
return nsISiteSecurityService::Success;
}
nsresult
nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
const char* aHeader,
nsISSLStatus* aSSLStatus,
uint32_t aFlags,
uint64_t* aMaxAge,
bool* aIncludeSubdomains,
uint32_t* aFailureResult)
{
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
}
if (!mHPKPEnabled) {
SSSLOG(("SSS: HPKP disabled: not processing header '%s'", aHeader));
if (aMaxAge) {
*aMaxAge = 0;
}
if (aIncludeSubdomains) {
*aIncludeSubdomains = false;
}
return NS_OK;
}
SSSLOG(("SSS: processing HPKP header '%s'", aHeader));
NS_ENSURE_ARG(aSSLStatus);
const uint32_t aType = nsISiteSecurityService::HEADER_HPKP;
bool foundMaxAge = false;
bool foundIncludeSubdomains = false;
bool foundUnrecognizedDirective = false;
uint64_t maxAge = 0;
nsTArray<nsCString> sha256keys;
uint32_t sssrv = ParseSSSHeaders(aType, aHeader, foundIncludeSubdomains,
foundMaxAge, foundUnrecognizedDirective,
maxAge, sha256keys);
if (sssrv != nsISiteSecurityService::Success) {
if (aFailureResult) {
*aFailureResult = sssrv;
}
return NS_ERROR_FAILURE;
}
// after processing all the directives, make sure we came across max-age
// somewhere.
if (!foundMaxAge) {
SSSLOG(("SSS: did not encounter required max-age directive"));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_NO_MAX_AGE;
}
return NS_ERROR_FAILURE;
}
// before we add the pin we need to ensure it will not break the site as
// currently visited so:
// 1. recompute a valid chain (no external ocsp)
// 2. use this chain to check if things would have broken!
nsAutoCString host;
nsresult rv = GetHost(aSourceURI, host);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIX509Cert> cert;
rv = aSSLStatus->GetServerCert(getter_AddRefs(cert));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(cert, NS_ERROR_FAILURE);
UniqueCERTCertificate nssCert(cert->GetCert());
NS_ENSURE_TRUE(nssCert, NS_ERROR_FAILURE);
mozilla::pkix::Time now(mozilla::pkix::Now());
UniqueCERTCertList certList;
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
// We don't want this verification to cause any network traffic that would
// block execution. Also, since we don't have access to the original stapled
// OCSP response, we can't enforce this aspect of the TLS Feature extension.
// This is ok, because it will have been enforced when we originally connected
// to the site (or it's disabled, in which case we wouldn't want to enforce it
// anyway).
CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY |
CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
if (certVerifier->VerifySSLServerCert(nssCert,
nullptr, // stapledOCSPResponse
nullptr, // sctsFromTLSExtension
now, nullptr, // pinarg
host.get(), // hostname
certList,
false, // don't store intermediates
flags)
!= mozilla::pkix::Success) {
return NS_ERROR_FAILURE;
}
CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
if (CERT_LIST_END(rootNode, certList)) {
return NS_ERROR_FAILURE;
}
bool isBuiltIn = false;
mozilla::pkix::Result result = IsCertBuiltInRoot(rootNode->cert, isBuiltIn);
if (result != mozilla::pkix::Success) {
return NS_ERROR_FAILURE;
}
if (!isBuiltIn && !mProcessPKPHeadersFromNonBuiltInRoots) {
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_ROOT_NOT_BUILT_IN;
}
return NS_ERROR_FAILURE;
}
// If maxAge == 0, we remove dynamic HPKP state for this host. Due to
// architectural constraints, if this host was preloaded, any future lookups
// will use the preloaded state (i.e. we can't store a "this host is not HPKP"
// entry like we can for HSTS).
if (maxAge == 0) {
return RemoveState(aType, aSourceURI, aFlags);
}
// clamp maxAge to the maximum set by pref
if (maxAge > mMaxMaxAge) {
maxAge = mMaxMaxAge;
}
bool chainMatchesPinset;
rv = PublicKeyPinningService::ChainMatchesPinset(certList, sha256keys,
chainMatchesPinset);
if (NS_FAILED(rv)) {
return rv;
}
if (!chainMatchesPinset) {
// is invalid
SSSLOG(("SSS: Pins provided by %s are invalid no match with certList\n", host.get()));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_PINSET_DOES_NOT_MATCH_CHAIN;
}
return NS_ERROR_FAILURE;
}
// finally we need to ensure that there is a "backup pin" ie. There must be
// at least one fingerprint hash that does NOT validate against the verified
// chain (Section 2.5 of the spec)
bool hasBackupPin = false;
for (uint32_t i = 0; i < sha256keys.Length(); i++) {
nsTArray<nsCString> singlePin;
singlePin.AppendElement(sha256keys[i]);
rv = PublicKeyPinningService::ChainMatchesPinset(certList, singlePin,
chainMatchesPinset);
if (NS_FAILED(rv)) {
return rv;
}
if (!chainMatchesPinset) {
hasBackupPin = true;
}
}
if (!hasBackupPin) {
// is invalid
SSSLOG(("SSS: Pins provided by %s are invalid no backupPin\n", host.get()));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_NO_BACKUP_PIN;
}
return NS_ERROR_FAILURE;
}
int64_t expireTime = ExpireTimeFromMaxAge(maxAge);
SiteHPKPState dynamicEntry(expireTime, SecurityPropertySet,
foundIncludeSubdomains, sha256keys);
SSSLOG(("SSS: about to set pins for %s, expires=%ld now=%ld maxAge=%lu\n",
host.get(), expireTime, PR_Now() / PR_USEC_PER_MSEC, maxAge));
rv = SetHPKPState(host.get(), dynamicEntry, aFlags, false);
if (NS_FAILED(rv)) {
SSSLOG(("SSS: failed to set pins for %s\n", host.get()));
if (aFailureResult) {
*aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
}
return rv;
}
if (aMaxAge != nullptr) {
*aMaxAge = maxAge;
}
if (aIncludeSubdomains != nullptr) {
*aIncludeSubdomains = foundIncludeSubdomains;
}
return foundUnrecognizedDirective
? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
: NS_OK;
}
nsresult
nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
const char* aHeader,
@ -937,17 +534,11 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
uint32_t aFlags, bool* aCached,
bool* aResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureURI for non-HSTS entries");
}
NS_ENSURE_ARG(aURI);
NS_ENSURE_ARG(aResult);
// Only HSTS and HPKP are supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
nsAutoCString hostname;
@ -969,47 +560,16 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
return IsSecureHost(aType, hostname.get(), aFlags, aCached, aResult);
}
int STSPreloadCompare(const void *key, const void *entry)
{
const char *keyStr = (const char *)key;
const nsSTSPreload *preloadEntry = (const nsSTSPreload *)entry;
return strcmp(keyStr, preloadEntry->mHost);
}
// Returns the preload list entry for the given host, if it exists.
// Only does exact host matching - the user must decide how to use the returned
// data. May return null.
const nsSTSPreload *
nsSiteSecurityService::GetPreloadListEntry(const char *aHost)
{
PRTime currentTime = PR_Now() + (mPreloadListTimeOffset * PR_USEC_PER_SEC);
if (mUsePreloadList && currentTime < gPreloadListExpirationTime) {
return (const nsSTSPreload *) bsearch(aHost,
kSTSPreloadList,
mozilla::ArrayLength(kSTSPreloadList),
sizeof(nsSTSPreload),
STSPreloadCompare);
}
return nullptr;
}
NS_IMETHODIMP
nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
uint32_t aFlags, bool* aCached,
bool* aResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureHost for non-HSTS entries");
}
NS_ENSURE_ARG(aHost);
NS_ENSURE_ARG(aResult);
// Only HSTS and HPKP are supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
aType == nsISiteSecurityService::HEADER_HPKP,
// Only HSTS is supported at the moment.
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS,
NS_ERROR_NOT_IMPLEMENTED);
// set default in case if we can't find any STS information
@ -1023,38 +583,14 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
return NS_OK;
}
/* An IP address never qualifies as a secure URI. */
// An IP address never qualifies as a secure URI.
if (HostIsIPAddress(aHost)) {
return NS_OK;
}
if (aType == nsISiteSecurityService::HEADER_HPKP) {
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
if (!certVerifier) {
return NS_ERROR_FAILURE;
}
if (certVerifier->mPinningMode ==
CertVerifier::PinningMode::pinningDisabled) {
return NS_OK;
}
bool enforceTestMode = certVerifier->mPinningMode ==
CertVerifier::PinningMode::pinningEnforceTestMode;
return PublicKeyPinningService::HostHasPins(aHost, mozilla::pkix::Now(),
enforceTestMode, *aResult);
}
// Holepunch chart.apis.google.com and subdomains.
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
if (host.EqualsLiteral("chart.apis.google.com") ||
StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) {
if (aCached) {
*aCached = true;
}
return NS_OK;
}
const nsSTSPreload *preload = nullptr;
// Canonicalize the passed host name
nsAutoCString host(CanonicalizeHostname(aHost));
// First check the exact host. This involves first checking for an entry in
// site security storage. If that entry exists, we don't want to check
// in the preload list. We only want to use the stored value if it is not a
@ -1086,21 +622,11 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
}
}
// If the entry is expired and not in the preload list, we can remove it.
if (expired && !GetPreloadListEntry(host.get())) {
// If the entry is expired we can remove it.
if (expired) {
mSiteStateStorage->Remove(storageKey, storageType);
}
}
// Finally look in the preloaded list. This is the exact host,
// so if an entry exists at all, this host is HSTS.
else if (GetPreloadListEntry(host.get())) {
SSSLOG(("%s is a preloaded STS host", host.get()));
*aResult = true;
if (aCached) {
*aCached = true;
}
return NS_OK;
}
SSSLOG(("no HSTS data for %s found, walking up domain", host.get()));
const char *subdomain;
@ -1144,23 +670,11 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
}
}
// If the entry is expired and not in the preload list, we can remove it.
if (expired && !GetPreloadListEntry(subdomain)) {
// If the entry is expired we can remove it.
if (expired) {
mSiteStateStorage->Remove(storageKey, storageType);
}
}
// This is an ancestor, so if we get a match, we have to check if the
// preloaded entry includes subdomains.
else if ((preload = GetPreloadListEntry(subdomain)) != nullptr) {
if (preload->mIncludeSubdomains) {
SSSLOG(("%s is a preloaded STS host", subdomain));
*aResult = true;
if (aCached) {
*aCached = true;
}
break;
}
}
SSSLOG(("no HSTS data for %s found, walking up domain", subdomain));
}
@ -1172,155 +686,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
NS_IMETHODIMP
nsSiteSecurityService::ClearAll()
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ClearAll");
}
return mSiteStateStorage->Clear();
}
NS_IMETHODIMP
nsSiteSecurityService::ClearPreloads()
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::ClearPreloads");
}
return mPreloadStateStorage->Clear();
}
bool entryStateNotOK(SiteHPKPState& state, mozilla::pkix::Time& aEvalTime) {
return state.mState != SecurityPropertySet || state.IsExpired(aEvalTime) ||
state.mSHA256keys.Length() < 1;
}
NS_IMETHODIMP
nsSiteSecurityService::GetKeyPinsForHostname(const char* aHostname,
mozilla::pkix::Time& aEvalTime,
/*out*/ nsTArray<nsCString>& pinArray,
/*out*/ bool* aIncludeSubdomains,
/*out*/ bool* aFound) {
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::GetKeyPinsForHostname");
}
NS_ENSURE_ARG(aFound);
NS_ENSURE_ARG(aHostname);
if (!mHPKPEnabled) {
SSSLOG(("HPKP disabled - returning 'pins not found' for %s",
aHostname));
*aFound = false;
return NS_OK;
}
SSSLOG(("Top of GetKeyPinsForHostname for %s", aHostname));
*aFound = false;
*aIncludeSubdomains = false;
pinArray.Clear();
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHostname));
nsAutoCString storageKey;
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
SSSLOG(("storagekey '%s'\n", storageKey.get()));
mozilla::DataStorageType storageType = mozilla::DataStorage_Persistent;
nsCString value = mSiteStateStorage->Get(storageKey, storageType);
// decode now
SiteHPKPState foundEntry(value);
if (entryStateNotOK(foundEntry, aEvalTime)) {
// not in permanent storage, try now private
value = mSiteStateStorage->Get(storageKey, mozilla::DataStorage_Private);
SiteHPKPState privateEntry(value);
if (entryStateNotOK(privateEntry, aEvalTime)) {
// not in private storage, try dynamic preload
value = mPreloadStateStorage->Get(storageKey,
mozilla::DataStorage_Persistent);
SiteHPKPState preloadEntry(value);
if (entryStateNotOK(preloadEntry, aEvalTime)) {
return NS_OK;
}
foundEntry = preloadEntry;
} else {
foundEntry = privateEntry;
}
}
pinArray = foundEntry.mSHA256keys;
*aIncludeSubdomains = foundEntry.mIncludeSubdomains;
*aFound = true;
return NS_OK;
}
NS_IMETHODIMP
nsSiteSecurityService::SetKeyPins(const char* aHost, bool aIncludeSubdomains,
int64_t aExpires, uint32_t aPinCount,
const char** aSha256Pins,
bool aIsPreload,
/*out*/ bool* aResult)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::SetKeyPins");
}
NS_ENSURE_ARG_POINTER(aHost);
NS_ENSURE_ARG_POINTER(aResult);
NS_ENSURE_ARG_POINTER(aSha256Pins);
if (!mHPKPEnabled) {
SSSLOG(("SSS: HPKP disabled: not setting pins"));
*aResult = false;
return NS_OK;
}
SSSLOG(("Top of SetPins"));
nsTArray<nsCString> sha256keys;
for (unsigned int i = 0; i < aPinCount; i++) {
nsAutoCString pin(aSha256Pins[i]);
SSSLOG(("SetPins pin=%s\n", pin.get()));
if (!stringIsBase64EncodingOf256bitValue(pin)) {
return NS_ERROR_INVALID_ARG;
}
sha256keys.AppendElement(pin);
}
SiteHPKPState dynamicEntry(aExpires, SecurityPropertySet,
aIncludeSubdomains, sha256keys);
// we always store data in permanent storage (ie no flags)
nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
return SetHPKPState(host.get(), dynamicEntry, 0, aIsPreload);
}
nsresult
nsSiteSecurityService::SetHPKPState(const char* aHost, SiteHPKPState& entry,
uint32_t aFlags, bool aIsPreload)
{
SSSLOG(("Top of SetPKPState"));
nsAutoCString host(aHost);
nsAutoCString storageKey;
SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
mozilla::DataStorageType storageType = isPrivate
? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent;
nsAutoCString stateString;
entry.ToString(stateString);
nsresult rv;
if (aIsPreload) {
rv = mPreloadStateStorage->Put(storageKey, stateString, storageType);
} else {
rv = mSiteStateStorage->Put(storageKey, stateString, storageType);
}
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
//------------------------------------------------------------
// nsSiteSecurityService::nsIObserver
//------------------------------------------------------------
@ -1337,18 +705,10 @@ nsSiteSecurityService::Observe(nsISupports *subject,
}
if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
mUsePreloadList = mozilla::Preferences::GetBool(
"network.stricttransportsecurity.preloadlist", true);
mUseStsService = mozilla::Preferences::GetBool(
"network.stricttransportsecurity.enabled", true);
mPreloadListTimeOffset =
mozilla::Preferences::GetInt("test.currentTimeOffsetSeconds", 0);
mHPKPEnabled = mozilla::Preferences::GetBool(
"security.cert_pinning.hpkp.enabled", false);
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
mMaxMaxAge = mozilla::Preferences::GetInt(
"security.cert_pinning.max_max_age_seconds", kSixtyDaysInSeconds);
}
return NS_OK;

View file

@ -17,10 +17,10 @@
class nsIURI;
class nsISSLStatus;
// {16955eee-6c48-4152-9309-c42a465138a1}
// 91ea3803-9c79-45d9-97bf-88bc80269236
#define NS_SITE_SECURITY_SERVICE_CID \
{0x16955eee, 0x6c48, 0x4152, \
{0x93, 0x09, 0xc4, 0x2a, 0x46, 0x51, 0x38, 0xa1} }
{ 0x91ea3803, 0x9c79, 0x45d9, \
{ 0x97, 0xbf, 0x88, 0xbc, 0x80, 0x26, 0x92, 0x36 } }
/**
* SecurityPropertyState: A utility enum for representing the different states
@ -38,40 +38,6 @@ enum SecurityPropertyState {
SecurityPropertyNegative = 3,
};
/**
* SiteHPKPState: A utility class that encodes/decodes a string describing
* the public key pins of a site.
* HPKP state consists of:
* - Expiry time (PRTime (aka int64_t) in milliseconds)
* - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
* - An include subdomains flag (bool, default false)
* - An array of sha-256 hashed base 64 encoded fingerprints of required keys
*/
class SiteHPKPState
{
public:
SiteHPKPState();
explicit SiteHPKPState(nsCString& aStateString);
SiteHPKPState(PRTime aExpireTime, SecurityPropertyState aState,
bool aIncludeSubdomains, nsTArray<nsCString>& SHA256keys);
PRTime mExpireTime;
SecurityPropertyState mState;
bool mIncludeSubdomains;
nsTArray<nsCString> mSHA256keys;
bool IsExpired(mozilla::pkix::Time aTime)
{
if (aTime > mozilla::pkix::TimeFromEpochInSeconds(mExpireTime /
PR_MSEC_PER_SEC)) {
return true;
}
return false;
}
void ToString(nsCString& aString);
};
/**
* SiteHSTSState: A utility class that encodes/decodes a string describing
* the security state of a site. Currently only handles HSTS.
@ -110,8 +76,6 @@ public:
void ToString(nsCString &aString);
};
class nsSTSPreload;
class nsSiteSecurityService : public nsISiteSecurityService
, public nsIObserver
{
@ -139,23 +103,10 @@ private:
nsresult ProcessSTSHeader(nsIURI* aSourceURI, const char* aHeader,
uint32_t flags, uint64_t* aMaxAge,
bool* aIncludeSubdomains, uint32_t* aFailureResult);
nsresult ProcessPKPHeader(nsIURI* aSourceURI, const char* aHeader,
nsISSLStatus* aSSLStatus, uint32_t flags,
uint64_t* aMaxAge, bool* aIncludeSubdomains,
uint32_t* aFailureResult);
nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
bool aIsPreload);
const nsSTSPreload *GetPreloadListEntry(const char *aHost);
uint64_t mMaxMaxAge;
bool mUsePreloadList;
bool mUseStsService;
int64_t mPreloadListTimeOffset;
bool mHPKPEnabled;
bool mProcessPKPHeadersFromNonBuiltInRoots;
RefPtr<mozilla::DataStorage> mSiteStateStorage;
RefPtr<mozilla::DataStorage> mPreloadStateStorage;
};
#endif // __nsSiteSecurityService_h__

View file

@ -1,266 +0,0 @@
// -*- 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// For all cases, the acceptable pinset includes only certificates pinned to
// Test End Entity Cert (signed by issuer testCA). Other certificates
// are issued by otherCA, which is never in the pinset but is a user-specified
// trust anchor. This test covers multiple cases:
//
// Pinned domain include-subdomains.pinning.example.com includes subdomains
// - PASS: include-subdomains.pinning.example.com serves a correct cert
// - PASS: good.include-subdomains.pinning.example.com serves a correct cert
// - FAIL (strict): bad.include-subdomains.pinning.example.com serves a cert
// not in the pinset
// - PASS (mitm): bad.include-subdomains.pinning.example.com serves a cert not
// in the pinset, but issued by a user-specified trust domain
//
// Pinned domain exclude-subdomains.pinning.example.com excludes subdomains
// - PASS: exclude-subdomains.pinning.example.com serves a correct cert
// - FAIL: exclude-subdomains.pinning.example.com serves an incorrect cert
// (TODO: test using verifyCertNow)
// - PASS: sub.exclude-subdomains.pinning.example.com serves an incorrect cert
"use strict";
do_get_profile(); // must be called before getting nsIX509CertDB
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
function add_clear_override(host) {
add_test(function() {
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
.getService(Ci.nsICertOverrideService);
certOverrideService.clearValidityOverride(host, 8443);
run_next_test();
});
}
function test_strict() {
// In strict mode, we always evaluate pinning data, regardless of whether the
// issuer is a built-in trust anchor. We only enforce pins that are not in
// test mode.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
run_next_test();
});
// Normally this is overridable. But, since we have pinning information for
// this host, we don't allow overrides.
add_prevented_cert_override_test(
"unknownissuer.include-subdomains.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
// Issued by otherCA, which is not in the pinset for pinning.example.com.
add_connection_test("bad.include-subdomains.pinning.example.com",
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
// Check that using a FQDN doesn't bypass pinning.
add_connection_test("bad.include-subdomains.pinning.example.com.",
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
// For some reason this is also navigable (see bug 1118522).
add_connection_test("bad.include-subdomains.pinning.example.com..",
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
// These domains serve certs that match the pinset.
add_connection_test("include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("good.include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
// This domain serves a cert that doesn't match the pinset, but subdomains
// are excluded.
add_connection_test("sub.exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
// This domain's pinset is exactly the same as
// include-subdomains.pinning.example.com, serves the same cert as
// bad.include-subdomains.pinning.example.com, but it should pass because
// it's in test_mode.
add_connection_test("test-mode.pinning.example.com",
PRErrorCodeSuccess);
// Similarly, this pin is in test-mode, so it should be overridable.
add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.test-mode.pinning.example.com");
}
function test_mitm() {
// In MITM mode, we allow pinning to pass if the chain resolves to any
// user-specified trust anchor, even if it is not in the pinset.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
run_next_test();
});
add_connection_test("include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("good.include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
// Normally this is overridable. But, since we have pinning information for
// this host, we don't allow overrides (since building a trusted chain fails,
// we have no reason to believe this was issued by a user-added trust
// anchor, so we can't allow overrides for it).
add_prevented_cert_override_test(
"unknownissuer.include-subdomains.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
// In this case, even though otherCA is not in the pinset, it is a
// user-specified trust anchor and the pinning check succeeds.
add_connection_test("bad.include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("sub.exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.test-mode.pinning.example.com");
}
function test_disabled() {
// Disable pinning.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
run_next_test();
});
add_connection_test("include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("good.include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("bad.include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("sub.exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
add_cert_override_test("unknownissuer.include-subdomains.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.test-mode.pinning.example.com");
}
function test_enforce_test_mode() {
// In enforce test mode, we always enforce all pins, even test pins.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 3);
run_next_test();
});
// Normally this is overridable. But, since we have pinning information for
// this host, we don't allow overrides.
add_prevented_cert_override_test(
"unknownissuer.include-subdomains.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
// Issued by otherCA, which is not in the pinset for pinning.example.com.
add_connection_test("bad.include-subdomains.pinning.example.com",
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
// These domains serve certs that match the pinset.
add_connection_test("include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("good.include-subdomains.pinning.example.com",
PRErrorCodeSuccess);
add_connection_test("exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
// This domain serves a cert that doesn't match the pinset, but subdomains
// are excluded.
add_connection_test("sub.exclude-subdomains.pinning.example.com",
PRErrorCodeSuccess);
// This domain's pinset is exactly the same as
// include-subdomains.pinning.example.com, serves the same cert as
// bad.include-subdomains.pinning.example.com, is in test-mode, but we are
// enforcing test mode pins.
add_connection_test("test-mode.pinning.example.com",
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
// Normally this is overridable. But, since we have pinning information for
// this host (and since we're enforcing test mode), we don't allow overrides.
add_prevented_cert_override_test(
"unknownissuer.test-mode.pinning.example.com",
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
SEC_ERROR_UNKNOWN_ISSUER);
add_clear_override("unknownissuer.test-mode.pinning.example.com");
}
function check_pinning_telemetry() {
let service = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
let prod_histogram = service.getHistogramById("CERT_PINNING_RESULTS")
.snapshot();
let test_histogram = service.getHistogramById("CERT_PINNING_TEST_RESULTS")
.snapshot();
// Because all of our test domains are pinned to user-specified trust
// anchors, effectively only strict mode and enforce test-mode get evaluated
equal(prod_histogram.counts[0], 4,
"Actual and expected prod (non-Mozilla) failure count should match");
equal(prod_histogram.counts[1], 4,
"Actual and expected prod (non-Mozilla) success count should match");
equal(test_histogram.counts[0], 2,
"Actual and expected test (non-Mozilla) failure count should match");
equal(test_histogram.counts[1], 0,
"Actual and expected test (non-Mozilla) success count should match");
let moz_prod_histogram = service.getHistogramById("CERT_PINNING_MOZ_RESULTS")
.snapshot();
let moz_test_histogram =
service.getHistogramById("CERT_PINNING_MOZ_TEST_RESULTS").snapshot();
equal(moz_prod_histogram.counts[0], 0,
"Actual and expected prod (Mozilla) failure count should match");
equal(moz_prod_histogram.counts[1], 0,
"Actual and expected prod (Mozilla) success count should match");
equal(moz_test_histogram.counts[0], 0,
"Actual and expected test (Mozilla) failure count should match");
equal(moz_test_histogram.counts[1], 0,
"Actual and expected test (Mozilla) success count should match");
let per_host_histogram =
service.getHistogramById("CERT_PINNING_MOZ_RESULTS_BY_HOST").snapshot();
equal(per_host_histogram.counts[0], 0,
"Actual and expected per host (Mozilla) failure count should match");
equal(per_host_histogram.counts[1], 2,
"Actual and expected per host (Mozilla) success count should match");
run_next_test();
}
function run_test() {
// Ensure that static pinning works when HPKP is disabled.
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", false);
add_tls_server_setup("BadCertServer", "bad_certs");
// Add a user-specified trust anchor.
addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
test_strict();
test_mitm();
test_disabled();
test_enforce_test_mode();
add_test(function () {
check_pinning_telemetry();
});
run_next_test();
}

View file

@ -1,247 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// The purpose of this test is to create a site security service state file
// and see that the site security service reads it properly.
function writeLine(aLine, aOutputStream) {
aOutputStream.write(aLine, aLine.length);
}
var gSSService = null;
var gSSSStateSeen = false;
var gPreloadStateSeen = false;
var profileDir = do_get_profile();
var certdb;
function certFromFile(cert_name) {
return constructCertFromFile("test_pinning_dynamic/" + cert_name + ".pem");
}
function loadCert(cert_name, trust_string) {
let cert_filename = "test_pinning_dynamic/" + cert_name + ".pem";
addCertFromFile(certdb, cert_filename, trust_string);
return constructCertFromFile(cert_filename);
}
function checkOK(cert, hostname) {
return checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
certificateUsageSSLServer, {}, hostname);
}
function checkFail(cert, hostname) {
return checkCertErrorGeneric(certdb, cert, MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE,
certificateUsageSSLServer, {}, hostname);
}
const NON_ISSUED_KEY_HASH = "KHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN=";
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
function run_test() {
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
let stateFile = profileDir.clone();
stateFile.append(SSS_STATE_FILE_NAME);
// Assuming we're working with a clean slate, the SSS_STATE file shouldn't
// exist until we create it.
ok(!stateFile.exists(),
"State file should not exist when working with a clean slate");
let outputStream = FileUtils.openFileOutputStream(stateFile);
let now = (new Date()).getTime();
writeLine(`a.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,0,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
writeLine(`b.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
outputStream.close();
let preloadFile = profileDir.clone();
preloadFile.append(PRELOAD_STATE_FILE_NAME);
ok(!preloadFile.exists(),
"Preload file should not exist when working with a clean slate");
outputStream = FileUtils.openFileOutputStream(preloadFile);
writeLine(`a.preload.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
outputStream.close();
Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
do_test_pending();
gSSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
notEqual(gSSService, null,
"SiteSecurityService should have initialized successfully using" +
" the generated state file");
}
function checkDefaultSiteHPKPStatus() {
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"a.pinning2.example.com", 0),
"a.pinning2.example.com should have HPKP status");
ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"x.a.pinning2.example.com", 0),
"x.a.pinning2.example.com should not have HPKP status");
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"b.pinning2.example.com", 0),
"b.pinning2.example.com should have HPKP status");
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"x.b.pinning2.example.com", 0),
"x.b.pinning2.example.com should have HPKP status");
}
function checkStateRead(aSubject, aTopic, aData) {
if (aData == SSS_STATE_FILE_NAME) {
gSSSStateSeen = true;
} else if (aData == PRELOAD_STATE_FILE_NAME) {
gPreloadStateSeen = true;
} else {
throw new Error("Observed data should either be the Site Security " +
"Service state file name or the preload file name");
}
if (!gSSSStateSeen || !gPreloadStateSeen) {
return;
}
notEqual(gSSService, null, "SiteSecurityService should be initialized");
// Initializing the certificate DB will cause NSS-initialization, which in
// turn initializes the site security service. Since we're in part testing
// that the site security service correctly reads its state file, we have to
// make sure it doesn't start up before we've populated the file
certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
loadCert("pinningroot", "CTu,CTu,CTu");
loadCert("badca", "CTu,CTu,CTu");
// the written entry is for a.pinning2.example.com without subdomains
// and b.pinning2.example.com with subdomains
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
checkDefaultSiteHPKPStatus();
// add includeSubdomains to a.pinning2.example.com
gSSService.setKeyPins("a.pinning2.example.com", true,
new Date().getTime() + 1000000, 2,
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
checkFail(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"a.pinning2.example.com", 0),
"a.pinning2.example.com should still have HPKP status after adding" +
" includeSubdomains to a.pinning2.example.com");
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"x.a.pinning2.example.com", 0),
"x.a.pinning2.example.com should now have HPKP status after adding" +
" includeSubdomains to a.pinning2.example.com");
// Now setpins without subdomains
gSSService.setKeyPins("a.pinning2.example.com", false,
new Date().getTime() + 1000000, 2,
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
checkDefaultSiteHPKPStatus();
// failure to insert new pin entry leaves previous pin behavior
throws(() => {
gSSService.setKeyPins("a.pinning2.example.com", true,
new Date().getTime() + 1000000, 1, ["not a hash"]);
}, /NS_ERROR_ILLEGAL_VALUE/, "Attempting to set an invalid pin should fail");
checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
checkDefaultSiteHPKPStatus();
// Incorrect size results in failure
throws(() => {
gSSService.setKeyPins("a.pinning2.example.com", true,
new Date().getTime() + 1000000, 2, ["not a hash"]);
}, /NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY/,
"Attempting to set a pin with an incorrect size should fail");
// Ensure built-in pins work as expected
ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"nonexistent.example.com", 0),
"Not built-in nonexistent.example.com should not have HPKP status");
ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"include-subdomains.pinning.example.com", 0),
"Built-in include-subdomains.pinning.example.com should have HPKP status");
gSSService.setKeyPins("a.pinning2.example.com", false, new Date().getTime(),
1, [NON_ISSUED_KEY_HASH]);
// Check that a preload pin loaded from file works as expected
checkFail(certFromFile("a.preload.example.com-badca"), "a.preload.example.com");
checkOK(certFromFile("a.preload.example.com-pinningroot"), "a.preload.example.com");
// Check a dynamic addition works as expected
// first, it should succeed with the badCA - because there's no pin
checkOK(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
// then we add a pin, and we should get a failure (ensuring the expiry is
// after the test timeout)
gSSService.setKeyPins("b.preload.example.com", false,
new Date().getTime() + 1000000, 2,
[NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH], true);
checkFail(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
do_timeout(1250, checkExpiredState);
}
function checkExpiredState() {
checkOK(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
checkPreloadClear();
}
function checkPreloadClear() {
// Check that the preloaded pins still work after private data is cleared
gSSService.clearAll();
checkFail(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
// Check that the preloaded pins are cleared when we clear preloads
gSSService.clearPreloads();
checkOK(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
do_test_finished();
}

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC3TCCAcegAwIBAgIUXdB7LgBGZoRV1UmEFcsOhMigpB0wCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMlMCMwIQYD
VR0RBBowGIIWYS5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
AAKhpX2t/Bz9//u1DYyLZ6dLSJt121Vb58s8gQvI/7n6MdUP1IniQLbtPW+7wnV0
6LYagJQ11ZUJMxYUs6lB91yhwAO9NoN4QJWWB0i23DoZ6cg4dHmYKmQQ/HRndwm+
EATkJSnBAk8O2xmIm8CXbJ0W0lvaXEjzRfeoiEjQ0/THeo4hXvGOMPm31d+r4ji5
/u2+9jrpTII0kjCwFjqC97lPID14s9QRMqMB1CCV6fgT19EGYi9I7H6mnyukkmfX
9wOhLHSk6A2l5+5eJrZYXLOhcS31VBd54sb1Vvg+Bp05HMYjo051JcRlvxoIUsHT
JQDn8QrzwZBDBh4Pie3AwOM=
-----END CERTIFICATE-----

View file

@ -1,5 +0,0 @@
issuer:badca
subject:test end-entity
issuerKey:alternate
subjectKey:alternate
extension:subjectAlternativeName:a.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC4zCCAc2gAwIBAgIUPQgjdPeWdWy/0oKRi+5Lr7JJorMwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMl
MCMwIQYDVR0RBBowGIIWYS5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0B
AQsDggEBAFUlxnwpxOFbSxtsBthWu6xmDxeFAzP+u5YOfuKeiIGnAx70k8ODQufJ
Vm1rXvKtN5r8jR6AZh/hdA+tGhnu4+pGi9/aqWnaF1FEs2mW0saUV8atQZwNGRBO
E9FXdAHA8WmGIfRf8TOuWpmEWejjJt5Zsfs+V3ARIxjCrVE7ixyfJ/hYpmthLtYJ
5vgp0iiPjzorKeFnqooLVAfzeayRX0bE5H79NISIWq4CN/9J50ZFkRORURlANU95
2Dcuw416b3BGrWVmWlKWOpA6NZ+Rj+AI+z9UTDpqCczTfMXMabX4EveW1GKMMYiA
eLD8SY4VQ4403eaCp6rxYFrCNOeDczs=
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:test end-entity
subjectKey:alternate
extension:subjectAlternativeName:a.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC3DCCAcagAwIBAgIUKUG7kBZ72CvuLQ0uPfjKHLkKDQAwCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMkMCIwIAYD
VR0RBBkwF4IVYS5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
tx5YO8uvYac92scnMEswv4ZIslou8UYV/2mtxA+MaXf/g+MizOKeZgTI1+b9hR48
IDOgvrqPCbn1hKY6gb2gtRI1mC5dg9T8EYEXcC1TM+ncY/l4SZUjfMhzY2iOf62x
jhDqMMt4V5uaHUxVmJQI82X5qpxH3yJ3WOC87iGZNfMB8MSbLM3lxor9OHeTlTHQ
vPb/r7cLW+ikxirDGyBBvThkvDA/8qyN5Qp6Ae1BiPeEMoScNf3fChvNV6Jyb8g8
e9q0LnTlTuVgaDWtg7PVOxeiI+wf3Jhv9uqXQLX8JHZDKebLbQEkNcbR4DK/8wsP
uFhj0j8DY6+/YZbcF7Jgfw==
-----END CERTIFICATE-----

View file

@ -1,5 +0,0 @@
issuer:badca
subject:test end-entity
issuerKey:alternate
subjectKey:alternate
extension:subjectAlternativeName:a.preload.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC4jCCAcygAwIBAgIURV3mf9Dz42lALe31OAm2SYbpFaEwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMk
MCIwIAYDVR0RBBkwF4IVYS5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEB
CwOCAQEATOA0bbfg81JieQkTzr4oxBqPuFamtLSAsLpbKakikYQo2znMGNnHV7Xe
uxMGMhCIPRsiJ6jj6ZTQJNqQRKzXWEiBgREsarmJxA53ITIcO2cK2rqyetNAAwzZ
oViENmK3tLA5KT2VC9IGgMXdSE7IfXn+5yCdpKZ2ohwtkYHNkCbQIU+4KaCPa/dB
yAelZZPE0mVHJLkd5HoOsFmjFOBQuOkn9/AAOmkgBZIk1Dp833ywn/mnwLZdVsdV
+TjqWKenDJXxhO2+aCCtZbUVxKMn0TACpAA+rhjS5vigCyIZh7V4rxki9UXaOfVq
EVy4rFlRIYYtXV40HavDZoPgxuCHDw==
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:test end-entity
subjectKey:alternate
extension:subjectAlternativeName:a.preload.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC3TCCAcegAwIBAgIUV89JsAhywp3graSGqjeSpMzd1B0wCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMlMCMwIQYD
VR0RBBowGIIWYi5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
ABevzhH9/hjTBgTtUk4ytZX0A7Tu0DR5F9ooFnlUwzupHFihO+9NzEoCSIvCy3L9
+i3LbkaiUWEHQItLjIg+aice13ZkuMp+DeZ+D/YR9ulxyY1QBYeZLQj/gSdkj/fK
uDm0Izgt8OBsgP+KFX2c2cGZyOcXmFFAwSfkLz7p2qzrmuM7r5ploNpxeHBUIxUW
jJzSFeQMfy5wflcKDBY+PDejzN9Ik4weRyERsckVgmZSJXuodb8xgYkNPvl/GOVJ
o+eDw+E3uOsdBIDrsyb+bcQTG7nBkQoSqG8M0610h0OqFhksfv/0HcB/wfW8VdU+
+C4+tR2KfvqTCm3T6gzRWX8=
-----END CERTIFICATE-----

View file

@ -1,5 +0,0 @@
issuer:badca
subject:test end-entity
issuerKey:alternate
subjectKey:alternate
extension:subjectAlternativeName:b.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC4zCCAc2gAwIBAgIUVQNTrx+mRE96ggRLuZeFm+9uBdcwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMl
MCMwIQYDVR0RBBowGIIWYi5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0B
AQsDggEBAHYCfQaolF6z4IicBDTEQQVfYi4A3BcCNLTdInQlal/DHNytNRufM5TB
ccNpau5U9e10NBYWbMqRUBb/7wtYE4O7jhEWxjaHBOz5KTYLv8hjEc2wcHXfhlYM
QKmxOnA7SguSNYBdfXywav//ssLmDnB06nc2vv5NaKvIWbUv3HvfM8oRAr+NICUs
UMcIb+hjY+u/qrnOeFJxXzeqPYKMa7H+33baRgy7xnL95PxAwkz0XL8vcMFupTX5
dL5HsSKku23C0BoE6pK39TVh758fQjCAnD+QRTH/o+dfE2sIFpRiyszdXGmh2IRR
gMSy+gJbH+zh0D9ncL0Kev0PyEuBYR4=
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:test end-entity
subjectKey:alternate
extension:subjectAlternativeName:b.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC3DCCAcagAwIBAgIUf2T4BVvxeCgWVp/FL3tCFNjuZYQwCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMkMCIwIAYD
VR0RBBkwF4IVYi5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
okmxK2NDRYWSAn6b1YZpLiZnoaNrM0HXHY6fkARY/9EiAApvNPxT663EKtTZn27a
JtwXP2zzlYQDRc9cxa1zBX9Tp+0sn5aqokqzoVWx4VIe/emzi9FDf3lgaYewHLez
RINv3kUZmqlw6tmMQxjd51UGyvNsi52+gcet1cPr5kBzGQv/q7iNs/lcetL3+KQF
klJ3PfI4VjFwRRYNhScxiRczklPVDySvxSNw+csUxNRunFLXIi3+WqQzYhw7R8ga
ASwozTfvVAUySOmDipCZZXAHFtlpBr6vAllfD9v8hAsrE7Bkivafr+i5HMD3DtJE
4ZedqFCkTkqKvd0fMIbOIA==
-----END CERTIFICATE-----

View file

@ -1,5 +0,0 @@
issuer:badca
subject:test end-entity
issuerKey:alternate
subjectKey:alternate
extension:subjectAlternativeName:b.preload.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC4jCCAcygAwIBAgIUI5rdRX/x0w0bDx6hQhc8ZhGLfqQwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMk
MCIwIAYDVR0RBBkwF4IVYi5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEB
CwOCAQEAg2VdHBLmFLJ03N9VT4uUrnpjuYY9bsvPJF2JCk9817nxBbeMf+Qn0C/o
OeoQnZRqsaFbKZ80JXmh/j4RO6T/aaQUMpk+NXrdSPddy2B3eUByF/NJqipV3M2a
CRNWUUVF+msjRWwbzJafju2nEZcD4d4cUkHHYAaRRxAHH3ylEvWmdv/brgfAPCPH
WDVaCMc3OXgHkyrLAfkMKSYTNPJ7DJn/BXET5tCzqYGRUgRnME4ON2Mmp19lsdig
dIFbm76wg6l5M+s9pqiYzODUxJXUOd6BkAR5pqB9WyIRVfBr5LGT72nv00LHVcSm
hnsti9nAtFdJx4E1lJilrnQwu0q4Iw==
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:test end-entity
subjectKey:alternate
extension:subjectAlternativeName:b.preload.example.com

View file

@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICyzCCAbWgAwIBAgIUXQevdaeXMieCrG6ZqhI2yfACBq4wCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBAxDjAMBgNVBAMMBWJhZGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAwXXGUmYJn3cIKmeR8bh2w39c5TiwbErNIrHL1G+mWtoq3UHIwkmK
xKOzwfYUh/QbaYlBvYClHDwSAkTFhKTESDMF5ROMAQbPCL6ahidguuai6PNvI8XZ
gxO53683g0XazlHU1tzSpss8xwbrzTBw7JjM5AqlkdcpWn9xxb5maR0rLf7ISURZ
C8Wj6kn9k7HXU0BfF3N2mZWGZiVHl+1CaQiICBFCIGmYikP+5Izmh4HdIramnNKD
dRMfkysSjOKG+n0lHAYq0n7wFvGHzdVOgys1uJMPdLqQqovHYWckKrH9bWIUDRjE
wLjGj8N0hFcyStfehuZVLx0eGR1xIWjTuwIDAQABox0wGzAMBgNVHRMEBTADAQH/
MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHitWfZzPxR/UWEKQgz9zzm2
NXszG7nV82w8qfC9pq8mU3f7eqbHJ2HNFkZzttJsH9DNl30OK2Y5IVLUiZHckz2e
OFUyxK0tBCCBYd79FiK4BgP/Ys/7LK+4UaDhbRQP//MGuofwjsrNxgPgtkNaeKtF
EXKCuDrHoa4ua7afrkUWKzPZ6JbDOEjJIyuJ3ISI0Q20Oc3ERxGwG1SQ1EldgWBr
0dJJWBHZtNpIVvSm1dRfjMYtSrBoUXwbn6kDrdk4T98OHnFP0V0KW4j4umLHK7Gi
OSAwvWtir3fSJaLJClTCFe1XoNvJnQ53PJs0JR26mAixV2VuylStO2KlbYy7fOc=
-----END CERTIFICATE-----

View file

@ -1,6 +0,0 @@
issuer:badca
subject:badca
issuerKey:alternate
subjectKey:alternate
extension:basicConstraints:cA,
extension:keyUsage:keyCertSign,cRLSign

View file

@ -1,26 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Temporarily disabled. See bug 1256495.
#test_certificates = (
# 'badca.pem',
# 'a.pinning2.example.com-badca.pem',
# 'a.pinning2.example.com-pinningroot.pem',
# 'a.preload.example.com-badca.pem',
# 'a.preload.example.com-pinningroot.pem',
# 'b.pinning2.example.com-badca.pem',
# 'b.pinning2.example.com-pinningroot.pem',
# 'b.preload.example.com-badca.pem',
# 'b.preload.example.com-pinningroot.pem',
# 'x.a.pinning2.example.com-badca.pem',
# 'x.a.pinning2.example.com-pinningroot.pem',
# 'x.b.pinning2.example.com-badca.pem',
# 'x.b.pinning2.example.com-pinningroot.pem',
# 'pinningroot.pem',
#)
#
#for test_certificate in test_certificates:
# GeneratedTestCertificate(test_certificate)

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC1zCCAcGgAwIBAgIUMwSUmBShbg5sMNZSTiPd5Tb1udkwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAM
BgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBADNuQnKg
y8zWnKlfBq/50UOtdSlvevg6u6tsUTvay2kVgB8BRTvm76aw4yOLgk84eHHkrX5c
TqdutWh2JZarUWbO7JnPTdDE2CAkDh1smSe9L/XJENbgVXleg/VYLgnfnuSQCCnK
WjjExcorX6IKDks1ZoBJ1HIvBzMRMWzIQgBL9B2Y1V05lgfn0bwZD+TjUJBmN1w0
NTaPgrxE7FWZ2CTcowrYRKEEDAUX4cTFoce5YMwALCgW59KfVQfQdHaiCCcdNbfi
qSQGZu+59JrrasmgK9VTahukYWcaQCz8HBCasdknGodLAzThuWMkjXU3D2IZYl15
GfE5yrRFop/89xo=
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:pinningroot
extension:basicConstraints:cA,
extension:keyUsage:keyCertSign,cRLSign

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC3zCCAcmgAwIBAgIUe11LKIzCrdnRTgrLsfuGMoOpL1QwCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMnMCUwIwYD
VR0RBBwwGoIYeC5hLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOC
AQEAgdFC/SwBLRp6A+n3znR+sEuU8UvmbgbXp7pIFVh6cbC6lNF0nXk9ywPeIWyh
B7TCn3YHj4uc/PbvzRj9Py0gQLXcimKpmLoxclV5g1uTAydgXPiPulv/kaL9NOME
lm88pyQeDwfEkUz7VijabIzFRTEVRmOudb8mX4SuzjhxsdzSMjffpae335beJ4Im
lxgJgMsuJdEoK0WyG5nlBhVdzrT/kwdiwULeVNV//UHid1YZy56G5Lo22Hgd4wT3
1W3LXQelBdHhee7Hf7mg4rjCUPulFAr8qBLdywf1Hnu1o7rXUcn46PLwKLOWJPOM
SKpiqRKqvzlrzLaHPejfT0IMrw==
-----END CERTIFICATE-----

View file

@ -1,5 +0,0 @@
issuer:badca
subject:test end-entity
issuerKey:alternate
subjectKey:alternate
extension:subjectAlternativeName:x.a.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC5TCCAc+gAwIBAgIUefEeE+Sj5fBSec+97B6UmZFQEncwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMn
MCUwIwYDVR0RBBwwGoIYeC5hLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3
DQEBCwOCAQEAT2fxisiLJvVdFTba07a2Pc6UHBE+O0tOaLfMmHx/ET2FZdd9sLTL
X2f+hQCmXEBQ7Au2eYTew8hTyXYGYFauMJNk+XHHUIaSOhmnYTccye4d6j5bXRCp
7zA1qPlReCDLjp7o/34whkvngvdgdLYf60EkBO/NJfj+zsR1JTVfyVzIKXl6veLz
0xKicBAq9vS0Yqq10japVYKKqAw6gDpbNkSAd3xsl4+EbMRq+BnMB4W2anw1gM/e
hV11JQVA/MREtmUiTkvJFF6chHVCn5aL7JzVM2miZjZC8Ix59LUBoyO3SrxgrzZw
xeYuwoDhzTCrcFxn8gdKNajbGHuW5ekQpg==
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:test end-entity
subjectKey:alternate
extension:subjectAlternativeName:x.a.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC3zCCAcmgAwIBAgIUYcTc5Pz7KlQldGOO+KzbuBdf8TswCwYJKoZIhvcNAQEL
MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMnMCUwIwYD
VR0RBBwwGoIYeC5iLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOC
AQEAd6HusXqftFBpSUzivIY6icTZ95+wY+xIOsf1QOgyzZ/CDx4Tly+rgue2xSNT
59FmnFvh8jW202K8TykamsAX20A8ArzubNoc/+soA752YEvrMmOgWjmH2arqTfqg
zcfNdgUDESwnOoy123F+PkT3rRDXwINzCwftxhKbvmqhO6YENteqyWWmSZoMClsJ
xtm+bmPN+m26k6zMMYWzIu2HIXI3CgqOmJltfyqea02Y58S1+XlajrcewPpC17xD
r5a1sizecCFrmV0ssbK8wvEYo9Xs+PNj8Vhi1DUwGjtnjrYn/WQ6v/luMEEO7EMD
b3BbEziS3Pqej2JyprUKqOjv1g==
-----END CERTIFICATE-----

View file

@ -1,5 +0,0 @@
issuer:badca
subject:test end-entity
issuerKey:alternate
subjectKey:alternate
extension:subjectAlternativeName:x.b.pinning2.example.com

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC5TCCAc+gAwIBAgIUNXGolw8M2HU/gP4dOSMD2bdTQ+MwCwYJKoZIhvcNAQEL
MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMn
MCUwIwYDVR0RBBwwGoIYeC5iLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3
DQEBCwOCAQEAevN1gW64H2kCjW5W4wbQFkJIITjcdEUsw+8GPzDuBDJCvgGirhOi
ArBie8Bz+JlqzgNCXSe6pFVLoNfLosG5xksLwHljEit/7gFQ5twFazdg7dwPXs9Z
MIV2iv3vHmKYTFTcjfw07UWy0rHHt6EH+zXqpZFtFkJHqSgngKxAHgQlvSKeyynM
albu5YAX/hzJ7TyAVGxVN8uxnvYqPbLCy3wKf9ILFiDer6B9pE4Ii+dUyUbqVQFZ
tY2ac1474nkcfj3uj5qbV0TTpd9EL9HMvixTnoUrT3bqkRX7orvL4gXpnJJyRjvC
/LvTh/Vt1mYKkNLc/ruOj7WfUUC0SJIDzQ==
-----END CERTIFICATE-----

View file

@ -1,4 +0,0 @@
issuer:pinningroot
subject:test end-entity
subjectKey:alternate
extension:subjectAlternativeName:x.b.pinning2.example.com

View file

@ -1,147 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// The purpose of this test is to check that parsing of HPKP headers
// is correct.
var profileDir = do_get_profile();
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
var gSSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
function certFromFile(cert_name) {
return constructCertFromFile("test_pinning_dynamic/" + cert_name + ".pem");
}
function loadCert(cert_name, trust_string) {
let cert_filename = "test_pinning_dynamic/" + cert_name + ".pem";
addCertFromFile(certdb, cert_filename, trust_string);
return constructCertFromFile(cert_filename);
}
function checkFailParseInvalidPin(pinValue) {
let sslStatus = new FakeSSLStatus(
certFromFile('a.pinning2.example.com-pinningroot'));
let uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
throws(() => {
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
pinValue, sslStatus, 0);
}, /NS_ERROR_FAILURE/, `Invalid pin "${pinValue}" should be rejected`);
}
function checkPassValidPin(pinValue, settingPin, expectedMaxAge) {
let sslStatus = new FakeSSLStatus(
certFromFile('a.pinning2.example.com-pinningroot'));
let uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
let maxAge = {};
// setup preconditions for the test, if setting ensure there is no previous
// state, if removing ensure there is a valid pin in place.
if (settingPin) {
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
} else {
// add a known valid pin!
let validPinValue = "max-age=5000;" + VALID_PIN1 + BACKUP_PIN1;
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
validPinValue, sslStatus, 0);
}
try {
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
pinValue, sslStatus, 0, maxAge);
ok(true, "Valid pin should be accepted");
} catch (e) {
ok(false, "Valid pin should have been accepted");
}
// check that maxAge was processed correctly
if (settingPin && expectedMaxAge) {
ok(maxAge.value == expectedMaxAge, `max-age value should be ${expectedMaxAge}`);
}
// after processing ensure that the postconditions are true, if setting
// the host must be pinned, if removing the host must not be pinned
let hostIsPinned = gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
"a.pinning2.example.com", 0);
if (settingPin) {
ok(hostIsPinned, "Host should be considered pinned");
} else {
ok(!hostIsPinned, "Host should not be considered pinned");
}
}
function checkPassSettingPin(pinValue, expectedMaxAge) {
return checkPassValidPin(pinValue, true, expectedMaxAge);
}
function checkPassRemovingPin(pinValue) {
return checkPassValidPin(pinValue, false);
}
const MAX_MAX_AGE_SECONDS = 100000;
const GOOD_MAX_AGE_SECONDS = 69403;
const LONG_MAX_AGE_SECONDS = 2 * MAX_MAX_AGE_SECONDS;
const NON_ISSUED_KEY_HASH1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
const NON_ISSUED_KEY_HASH2 = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=";
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
const MAX_AGE_ZERO = "max-age=0;";
const VALID_PIN1 = `pin-sha256="${PINNING_ROOT_KEY_HASH}";`;
const BACKUP_PIN1 = `pin-sha256="${NON_ISSUED_KEY_HASH1}";`;
const BACKUP_PIN2 = `pin-sha256="${NON_ISSUED_KEY_HASH2}";`;
const BROKEN_PIN1 = "pin-sha256=\"jdjsjsjs\";";
const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
const LONG_MAX_AGE = `max-age=${LONG_MAX_AGE_SECONDS};`;
const INCLUDE_SUBDOMAINS = "includeSubdomains;";
const REPORT_URI = "report-uri=\"https://www.example.com/report/\";";
const UNRECOGNIZED_DIRECTIVE = "unreconized-dir=12343;";
function run_test() {
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
Services.prefs.setIntPref("security.cert_pinning.max_max_age_seconds", MAX_MAX_AGE_SECONDS);
Services.prefs.setBoolPref("security.cert_pinning.process_headers_from_non_builtin_roots", true);
loadCert("pinningroot", "CTu,CTu,CTu");
loadCert("badca", "CTu,CTu,CTu");
checkFailParseInvalidPin("max-age=INVALID");
// check that incomplete headers are failure
checkFailParseInvalidPin(GOOD_MAX_AGE);
checkFailParseInvalidPin(VALID_PIN1);
checkFailParseInvalidPin(REPORT_URI);
checkFailParseInvalidPin(UNRECOGNIZED_DIRECTIVE);
checkFailParseInvalidPin(VALID_PIN1 + BACKUP_PIN1);
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1);
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BROKEN_PIN1);
// next ensure a backup pin is present
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + VALID_PIN1);
// next section ensure duplicate directives result in failure
checkFailParseInvalidPin(GOOD_MAX_AGE + GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + INCLUDE_SUBDOMAINS + INCLUDE_SUBDOMAINS);
checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + REPORT_URI + REPORT_URI);
checkFailParseInvalidPin("thisisinvalidtest");
checkFailParseInvalidPin("invalid" + GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
checkPassRemovingPin("max-age=0"); //test removal without terminating ';'
checkPassRemovingPin(MAX_AGE_ZERO);
checkPassRemovingPin(MAX_AGE_ZERO + VALID_PIN1);
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1, GOOD_MAX_AGE_SECONDS);
checkPassSettingPin(LONG_MAX_AGE + VALID_PIN1 + BACKUP_PIN1, MAX_MAX_AGE_SECONDS);
checkPassRemovingPin(VALID_PIN1 + MAX_AGE_ZERO + VALID_PIN1);
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN2);
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN2 + INCLUDE_SUBDOMAINS);
checkPassSettingPin(VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2 + INCLUDE_SUBDOMAINS);
checkPassSettingPin(VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2 + REPORT_URI + INCLUDE_SUBDOMAINS);
checkPassSettingPin(INCLUDE_SUBDOMAINS + VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2);
checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + UNRECOGNIZED_DIRECTIVE);
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
Services.prefs.clearUserPref("security.cert_pinning.max_max_age_seconds");
Services.prefs.clearUserPref("security.cert_pinning.process_headers_from_non_builtin_roots");
}

View file

@ -1,34 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
"use strict";
// bug 961528: chart.apis.google.com doesn't handle https. Check that
// it isn't considered HSTS (other example.apis.google.com hosts should be
// HSTS as long as they're on the preload list, however).
function run_test() {
let SSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"chart.apis.google.com", 0));
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"CHART.APIS.GOOGLE.COM", 0));
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"sub.chart.apis.google.com", 0));
ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"SUB.CHART.APIS.GOOGLE.COM", 0));
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"example.apis.google.com", 0));
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"EXAMPLE.APIS.GOOGLE.COM", 0));
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"sub.example.apis.google.com", 0));
ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
"SUB.EXAMPLE.APIS.GOOGLE.COM", 0));
// also check isSecureURI
let chartURI = Services.io.newURI("http://chart.apis.google.com", null, null);
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, chartURI, 0));
let otherURI = Services.io.newURI("http://other.apis.google.com", null, null);
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, otherURI, 0));
}

View file

@ -26,7 +26,6 @@ support-files =
test_ocsp_fetch_method/**
test_ocsp_url/**
test_onecrl/**
test_pinning_dynamic/**
test_signed_apps/**
test_signed_dir/**
test_startcom_wosign/**
@ -111,13 +110,6 @@ run-sequentially = hardcoded ports
[test_ocsp_url.js]
run-sequentially = hardcoded ports
[test_password_prompt.js]
[test_pinning.js]
run-sequentially = hardcoded ports
# This test can take longer than 300 seconds on B2G emulator debug builds, so
# give it enough time to finish. See bug 1081128.
requesttimeoutfactor = 2
[test_pinning_dynamic.js]
[test_pinning_header_parsing.js]
[test_sdr.js]
[test_session_resumption.js]
run-sequentially = hardcoded ports
@ -137,7 +129,6 @@ skip-if = toolkit == 'android'
[test_sss_savestate.js]
[test_startcom_wosign.js]
[test_sts_fqdn.js]
[test_sts_holepunch.js]
[test_sts_ipv4_ipv6.js]
[test_sts_preloadlist_perwindowpb.js]
[test_sts_preloadlist_selfdestruct.js]

View file

@ -1,222 +0,0 @@
// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// The top-level element is a dictionary with two keys: "pinsets" maps details
// of certificate pinning to a name and "entries" contains the HPKP details for
// each host.
//
// "pinsets" is a list of objects. Each object has the following members:
// name: (string) the name of the pinset
// sha256_hashes: (list of strings) the set of allowed SPKIs hashes
//
// For a given pinset, a certificate is accepted if at least one of the
// Subject Public Key Infos (SPKIs) is found in the chain. SPKIs are specified
// as names, which must match up with the name given in the Mozilla root store.
//
// "entries" is a list of objects. Each object has the following members:
// name: (string) the DNS name of the host in question
// include_subdomains: (optional bool) whether subdomains of |name| are also covered
// pins: (string) the |name| member of an object in |pinsets|
//
// "extra_certs" is a list of base64-encoded certificates. These are used in
// pinsets that reference certificates not in our root program (for example,
// Facebook).
// equifax -> aus3
// Geotrust Primary -> www.mozilla.org
// Geotrust Global -> *. addons.mozilla.org
{
"chromium_data" : {
"cert_file_url": "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.pins?format=TEXT",
"json_file_url": "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json?format=TEXT",
"substitute_pinsets": {
// Use the larger google_root_pems pinset instead of google
"google": "google_root_pems"
},
"production_pinsets": [
"google_root_pems",
"facebook"
],
"production_domains": [
// Chrome's test domains.
"pinningtest.appspot.com",
"pinning-test.badssl.com",
// Dropbox
"dropbox.com",
"www.dropbox.com",
// Twitter
"api.twitter.com",
"business.twitter.com",
"dev.twitter.com",
"mobile.twitter.com",
"oauth.twitter.com",
"platform.twitter.com",
"twimg.com",
"www.twitter.com",
// Tor
"torproject.org",
"blog.torproject.org",
"check.torproject.org",
"dist.torproject.org",
"www.torproject.org",
// SpiderOak
"spideroak.com"
],
"exclude_domains" : [
// Chrome's entry for twitter.com doesn't include subdomains, so replace
// it with our own entry below which also uses an expanded pinset.
"twitter.com"
]
},
"pinsets": [
{
// From bug 772756, mozilla uses GeoTrust, Digicert and Thawte. Our
// cdn sites use Verisign and Baltimore. We exclude 1024-bit root certs
// from all providers. geotrust ca info:
// http://www.geotrust.com/resources/root-certificates/index.html
"name": "mozilla",
"sha256_hashes": [
"Baltimore CyberTrust Root",
"DigiCert Assured ID Root CA",
"DigiCert Global Root CA",
"DigiCert High Assurance EV Root CA",
"GeoTrust Global CA",
"GeoTrust Global CA 2",
"GeoTrust Primary Certification Authority",
"GeoTrust Primary Certification Authority - G2",
"GeoTrust Primary Certification Authority - G3",
"GeoTrust Universal CA",
"GeoTrust Universal CA 2",
"thawte Primary Root CA",
"thawte Primary Root CA - G2",
"thawte Primary Root CA - G3",
"Verisign Class 1 Public Primary Certification Authority - G3",
"Verisign Class 2 Public Primary Certification Authority - G3",
"Verisign Class 3 Public Primary Certification Authority - G3",
"VeriSign Class 3 Public Primary Certification Authority - G4",
"VeriSign Class 3 Public Primary Certification Authority - G5",
// "Verisign Class 4 Public Primary Certification Authority - G3",
"VeriSign Universal Root Certification Authority"
]
},
{
"name": "mozilla_services",
"sha256_hashes": [
"DigiCert Global Root CA"
]
},
// For pinning tests on pinning.example.com, the certificate must be 'End
// Entity Test Cert'
{
"name": "mozilla_test",
"sha256_hashes": [
"End Entity Test Cert"
]
},
// Google's root PEMs. Chrome pins only to their intermediate certs, but
// they'd like us to be more liberal. For the initial list, we are using
// the certs from http://pki.google.com/roots.pem.
// We have no built-in for commented out CAs.
{
"name": "google_root_pems",
"sha256_hashes": [
"AddTrust External Root",
"AddTrust Low-Value Services Root",
"AddTrust Public Services Root",
"AddTrust Qualified Certificates Root",
"AffirmTrust Commercial",
"AffirmTrust Networking",
"AffirmTrust Premium",
"AffirmTrust Premium ECC",
"Baltimore CyberTrust Root",
"Comodo AAA Services root",
"COMODO Certification Authority",
"COMODO ECC Certification Authority",
"COMODO RSA Certification Authority",
"Comodo Secure Services root",
"Comodo Trusted Services root",
"Cybertrust Global Root",
"DigiCert Assured ID Root CA",
"DigiCert Assured ID Root G2",
"DigiCert Assured ID Root G3",
"DigiCert Global Root CA",
"DigiCert Global Root G2",
"DigiCert Global Root G3",
"DigiCert High Assurance EV Root CA",
"DigiCert Trusted Root G4",
"Entrust Root Certification Authority",
"Entrust Root Certification Authority - EC1",
"Entrust Root Certification Authority - G2",
"Entrust.net Premium 2048 Secure Server CA",
// "Equifax Secure Certificate Authority",
"GeoTrust Global CA",
"GeoTrust Global CA 2",
"GeoTrust Primary Certification Authority",
"GeoTrust Primary Certification Authority - G2",
"GeoTrust Primary Certification Authority - G3",
"GeoTrust Universal CA",
"GeoTrust Universal CA 2",
"GlobalSign ECC Root CA - R4",
"GlobalSign ECC Root CA - R5",
"GlobalSign Root CA",
"GlobalSign Root CA - R2",
"GlobalSign Root CA - R3",
"Go Daddy Class 2 CA",
"Go Daddy Root Certificate Authority - G2",
"Starfield Class 2 CA",
"Starfield Root Certificate Authority - G2",
"thawte Primary Root CA",
"thawte Primary Root CA - G2",
"thawte Primary Root CA - G3",
"USERTrust ECC Certification Authority",
"USERTrust RSA Certification Authority",
"UTN USERFirst Hardware Root CA",
"Verisign Class 3 Public Primary Certification Authority - G3",
"VeriSign Class 3 Public Primary Certification Authority - G4",
"VeriSign Class 3 Public Primary Certification Authority - G5",
"VeriSign Universal Root Certification Authority"
]
}
],
"entries": [
// Only domains that are operationally crucial to Firefox can have per-host
// telemetry reporting (the "id") field
{ "name": "addons.mozilla.org", "include_subdomains": true,
"pins": "mozilla", "test_mode": false, "id": 1 },
{ "name": "addons.mozilla.net", "include_subdomains": true,
"pins": "mozilla", "test_mode": false, "id": 2 },
{ "name": "aus4.mozilla.org", "include_subdomains": true,
"pins": "mozilla", "test_mode": true, "id": 3 },
{ "name": "accounts.firefox.com", "include_subdomains": true,
"pins": "mozilla_services", "test_mode": false, "id": 4 },
{ "name": "api.accounts.firefox.com", "include_subdomains": true,
"pins": "mozilla_services", "test_mode": false, "id": 5 },
{ "name": "cdn.mozilla.net", "include_subdomains": true,
"pins": "mozilla", "test_mode": false },
{ "name": "cdn.mozilla.org", "include_subdomains": true,
"pins": "mozilla", "test_mode": false },
{ "name": "services.mozilla.com", "include_subdomains": true,
"pins": "mozilla_services", "test_mode": false, "id": 6 },
{ "name": "include-subdomains.pinning.example.com",
"include_subdomains": true, "pins": "mozilla_test",
"test_mode": false },
// Example domain to collect per-host stats for telemetry tests.
{ "name": "exclude-subdomains.pinning.example.com",
"include_subdomains": false, "pins": "mozilla_test",
"test_mode": false, "id": 0 },
{ "name": "test-mode.pinning.example.com", "include_subdomains": true,
"pins": "mozilla_test", "test_mode": true },
// Expand twitter's pinset to include all of *.twitter.com and use
// twitterCDN. More specific rules take precedence because we search for
// exact domain name first.
{ "name": "twitter.com", "include_subdomains": true,
"pins": "twitterCDN", "test_mode": false },
{ "name": "aus5.mozilla.org", "include_subdomains": true,
"pins": "mozilla", "test_mode": true, "id": 7 }
],
"extra_certificates": []
}

View file

@ -1,630 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// How to run this file:
// 1. [obtain firefox source code]
// 2. [build/obtain firefox binaries]
// 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \
// [path to]/genHPKPStaticpins.js \
// [absolute path to]/PreloadedHPKPins.json \
// [an unused argument - see bug 1205406] \
// [absolute path to]/StaticHPKPins.h
"use strict";
if (arguments.length != 3) {
throw new Error("Usage: genHPKPStaticPins.js " +
"<absolute path to PreloadedHPKPins.json> " +
"<an unused argument - see bug 1205406> " +
"<absolute path to StaticHPKPins.h>");
}
var { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components;
var { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
var { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
const SHA256_PREFIX = "sha256/";
const GOOGLE_PIN_PREFIX = "GOOGLE_PIN_";
// Pins expire in 14 weeks (6 weeks on Beta + 8 weeks on stable)
const PINNING_MINIMUM_REQUIRED_MAX_AGE = 60 * 60 * 24 * 7 * 14;
const FILE_HEADER = "/* This Source Code Form is subject to the terms of the Mozilla Public\n" +
" * License, v. 2.0. If a copy of the MPL was not distributed with this\n" +
" * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n" +
"\n" +
"/*****************************************************************************/\n" +
"/* This is an automatically generated file. If you're not */\n" +
"/* PublicKeyPinningService.cpp, you shouldn't be #including it. */\n" +
"/*****************************************************************************/\n" +
"#include <stdint.h>" +
"\n";
const DOMAINHEADER = "/* Domainlist */\n" +
"struct TransportSecurityPreload {\n" +
" const char* mHost;\n" +
" const bool mIncludeSubdomains;\n" +
" const bool mTestMode;\n" +
" const bool mIsMoz;\n" +
" const int32_t mId;\n" +
" const StaticFingerprints* pinset;\n" +
"};\n\n";
const PINSETDEF = "/* Pinsets are each an ordered list by the actual value of the fingerprint */\n" +
"struct StaticFingerprints {\n" +
" const size_t size;\n" +
" const char* const* data;\n" +
"};\n\n";
// Command-line arguments
var gStaticPins = parseJson(arguments[0]);
// arguments[1] is ignored for now. See bug 1205406.
// Open the output file.
var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(arguments[2]);
var gFileOutputStream = FileUtils.openSafeFileOutputStream(file);
function writeString(string) {
gFileOutputStream.write(string, string.length);
}
function readFileToString(filename) {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(filename);
let stream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
stream.init(file, -1, 0, 0);
let buf = NetUtil.readInputStreamToString(stream, stream.available());
return buf;
}
function stripComments(buf) {
let lines = buf.split("\n");
let entryRegex = /^\s*\/\//;
let data = "";
for (let i = 0; i < lines.length; ++i) {
let match = entryRegex.exec(lines[i]);
if (!match) {
data = data + lines[i];
}
}
return data;
}
function isBuiltinToken(tokenName) {
return tokenName == "Builtin Object Token";
}
function isCertBuiltIn(cert) {
let tokenNames = cert.getAllTokenNames({});
if (!tokenNames) {
return false;
}
if (tokenNames.some(isBuiltinToken)) {
return true;
}
return false;
}
function download(filename) {
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
req.open("GET", filename, false); // doing the request synchronously
try {
req.send();
}
catch (e) {
throw new Error(`ERROR: problem downloading '${filename}': ${e}`);
}
if (req.status != 200) {
throw new Error("ERROR: problem downloading '" + filename + "': status " +
req.status);
}
let resultDecoded;
try {
resultDecoded = atob(req.responseText);
}
catch (e) {
throw new Error("ERROR: could not decode data as base64 from '" + filename +
"': " + e);
}
return resultDecoded;
}
function downloadAsJson(filename) {
// we have to filter out '//' comments, while not mangling the json
let result = download(filename).replace(/^(\s*)?\/\/[^\n]*\n/mg, "");
let data = null;
try {
data = JSON.parse(result);
}
catch (e) {
throw new Error("ERROR: could not parse data from '" + filename + "': " + e);
}
return data;
}
// Returns a Subject Public Key Digest from the given pem, if it exists.
function getSKDFromPem(pem) {
let cert = gCertDB.constructX509FromBase64(pem, pem.length);
return cert.sha256SubjectPublicKeyInfoDigest;
}
/**
* Hashes |input| using the SHA-256 algorithm in the following manner:
* btoa(sha256(atob(input)))
*
* @argument {String} input Base64 string to decode and return the hash of.
* @returns {String} Base64 encoded SHA-256 hash.
*/
function sha256Base64(input) {
let decodedValue;
try {
decodedValue = atob(input);
}
catch (e) {
throw new Error(`ERROR: could not decode as base64: '${input}': ${e}`);
}
// Convert |decodedValue| to an array so that it can be hashed by the
// nsICryptoHash instance below.
// In most cases across the code base, convertToByteArray() of
// nsIScriptableUnicodeConverter is used to do this, but the method doesn't
// seem to work here.
let data = [];
for (let i = 0; i < decodedValue.length; i++) {
data[i] = decodedValue.charCodeAt(i);
}
let hasher = Cc["@mozilla.org/security/hash;1"]
.createInstance(Ci.nsICryptoHash);
hasher.init(hasher.SHA256);
hasher.update(data, data.length);
// true is passed so that the hasher returns a Base64 encoded string.
return hasher.finish(true);
}
// Downloads the static certs file and tries to map Google Chrome nicknames
// to Mozilla nicknames, as well as storing any hashes for pins for which we
// don't have root PEMs. Each entry consists of a line containing the name of
// the pin followed either by a hash in the format "sha256/" + base64(hash),
// a PEM encoded public key, or a PEM encoded certificate.
// For certificates that we have in our database,
// return a map of Google's nickname to ours. For ones that aren't return a
// map of Google's nickname to SHA-256 values. This code is modeled after agl's
// https://github.com/agl/transport-security-state-generate, which doesn't
// live in the Chromium repo because go is not an official language in
// Chromium.
// For all of the entries in this file:
// - If the entry has a hash format, find the Mozilla pin name (cert nickname)
// and stick the hash into certSKDToName
// - If the entry has a PEM format, parse the PEM, find the Mozilla pin name
// and stick the hash in certSKDToName
// We MUST be able to find a corresponding cert nickname for the Chrome names,
// otherwise we skip all pinsets referring to that Chrome name.
function downloadAndParseChromeCerts(filename, certNameToSKD, certSKDToName) {
// Prefixes that we care about.
const BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
const END_CERT = "-----END CERTIFICATE-----";
const BEGIN_PUB_KEY = "-----BEGIN PUBLIC KEY-----";
const END_PUB_KEY = "-----END PUBLIC KEY-----";
// Parsing states.
const PRE_NAME = 0;
const POST_NAME = 1;
const IN_CERT = 2;
const IN_PUB_KEY = 3;
let state = PRE_NAME;
let lines = download(filename).split("\n");
let name = "";
let pemCert = "";
let pemPubKey = "";
let hash = "";
let chromeNameToHash = {};
let chromeNameToMozName = {};
let chromeName;
for (let line of lines) {
// Skip comments and newlines.
if (line.length == 0 || line[0] == '#') {
continue;
}
switch (state) {
case PRE_NAME:
chromeName = line;
state = POST_NAME;
break;
case POST_NAME:
if (line.startsWith(SHA256_PREFIX)) {
hash = line.substring(SHA256_PREFIX.length);
chromeNameToHash[chromeName] = hash;
certNameToSKD[chromeName] = hash;
certSKDToName[hash] = chromeName;
state = PRE_NAME;
} else if (line.startsWith(BEGIN_CERT)) {
state = IN_CERT;
} else if (line.startsWith(BEGIN_PUB_KEY)) {
state = IN_PUB_KEY;
} else {
throw new Error("ERROR: couldn't parse Chrome certificate file " +
"line: " + line);
}
break;
case IN_CERT:
if (line.startsWith(END_CERT)) {
state = PRE_NAME;
hash = getSKDFromPem(pemCert);
pemCert = "";
let mozName;
if (hash in certSKDToName) {
mozName = certSKDToName[hash];
} else {
// Not one of our built-in certs. Prefix the name with
// GOOGLE_PIN_.
mozName = GOOGLE_PIN_PREFIX + chromeName;
dump("Can't find hash in builtin certs for Chrome nickname " +
chromeName + ", inserting " + mozName + "\n");
certSKDToName[hash] = mozName;
certNameToSKD[mozName] = hash;
}
chromeNameToMozName[chromeName] = mozName;
} else {
pemCert += line;
}
break;
case IN_PUB_KEY:
if (line.startsWith(END_PUB_KEY)) {
state = PRE_NAME;
hash = sha256Base64(pemPubKey);
pemPubKey = "";
chromeNameToHash[chromeName] = hash;
certNameToSKD[chromeName] = hash;
certSKDToName[hash] = chromeName;
} else {
pemPubKey += line;
}
break;
default:
throw new Error("ERROR: couldn't parse Chrome certificate file " + line);
}
}
return [ chromeNameToHash, chromeNameToMozName ];
}
// We can only import pinsets from chrome if for every name in the pinset:
// - We have a hash from Chrome's static certificate file
// - We have a builtin cert
// If the pinset meets these requirements, we store a map array of pinset
// objects:
// {
// pinset_name : {
// // Array of names with entries in certNameToSKD
// sha256_hashes: []
// }
// }
// and an array of imported pinset entries:
// { name: string, include_subdomains: boolean, test_mode: boolean,
// pins: pinset_name }
function downloadAndParseChromePins(filename,
chromeNameToHash,
chromeNameToMozName,
certNameToSKD,
certSKDToName) {
let chromePreloads = downloadAsJson(filename);
let chromePins = chromePreloads.pinsets;
let chromeImportedPinsets = {};
let chromeImportedEntries = [];
chromePins.forEach(function(pin) {
let valid = true;
let pinset = { name: pin.name, sha256_hashes: [] };
// Translate the Chrome pinset format to ours
pin.static_spki_hashes.forEach(function(name) {
if (name in chromeNameToHash) {
let hash = chromeNameToHash[name];
pinset.sha256_hashes.push(certSKDToName[hash]);
// We should have already added hashes for all of these when we
// imported the certificate file.
if (!certNameToSKD[name]) {
throw new Error("ERROR: No hash for name: " + name);
}
} else if (name in chromeNameToMozName) {
pinset.sha256_hashes.push(chromeNameToMozName[name]);
} else {
dump("Skipping Chrome pinset " + pinset.name + ", couldn't find " +
"builtin " + name + " from cert file\n");
valid = false;
}
});
if (valid) {
chromeImportedPinsets[pinset.name] = pinset;
}
});
// Grab the domain entry lists. Chrome's entry format is similar to
// ours, except theirs includes a HSTS mode.
const cData = gStaticPins.chromium_data;
let entries = chromePreloads.entries;
entries.forEach(function(entry) {
// HSTS entry only
if (!entry.pins) {
return;
}
let pinsetName = cData.substitute_pinsets[entry.pins];
if (!pinsetName) {
pinsetName = entry.pins;
}
// We trim the entry name here to avoid breaking hostname comparisons in the
// HPKP implementation.
entry.name = entry.name.trim();
let isProductionDomain =
(cData.production_domains.indexOf(entry.name) != -1);
let isProductionPinset =
(cData.production_pinsets.indexOf(pinsetName) != -1);
let excludeDomain =
(cData.exclude_domains.indexOf(entry.name) != -1);
let isTestMode = !isProductionPinset && !isProductionDomain;
if (entry.pins && !excludeDomain && chromeImportedPinsets[entry.pins]) {
chromeImportedEntries.push({
name: entry.name,
include_subdomains: entry.include_subdomains,
test_mode: isTestMode,
is_moz: false,
pins: pinsetName });
}
});
return [ chromeImportedPinsets, chromeImportedEntries ];
}
// Returns a pair of maps [certNameToSKD, certSKDToName] between cert
// nicknames and digests of the SPKInfo for the mozilla trust store
function loadNSSCertinfo(extraCertificates) {
let allCerts = gCertDB.getCerts();
let enumerator = allCerts.getEnumerator();
let certNameToSKD = {};
let certSKDToName = {};
while (enumerator.hasMoreElements()) {
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
if (!isCertBuiltIn(cert)) {
continue;
}
let name = cert.nickname.substr(BUILT_IN_NICK_PREFIX.length);
let SKD = cert.sha256SubjectPublicKeyInfoDigest;
certNameToSKD[name] = SKD;
certSKDToName[SKD] = name;
}
for (let cert of extraCertificates) {
let name = cert.commonName;
let SKD = cert.sha256SubjectPublicKeyInfoDigest;
certNameToSKD[name] = SKD;
certSKDToName[SKD] = name;
}
{
// This is the pinning test certificate. The key hash identifies the
// default RSA key from pykey.
let name = "End Entity Test Cert";
let SKD = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
certNameToSKD[name] = SKD;
certSKDToName[SKD] = name;
}
return [certNameToSKD, certSKDToName];
}
function parseJson(filename) {
let json = stripComments(readFileToString(filename));
return JSON.parse(json);
}
function nameToAlias(certName) {
// change the name to a string valid as a c identifier
// remove non-ascii characters
certName = certName.replace(/[^[:ascii:]]/g, "_");
// replace non word characters
certName = certName.replace(/[^A-Za-z0-9]/g, "_");
return "k" + certName + "Fingerprint";
}
function compareByName (a, b) {
return a.name.localeCompare(b.name);
}
function genExpirationTime() {
let now = new Date();
let nowMillis = now.getTime();
let expirationMillis = nowMillis + (PINNING_MINIMUM_REQUIRED_MAX_AGE * 1000);
let expirationMicros = expirationMillis * 1000;
return "static const PRTime kPreloadPKPinsExpirationTime = INT64_C(" +
expirationMicros + ");\n";
}
function writeFullPinset(certNameToSKD, certSKDToName, pinset) {
let prefix = "kPinset_" + pinset.name;
if (!pinset.sha256_hashes || pinset.sha256_hashes.length == 0) {
throw new Error(`ERROR: Pinset ${pinset.name} does not contain any hashes`);
}
writeFingerprints(certNameToSKD, certSKDToName, pinset.name,
pinset.sha256_hashes);
}
function writeFingerprints(certNameToSKD, certSKDToName, name, hashes) {
let varPrefix = "kPinset_" + name;
writeString("static const char* const " + varPrefix + "_Data[] = {\n");
let SKDList = [];
for (let certName of hashes) {
if (!(certName in certNameToSKD)) {
throw new Error(`ERROR: Can't find '${certName}' in certNameToSKD`);
}
SKDList.push(certNameToSKD[certName]);
}
for (let skd of SKDList.sort()) {
writeString(" " + nameToAlias(certSKDToName[skd]) + ",\n");
}
if (hashes.length == 0) {
// ANSI C requires that an initialiser list be non-empty.
writeString(" 0\n");
}
writeString("};\n");
writeString("static const StaticFingerprints " + varPrefix + " = {\n " +
"sizeof(" + varPrefix + "_Data) / sizeof(const char*),\n " + varPrefix +
"_Data\n};\n\n");
}
function writeEntry(entry) {
let printVal = " { \"" + entry.name + "\",\ ";
if (entry.include_subdomains) {
printVal += "true, ";
} else {
printVal += "false, ";
}
// Default to test mode if not specified.
let testMode = true;
if (entry.hasOwnProperty("test_mode")) {
testMode = entry.test_mode;
}
if (testMode) {
printVal += "true, ";
} else {
printVal += "false, ";
}
if (entry.is_moz || (entry.pins.indexOf("mozilla") != -1 &&
entry.pins != "mozilla_test")) {
printVal += "true, ";
} else {
printVal += "false, ";
}
if ("id" in entry) {
if (entry.id >= 256) {
throw new Error("ERROR: Not enough buckets in histogram");
}
if (entry.id >= 0) {
printVal += entry.id + ", ";
}
} else {
printVal += "-1, ";
}
printVal += "&kPinset_" + entry.pins;
printVal += " },\n";
writeString(printVal);
}
function writeDomainList(chromeImportedEntries) {
writeString("/* Sort hostnames for binary search. */\n");
writeString("static const TransportSecurityPreload " +
"kPublicKeyPinningPreloadList[] = {\n");
let count = 0;
let mozillaDomains = {};
gStaticPins.entries.forEach(function(entry) {
mozillaDomains[entry.name] = true;
});
// For any domain for which we have set pins, exclude them from
// chromeImportedEntries.
for (let i = chromeImportedEntries.length - 1; i >= 0; i--) {
if (mozillaDomains[chromeImportedEntries[i].name]) {
dump("Skipping duplicate pinset for domain " +
JSON.stringify(chromeImportedEntries[i], undefined, 2) + "\n");
chromeImportedEntries.splice(i, 1);
}
}
let sortedEntries = gStaticPins.entries;
sortedEntries.push.apply(sortedEntries, chromeImportedEntries);
for (let entry of sortedEntries.sort(compareByName)) {
count++;
writeEntry(entry);
}
writeString("};\n");
writeString("\n// Pinning Preload List Length = " + count + ";\n");
writeString("\nstatic const int32_t kUnknownId = -1;\n");
}
function writeFile(certNameToSKD, certSKDToName,
chromeImportedPinsets, chromeImportedEntries) {
// Compute used pins from both Chrome's and our pinsets, so we can output
// them later.
let usedFingerprints = {};
let mozillaPins = {};
gStaticPins.pinsets.forEach(function(pinset) {
mozillaPins[pinset.name] = true;
pinset.sha256_hashes.forEach(function (name) {
usedFingerprints[name] = true;
});
});
for (let key in chromeImportedPinsets) {
let pinset = chromeImportedPinsets[key];
pinset.sha256_hashes.forEach(function(name) {
usedFingerprints[name] = true;
});
}
writeString(FILE_HEADER);
// Write actual fingerprints.
Object.keys(usedFingerprints).sort().forEach(function(certName) {
if (certName) {
writeString("/* " + certName + " */\n");
writeString("static const char " + nameToAlias(certName) + "[] =\n");
writeString(" \"" + certNameToSKD[certName] + "\";\n");
writeString("\n");
}
});
// Write the pinsets
writeString(PINSETDEF);
writeString("/* PreloadedHPKPins.json pinsets */\n");
gStaticPins.pinsets.sort(compareByName).forEach(function(pinset) {
writeFullPinset(certNameToSKD, certSKDToName, pinset);
});
writeString("/* Chrome static pinsets */\n");
for (let key in chromeImportedPinsets) {
if (mozillaPins[key]) {
dump("Skipping duplicate pinset " + key + "\n");
} else {
dump("Writing pinset " + key + "\n");
writeFullPinset(certNameToSKD, certSKDToName, chromeImportedPinsets[key]);
}
}
// Write the domainlist entries.
writeString(DOMAINHEADER);
writeDomainList(chromeImportedEntries);
writeString("\n");
writeString(genExpirationTime());
}
function loadExtraCertificates(certStringList) {
let constructedCerts = [];
for (let certString of certStringList) {
constructedCerts.push(gCertDB.constructX509FromBase64(certString));
}
return constructedCerts;
}
var extraCertificates = loadExtraCertificates(gStaticPins.extra_certificates);
var [ certNameToSKD, certSKDToName ] = loadNSSCertinfo(extraCertificates);
var [ chromeNameToHash, chromeNameToMozName ] = downloadAndParseChromeCerts(
gStaticPins.chromium_data.cert_file_url, certNameToSKD, certSKDToName);
var [ chromeImportedPinsets, chromeImportedEntries ] =
downloadAndParseChromePins(gStaticPins.chromium_data.json_file_url,
chromeNameToHash, chromeNameToMozName, certNameToSKD, certSKDToName);
writeFile(certNameToSKD, certSKDToName, chromeImportedPinsets,
chromeImportedEntries);
FileUtils.closeSafeFileOutputStream(gFileOutputStream);

View file

@ -1,461 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// How to run this file:
// 1. [obtain firefox source code]
// 2. [build/obtain firefox binaries]
// 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \
// [path to]/getHSTSPreloadlist.js \
// [absolute path to]/nsSTSPreloadlist.inc'
// Note: Running this file outputs a new nsSTSPreloadlist.inc in the current
// working directory.
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource:///modules/XPCOMUtils.jsm");
const SOURCE = "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json?format=TEXT";
const TOOL_IDENTIFIER = "UXP HSTS preload list verifier"
const OUTPUT = "nsSTSPreloadList.inc";
const ERROR_OUTPUT = "nsSTSPreloadList.errors";
const MINIMUM_REQUIRED_MAX_AGE = 60 * 60 * 24 * 7 * 18;
const MAX_CONCURRENT_REQUESTS = 15;
const MAX_RETRIES = 2;
const REQUEST_TIMEOUT = 10 * 1000;
const ERROR_NONE = "no error";
const ERROR_CONNECTING_TO_HOST = "could not connect to host";
const ERROR_NO_HSTS_HEADER = "did not receive HSTS header";
const ERROR_MAX_AGE_TOO_LOW = "max-age too low: ";
const HEADER = "/* This Source Code Form is subject to the terms of the Mozilla Public\n" +
" * License, v. 2.0. If a copy of the MPL was not distributed with this\n" +
" * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n" +
"\n" +
"/*****************************************************************************/\n" +
"/* This is an automatically generated file. If you're not */\n" +
"/* nsSiteSecurityService.cpp, you shouldn't be #including it. */\n" +
"/*****************************************************************************/\n" +
"\n" +
"#include <stdint.h>\n";
const PREFIX = "\n" +
"class nsSTSPreload\n" +
"{\n" +
" public:\n" +
" const char *mHost;\n" +
" const bool mIncludeSubdomains;\n" +
"};\n" +
"\n" +
"static const nsSTSPreload kSTSPreloadList[] = {\n";
const POSTFIX = "};\n";
function download() {
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
req.open("GET", SOURCE, false); // doing the request synchronously
try {
req.send();
}
catch (e) {
throw new Error(`ERROR: problem downloading '${SOURCE}': ${e}`);
}
if (req.status != 200) {
throw new Error("ERROR: problem downloading '" + SOURCE + "': status " +
req.status);
}
var resultDecoded;
try {
resultDecoded = atob(req.responseText);
}
catch (e) {
throw new Error("ERROR: could not decode data as base64 from '" + SOURCE +
"': " + e);
}
// we have to filter out '//' comments, while not mangling the json
var result = resultDecoded.replace(/^(\s*)?\/\/[^\n]*\n/mg, "");
var data = null;
try {
data = JSON.parse(result);
}
catch (e) {
throw new Error(`ERROR: could not parse data from '${SOURCE}': ${e}`);
}
return data;
}
function getHosts(rawdata) {
var hosts = [];
if (!rawdata || !rawdata.entries) {
throw new Error("ERROR: source data not formatted correctly: 'entries' " +
"not found");
}
for (let entry of rawdata.entries) {
if (entry.mode && entry.mode == "force-https") {
if (entry.name) {
// We trim the entry name here to avoid malformed URI exceptions when we
// later try to connect to the domain.
entry.name = entry.name.trim();
entry.retries = MAX_RETRIES;
entry.originalIncludeSubdomains = entry.include_subdomains;
hosts.push(entry);
} else {
throw new Error("ERROR: entry not formatted correctly: no name found");
}
}
}
return hosts;
}
var gSSService = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
function processStsHeader(host, header, status, securityInfo) {
var maxAge = { value: 0 };
var includeSubdomains = { value: false };
var error = ERROR_NONE;
if (header != null && securityInfo != null) {
try {
var uri = Services.io.newURI("https://" + host.name, null, null);
var sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
.SSLStatus;
gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS,
uri, header, sslStatus, 0, maxAge,
includeSubdomains);
}
catch (e) {
dump("ERROR: could not process header '" + header + "' from " +
host.name + ": " + e + "\n");
error = e;
}
} else if (status == 0) {
error = ERROR_CONNECTING_TO_HOST;
} else {
error = ERROR_NO_HSTS_HEADER;
}
let forceInclude = (host.forceInclude || host.pins == "google");
if (error == ERROR_NONE && maxAge.value < MINIMUM_REQUIRED_MAX_AGE) {
error = ERROR_MAX_AGE_TOO_LOW;
}
return { name: host.name,
maxAge: maxAge.value,
includeSubdomains: includeSubdomains.value,
error: error,
retries: host.retries - 1,
forceInclude: forceInclude,
originalIncludeSubdomains: host.originalIncludeSubdomains };
}
// RedirectAndAuthStopper prevents redirects and HTTP authentication
function RedirectAndAuthStopper() {}
RedirectAndAuthStopper.prototype = {
// nsIChannelEventSink
asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
throw new Error(Cr.NS_ERROR_ENTITY_CHANGED);
},
// nsIAuthPrompt2
promptAuth: function(channel, level, authInfo) {
return false;
},
asyncPromptAuth: function(channel, callback, context, level, authInfo) {
throw new Error(Cr.NS_ERROR_NOT_IMPLEMENTED);
},
getInterface: function(iid) {
return this.QueryInterface(iid);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink,
Ci.nsIAuthPrompt2])
};
function getHSTSStatus(host, resultList) {
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
var inResultList = false;
var uri = "https://" + host.name + "/";
req.open("HEAD", uri, true);
req.setRequestHeader("X-Automated-Tool", TOOL_IDENTIFIER);
req.timeout = REQUEST_TIMEOUT;
let errorhandler = (evt) => {
dump(`ERROR: error making request to ${host.name} (type=${evt.type})\n`);
if (!inResultList) {
inResultList = true;
resultList.push(processStsHeader(host, null, req.status,
req.channel.securityInfo));
}
};
req.onerror = errorhandler;
req.ontimeout = errorhandler;
req.onabort = errorhandler;
req.onload = function(event) {
if (!inResultList) {
inResultList = true;
var header = req.getResponseHeader("strict-transport-security");
resultList.push(processStsHeader(host, header, req.status,
req.channel.securityInfo));
}
};
try {
req.channel.notificationCallbacks = new RedirectAndAuthStopper();
req.send();
}
catch (e) {
dump("ERROR: exception making request to " + host.name + ": " + e + "\n");
}
}
function compareHSTSStatus(a, b) {
if (a.name > b.name) {
return 1;
}
if (a.name < b.name) {
return -1;
}
return 0;
}
function writeTo(string, fos) {
fos.write(string, string.length);
}
// Determines and returns a string representing a declaration of when this
// preload list should no longer be used.
// This is the current time plus MINIMUM_REQUIRED_MAX_AGE.
function getExpirationTimeString() {
var now = new Date();
var nowMillis = now.getTime();
// MINIMUM_REQUIRED_MAX_AGE is in seconds, so convert to milliseconds
var expirationMillis = nowMillis + (MINIMUM_REQUIRED_MAX_AGE * 1000);
var expirationMicros = expirationMillis * 1000;
return "const PRTime gPreloadListExpirationTime = INT64_C(" + expirationMicros + ");\n";
}
function errorToString(status) {
return (status.error == ERROR_MAX_AGE_TOO_LOW
? status.error + status.maxAge
: status.error);
}
function writeEntry(status, outputStream) {
let incSubdomainsBool = (status.forceInclude && status.error != ERROR_NONE
? status.originalIncludeSubdomains
: status.includeSubdomains);
let includeSubdomains = (incSubdomainsBool ? "true" : "false");
writeTo(" { \"" + status.name + "\", " + includeSubdomains + " },\n",
outputStream);
}
function output(sortedStatuses, currentList) {
try {
var file = FileUtils.getFile("CurWorkD", [OUTPUT]);
var errorFile = FileUtils.getFile("CurWorkD", [ERROR_OUTPUT]);
var fos = FileUtils.openSafeFileOutputStream(file);
var eos = FileUtils.openSafeFileOutputStream(errorFile);
writeTo(HEADER, fos);
writeTo(getExpirationTimeString(), fos);
writeTo(PREFIX, fos);
dump("INFO: Removing error-state sites from list\n");
for (let status in sortedStatuses) {
// If we've encountered an error for this entry (other than the site not
// sending an HSTS header), be safe and remove it from the list
// (preventing stale entries from accumulating).
if (status.error != ERROR_NONE &&
status.error != ERROR_NO_HSTS_HEADER &&
status.error != ERROR_MAX_AGE_TOO_LOW &&
status.name in currentList) {
// dump("INFO: error connecting to or processing " + status.name + " - dropping from list\n");
writeTo(status.name + ": " + errorToString(status) + "\n", eos);
status.maxAge = 0;
}
}
// Filter out entries we aren't including.
dump("INFO: Filtering out entries we aren't including...\n");
var includedStatuses = sortedStatuses.filter(function (status) {
if (status.maxAge < MINIMUM_REQUIRED_MAX_AGE && !status.forceInclude) {
// dump("INFO: " + status.name + " NOT ON the preload list\n");
writeTo(status.name + ": " + errorToString(status) + "\n", eos);
return false;
}
// dump("INFO: " + status.name + " ON the preload list\n");
if (status.forceInclude && status.error != ERROR_NONE) {
writeTo(status.name + ": " + errorToString(status) + " (error "
+ "ignored - included regardless)\n", eos);
}
return true;
});
dump("INFO: Writing statuses to file...\n");
for (var status of includedStatuses) {
writeEntry(status, fos);
}
writeTo(POSTFIX, fos);
FileUtils.closeSafeFileOutputStream(fos);
FileUtils.closeSafeFileOutputStream(eos);
}
catch (e) {
dump("ERROR: problem writing output to '" + OUTPUT + "': " + e + "\n");
}
}
function shouldRetry(response) {
return (response.error != ERROR_NO_HSTS_HEADER &&
response.error != ERROR_MAX_AGE_TOO_LOW &&
response.error != ERROR_NONE && response.retries > 0);
}
function getHSTSStatuses(inHosts, outStatuses) {
var expectedOutputLength = inHosts.length;
var tmpOutput = [];
var procCount = 0;
for (var i = 0; i < MAX_CONCURRENT_REQUESTS && inHosts.length > 0; i++) {
let host = inHosts.shift();
dump("spinning off request to '" + host.name + "' (remaining retries: " +
host.retries + ")\n");
getHSTSStatus(host, tmpOutput);
}
while (outStatuses.length != expectedOutputLength) {
procCount++;
if (procCount % 200 == 0) gc();
waitForAResponse(tmpOutput);
var response = tmpOutput.shift();
dump("request to '" + response.name + "' finished\n");
if (shouldRetry(response)) {
inHosts.push(response);
} else {
outStatuses.push(response);
}
if (inHosts.length > 0) {
let host = inHosts.shift();
dump("[" + procCount + "] spinning off request to '" + host.name + "' (remaining retries: " +
host.retries + ")\n");
getHSTSStatus(host, tmpOutput);
}
}
}
// Since all events are processed on the main thread, and since event
// handlers are not preemptible, there shouldn't be any concurrency issues.
function waitForAResponse(outputList) {
// From <https://developer.mozilla.org/en/XPConnect/xpcshell/HOWTO>
var threadManager = Cc["@mozilla.org/thread-manager;1"]
.getService(Ci.nsIThreadManager);
var mainThread = threadManager.currentThread;
while (outputList.length == 0) {
mainThread.processNextEvent(true);
}
}
function readCurrentList(filename) {
var currentHosts = {};
var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(filename);
var fis = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsILineInputStream);
fis.init(file, -1, -1, Ci.nsIFileInputStream.CLOSE_ON_EOF);
var line = {};
var entryRegex = / { "([^"]*)", (true|false) },/;
while (fis.readLine(line)) {
var match = entryRegex.exec(line.value);
if (match) {
currentHosts[match[1]] = (match[2] == "true");
}
}
return currentHosts;
}
function combineLists(newHosts, currentHosts) {
let newHostsSet = new Set();
for (let newHost of newHosts) {
newHostsSet.add(newHost.name);
}
for (let currentHost in currentHosts) {
if (!newHostsSet.has(currentHost)) {
newHosts.push({ name: currentHost, retries: MAX_RETRIES });
}
}
}
const TEST_ENTRIES = [
{ name: "includesubdomains.preloaded.test", includeSubdomains: true },
{ name: "includesubdomains2.preloaded.test", includeSubdomains: true },
{ name: "noincludesubdomains.preloaded.test", includeSubdomains: false },
];
function deleteTestHosts(currentHosts) {
for (let testEntry of TEST_ENTRIES) {
delete currentHosts[testEntry.name];
}
}
function insertTestHosts(hstsStatuses) {
for (let testEntry of TEST_ENTRIES) {
hstsStatuses.push({
name: testEntry.name,
maxAge: MINIMUM_REQUIRED_MAX_AGE,
includeSubdomains: testEntry.includeSubdomains,
error: ERROR_NONE,
// This deliberately doesn't have a value for `retries` (because we should
// never attempt to connect to this host).
forceInclude: true,
originalIncludeSubdomains: testEntry.includeSubdomains,
});
}
}
// ****************************************************************************
// This is where the action happens:
if (arguments.length != 1) {
throw new Error("Usage: getHSTSPreloadList.js " +
"<absolute path to current nsSTSPreloadList.inc>");
}
// get the current preload list
var currentHosts = readCurrentList(arguments[0]);
// delete any hosts we use in tests so we don't actually connect to them
deleteTestHosts(currentHosts);
// disable the current preload list so it won't interfere with requests we make
Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", false);
// download and parse the raw json file from the Chromium source
var rawdata = download();
// get just the hosts with mode: "force-https"
var hosts = getHosts(rawdata);
// add hosts in the current list to the new list (avoiding duplicates)
combineLists(hosts, currentHosts);
// get the HSTS status of each host
var hstsStatuses = [];
getHSTSStatuses(hosts, hstsStatuses);
// add the hosts we use in tests
insertTestHosts(hstsStatuses);
// sort the hosts alphabetically
hstsStatuses.sort(compareHSTSStatus);
// write the results to a file (this is where we filter out hosts that we
// either couldn't connect to, didn't receive an HSTS header from, couldn't
// parse the header, or had a header with too short a max-age)
output(hstsStatuses, currentHosts);
// ****************************************************************************

View file

@ -65,7 +65,7 @@ endif
RANLIB = echo
CPU_ARCH = sparc
OS_DEFINES += -DSVR4 -DSYSV -D__svr4 -D__svr4__ -DSOLARIS -D_REENTRANT
OS_DEFINES += -DSVR4 -DSYSV -D__svr4 -D__svr4__ -DSOLARIS -D_REENTRANT -D__EXTENSIONS__
ifeq ($(OS_TEST),i86pc)
ifeq ($(USE_64),1)

View file

@ -134,7 +134,6 @@ cert.InsecureSweepingOverride = function() {
// clear collected HSTS and HPKP state
// through the site security service
sss.clearAll();
sss.clearPreloads();
},
};
};

View file

@ -1829,6 +1829,9 @@ nsDownloadManager::RetryDownload(nsDownload* dl)
return rv;
}
rv = NotifyDownloadRemoval(dl);
NS_ENSURE_SUCCESS(rv, rv);
// reset time and download progress
dl->SetStartTime(PR_Now());
dl->SetProgressBytes(0, -1);
@ -3083,7 +3086,7 @@ nsDownload::OnStateChange(nsIWebProgress *aWebProgress,
#else
(void)SetState(nsIDownloadManager::DOWNLOAD_FINISHED);
#endif
} else {
} else if (aStatus != NS_BINDING_ABORTED) {
// We failed for some unknown reason -- fail with a generic message
(void)FailDownload(aStatus, nullptr);
}

View file

@ -67,7 +67,7 @@
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
#elif defined(sparc)
#define GOOGLE_PROTOBUF_ARCH_SPARC 1
#ifdef SOLARIS_64BIT_ENABLED
#ifdef __arch64__
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
#else
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1

View file

@ -216,8 +216,8 @@ this.ForgetAboutSite = {
});
}));
// HSTS and HPKP
// TODO (bug 1290529): also remove HSTS/HPKP information for subdomains.
// HSTS
// TODO (bug 1290529): also remove HSTS information for subdomains.
// Since we can't enumerate the information in the site security service
// (bug 1115712), we can't implement this right now.
promises.push(Task.spawn(function*() {
@ -225,9 +225,8 @@ this.ForgetAboutSite = {
getService(Ci.nsISiteSecurityService);
let httpsURI = NetUtil.newURI("https://" + aDomain);
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, httpsURI, 0);
sss.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, httpsURI, 0);
}).catch(ex => {
throw new Error("Exception thrown while clearing HSTS/HPKP: " + ex);
throw new Error("Exception thrown while clearing HSTS: " + ex);
}));
let ErrorCount = 0;

View file

@ -0,0 +1,241 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["ExtensionStorage"];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
function jsonReplacer(key, value) {
switch (typeof(value)) {
// Serialize primitive types as-is.
case "string":
case "number":
case "boolean":
return value;
case "object":
if (value === null) {
return value;
}
switch (Cu.getClassName(value, true)) {
// Serialize arrays and ordinary objects as-is.
case "Array":
case "Object":
return value;
// Serialize Date objects and regular expressions as their
// string representations.
case "Date":
case "RegExp":
return String(value);
}
break;
}
if (!key) {
// If this is the root object, and we can't serialize it, serialize
// the value to an empty object.
return {};
}
// Everything else, omit entirely.
return undefined;
}
this.ExtensionStorage = {
cache: new Map(),
listeners: new Map(),
/**
* Sanitizes the given value, and returns a JSON-compatible
* representation of it, based on the privileges of the given global.
*
* @param {value} value
* The value to sanitize.
* @param {Context} context
* The extension context in which to sanitize the value
* @returns {value}
* The sanitized value.
*/
sanitize(value, context) {
let json = context.jsonStringify(value, jsonReplacer);
return JSON.parse(json);
},
getExtensionDir(extensionId) {
return OS.Path.join(this.extensionDir, extensionId);
},
getStorageFile(extensionId) {
return OS.Path.join(this.extensionDir, extensionId, "storage.js");
},
read(extensionId) {
if (this.cache.has(extensionId)) {
return this.cache.get(extensionId);
}
let path = this.getStorageFile(extensionId);
let decoder = new TextDecoder();
let promise = OS.File.read(path);
promise = promise.then(array => {
return JSON.parse(decoder.decode(array));
}).catch((error) => {
if (!error.becauseNoSuchFile) {
Cu.reportError("Unable to parse JSON data for extension storage.");
}
return {};
});
this.cache.set(extensionId, promise);
return promise;
},
write(extensionId) {
let promise = this.read(extensionId).then(extData => {
let encoder = new TextEncoder();
let array = encoder.encode(JSON.stringify(extData));
let path = this.getStorageFile(extensionId);
OS.File.makeDir(this.getExtensionDir(extensionId), {
ignoreExisting: true,
from: OS.Constants.Path.profileDir,
});
let promise = OS.File.writeAtomic(path, array);
return promise;
}).catch(() => {
// Make sure this promise is never rejected.
Cu.reportError("Unable to write JSON data for extension storage.");
});
AsyncShutdown.profileBeforeChange.addBlocker(
"ExtensionStorage: Finish writing extension data",
promise);
return promise.then(() => {
AsyncShutdown.profileBeforeChange.removeBlocker(promise);
});
},
set(extensionId, items, context) {
return this.read(extensionId).then(extData => {
let changes = {};
for (let prop in items) {
let item = this.sanitize(items[prop], context);
changes[prop] = {oldValue: extData[prop], newValue: item};
extData[prop] = item;
}
this.notifyListeners(extensionId, changes);
return this.write(extensionId);
});
},
remove(extensionId, items) {
return this.read(extensionId).then(extData => {
let changes = {};
for (let prop of [].concat(items)) {
changes[prop] = {oldValue: extData[prop]};
delete extData[prop];
}
this.notifyListeners(extensionId, changes);
return this.write(extensionId);
});
},
clear(extensionId) {
return this.read(extensionId).then(extData => {
let changes = {};
for (let prop of Object.keys(extData)) {
changes[prop] = {oldValue: extData[prop]};
delete extData[prop];
}
this.notifyListeners(extensionId, changes);
return this.write(extensionId);
});
},
get(extensionId, keys) {
return this.read(extensionId).then(extData => {
let result = {};
if (keys === null) {
Object.assign(result, extData);
} else if (typeof(keys) == "object" && !Array.isArray(keys)) {
for (let prop in keys) {
if (prop in extData) {
result[prop] = extData[prop];
} else {
result[prop] = keys[prop];
}
}
} else {
for (let prop of [].concat(keys)) {
if (prop in extData) {
result[prop] = extData[prop];
}
}
}
return result;
});
},
addOnChangedListener(extensionId, listener) {
let listeners = this.listeners.get(extensionId) || new Set();
listeners.add(listener);
this.listeners.set(extensionId, listeners);
},
removeOnChangedListener(extensionId, listener) {
let listeners = this.listeners.get(extensionId);
listeners.delete(listener);
},
notifyListeners(extensionId, changes) {
let listeners = this.listeners.get(extensionId);
if (listeners) {
for (let listener of listeners) {
listener(changes);
}
}
},
init() {
if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
return;
}
Services.obs.addObserver(this, "extension-invalidate-storage-cache", false);
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe(subject, topic, data) {
if (topic == "xpcom-shutdown") {
Services.obs.removeObserver(this, "extension-invalidate-storage-cache");
Services.obs.removeObserver(this, "xpcom-shutdown");
} else if (topic == "extension-invalidate-storage-cache") {
this.cache.clear();
}
},
};
XPCOMUtils.defineLazyGetter(ExtensionStorage, "extensionDir",
() => OS.Path.join(OS.Constants.Path.profileDir, "browser-extension-data"));
ExtensionStorage.init();

View file

@ -11,7 +11,6 @@ EXTRA_JS_MODULES += [
'addons/WebNavigation.jsm',
'addons/WebNavigationContent.js',
'addons/WebNavigationFrames.jsm',
'addons/WebRequest.jsm',
'addons/WebRequestCommon.jsm',
'addons/WebRequestContent.js',
'addons/WebRequestUpload.jsm',
@ -29,6 +28,7 @@ EXTRA_JS_MODULES += [
'debug.js',
'DeferredTask.jsm',
'Deprecated.jsm',
'ExtensionStorage.jsm',
'FileUtils.jsm',
'Finder.jsm',
'FinderHighlighter.jsm',
@ -84,6 +84,7 @@ EXTRA_JS_MODULES.third_party.jsesc += ['third_party/jsesc/jsesc.js']
EXTRA_JS_MODULES.sessionstore += ['sessionstore/Utils.jsm']
EXTRA_PP_JS_MODULES += [
'addons/WebRequest.jsm',
'NewTabUtils.jsm',
'ResetProfile.jsm',
'Troubleshoot.jsm',

View file

@ -2784,21 +2784,26 @@ XREMain::XRE_mainInit(bool* aExitFlag)
SetupErrorHandling(gArgv[0]);
#if 0
// Set up environment for NSS DBM database
// Set up environment for NSS database choice
#ifndef NSS_DISABLE_DBM
// Allow iteration counts in DBM mode
SaveToEnv("NSS_ALLOW_LEGACY_DBM_ITERATION_COUNT=1");
#endif
#ifdef DEBUG
// Reduce the number of rounds for debug builds for perf/test reasons.
SaveToEnv("NSS_MAX_MP_PBE_ITERATION_COUNT=15");
#else
#ifdef MOZ_SECURITY_SQLSTORE
// We're using SQL; NSS's defaults for rounds are fine.
#else
// Set default Master Password rounds to a sane value for DBM which is slower
// than SQL for PBKDF. The NSS hard-coded default of 10,000 is too much.
// See also Bug 1606992 for perf issues.
#ifdef DEBUG
SaveToEnv("NSS_MAX_MP_PBE_ITERATION_COUNT=15");
#else
SaveToEnv("NSS_MAX_MP_PBE_ITERATION_COUNT=500");
#endif
#endif
#endif //0
#ifdef CAIRO_HAS_DWRITE_FONT
{

View file

@ -21,6 +21,9 @@ public:
static bool OnYosemiteOrLater();
static bool OnElCapitanOrLater();
static bool OnSierraOrLater();
static bool OnHighSierraOrLater();
static bool OnMojaveOrLater();
static bool OnCatalinaOrLater();
static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);

View file

@ -19,6 +19,9 @@
#define MAC_OS_X_VERSION_10_10_HEX 0x000010A0
#define MAC_OS_X_VERSION_10_11_HEX 0x000010B0
#define MAC_OS_X_VERSION_10_12_HEX 0x000010C0
#define MAC_OS_X_VERSION_10_13_HEX 0x000010D0
#define MAC_OS_X_VERSION_10_14_HEX 0x000010E0
#define MAC_OS_X_VERSION_10_15_HEX 0x000010F0
#include "nsCocoaFeatures.h"
#include "nsCocoaUtils.h"
@ -167,6 +170,24 @@ nsCocoaFeatures::OnSierraOrLater()
return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX);
}
/* static */ bool
nsCocoaFeatures::OnHighSierraOrLater()
{
return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
}
/* static */ bool
nsCocoaFeatures::OnMojaveOrLater()
{
return (OSXVersion() >= MAC_OS_X_VERSION_10_14_HEX);
}
/* static */ bool
nsCocoaFeatures::OnCatalinaOrLater()
{
return (OSXVersion() >= MAC_OS_X_VERSION_10_15_HEX);
}
/* static */ bool
nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
{

Some files were not shown because too many files have changed in this diff Show more