mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
4ecaa49dd0
102 changed files with 772 additions and 102069 deletions
|
|
@ -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
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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;"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
28.9.0a1
|
||||
28.9.1a1
|
||||
|
|
@ -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 |
BIN
application/palemoon/themes/osx/Search.png
Normal file
BIN
application/palemoon/themes/osx/Search.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 437 B |
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
7
build/autoconf/config.guess
vendored
7
build/autoconf/config.guess
vendored
|
|
@ -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 ;;
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 =========================================================
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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++
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.preload.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:a.preload.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.preload.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:b.preload.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
issuer:badca
|
||||
subject:badca
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:keyCertSign,cRLSign
|
||||
|
|
@ -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)
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:pinningroot
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:keyCertSign,cRLSign
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.a.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.a.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
issuer:badca
|
||||
subject:test end-entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.b.pinning2.example.com
|
||||
|
|
@ -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-----
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
issuer:pinningroot
|
||||
subject:test end-entity
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:x.b.pinning2.example.com
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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": []
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
// ****************************************************************************
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ cert.InsecureSweepingOverride = function() {
|
|||
// clear collected HSTS and HPKP state
|
||||
// through the site security service
|
||||
sss.clearAll();
|
||||
sss.clearPreloads();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
241
toolkit/modules/ExtensionStorage.jsm
Normal file
241
toolkit/modules/ExtensionStorage.jsm
Normal 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();
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue