Merge mozilla-inbound to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Wed, 25 Jul 2018 21:21:50 +0300
changeset 483449 02c8644c45b1f143263d30d769d86c2d1058812e
parent 483439 fc6b465453aa8b5e0bc98a12a33ec78e5dbc97da (current diff)
parent 483448 13c6faaf92d341470e11fbdf8a46c2831c035a96 (diff)
child 483475 daacc8061a8f086dfc1511a136c5c100fb7d4e3f
child 483489 61f0334d49102aa45e09b8f39075feaec5085a2f
child 483590 4e08eb5f94e73e34f331f8dce08f77e9953d525a
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
02c8644c45b1 / 63.0a1 / 20180725220116 / files
nightly linux64
02c8644c45b1 / 63.0a1 / 20180725220116 / files
nightly mac
02c8644c45b1 / 63.0a1 / 20180725220116 / files
nightly win32
02c8644c45b1 / 63.0a1 / 20180725220116 / files
nightly win64
02c8644c45b1 / 63.0a1 / 20180725220116 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -513,16 +513,25 @@
                 <menupopup id="menuWebDeveloperPopup">
                   <menuitem id="menu_pageSource"
                             label="&pageSourceCmd.label;"
                             key="key_viewSource"
                             command="View:PageSource"
                             accesskey="&pageSourceCmd.accesskey;">
                     <observes element="canViewSource" attribute="disabled"/>
                   </menuitem>
+                  <menuitem id="menu_devtools_recordExecution"
+                            observes="devtoolsMenuBroadcaster_RecordExecution"
+                            hidden="true"/>
+                  <menuitem id="menu_devtools_saveRecording"
+                            observes="devtoolsMenuBroadcaster_SaveRecording"
+                            hidden="true"/>
+                  <menuitem id="menu_devtools_replayExecution"
+                            observes="devtoolsMenuBroadcaster_ReplayExecution"
+                            hidden="true"/>
                 </menupopup>
               </menu>
               <menuitem id="menu_pageInfo"
                         accesskey="&pageInfoCmd.accesskey;"
                         label="&pageInfoCmd.label;"
 #ifndef XP_WIN
                         key="key_viewInfo"
 #endif
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -93,16 +93,19 @@
     <command id="Browser:RestoreLastSession" oncommand="SessionStore.restoreLastSession();" disabled="true"/>
     <command id="Browser:NewUserContextTab" oncommand="openNewUserContextTab(event.sourceEvent);"/>
     <command id="Browser:OpenAboutContainers" oncommand="openPreferences('paneContainers', {origin: 'ContainersCommand'});"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:Sanitize" oncommand="Sanitizer.showUI(window);"/>
+    <command id="Tools:RecordExecution" oncommand="BeginRecordExecution()"/>
+    <command id="Tools:SaveRecording" oncommand="SaveRecordedExecution()"/>
+    <command id="Tools:ReplayExecution" oncommand="BeginReplayExecution()"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
 
 #ifdef NIGHTLY_BUILD
     <command id="wrCaptureCmd" oncommand="gWebRender.capture();"/>
 #endif
@@ -148,16 +151,25 @@
     <broadcaster id="sync-unverified-state" hidden="true"/>
     <broadcaster id="sync-syncnow-state" hidden="true"/>
     <broadcaster id="sync-reauth-state" hidden="true"/>
     <broadcaster id="viewTabsSidebar" autoCheck="false" sidebartitle="&syncedTabs.sidebar.label;"
                  type="checkbox" group="sidebar"
                  sidebarurl="chrome://browser/content/syncedtabs/sidebar.xhtml"
                  oncommand="SidebarUI.toggle('viewTabsSidebar');"/>
     <broadcaster id="workOfflineMenuitemState"/>
+    <broadcaster id="devtoolsMenuBroadcaster_RecordExecution"
+                 label="&devtoolsRecordExecution.label;"
+                 command="Tools:RecordExecution"/>
+    <broadcaster id="devtoolsMenuBroadcaster_SaveRecording"
+                 label="&devtoolsSaveRecording.label;"
+                 command="Tools:SaveRecording"/>
+    <broadcaster id="devtoolsMenuBroadcaster_ReplayExecution"
+                 label="&devtoolsReplayExecution.label;"
+                 command="Tools:ReplayExecution"/>
   </broadcasterset>
 
   <keyset id="mainKeyset">
     <key id="key_newNavigator"
          key="&newNavigatorCmd.key;"
          command="cmd_newNavigator"
          modifiers="accel" reserved="true"/>
     <key id="key_newNavigatorTab" key="&tabCmd.commandkey;" modifiers="accel"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7119,16 +7119,45 @@ function BrowserOpenAddonsMgr(aView) {
       }
       aSubject.QueryInterface(Ci.nsIDOMWindow);
       aSubject.focus();
       resolve(aSubject);
     }, "EM-loaded");
   });
 }
 
+function BeginRecordExecution() {
+  gBrowser.selectedTab = gBrowser.addTab("about:blank", { recordExecution: "*" });
+}
+
+function SaveRecordedExecution() {
+  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+  let window = gBrowser.ownerGlobal;
+  fp.init(window, null, Ci.nsIFilePicker.modeSave);
+  fp.open(rv => {
+    if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
+      var tabParent = gBrowser.selectedTab.linkedBrowser.frameLoader.tabParent;
+      if (!tabParent || !tabParent.saveRecording(fp.file.path)) {
+        window.alert("Current tab is not recording");
+      }
+    }
+  });
+}
+
+function BeginReplayExecution() {
+  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+  let window = gBrowser.ownerGlobal;
+  fp.init(window, null, Ci.nsIFilePicker.modeOpen);
+  fp.open(rv => {
+    if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
+      gBrowser.selectedTab = gBrowser.addTab(null, { replayExecution: fp.file.path });
+    }
+  });
+}
+
 function AddKeywordForSearchField() {
   let mm = gBrowser.selectedBrowser.messageManager;
 
   let onMessage = (message) => {
     mm.removeMessageListener("ContextMenu:SearchFieldBookmarkData:Result", onMessage);
 
     let bookmarkData = message.data;
     let title = gNavigatorBundle.getFormattedString("addKeywordTitleAutoFill",
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1773,17 +1773,18 @@ window._gBrowser = {
     // Make sure the preloaded browser is loaded with desired zoom level
     let tabURI = Services.io.newURI(BROWSER_NEW_TAB_URL);
     FullZoom.onLocationChange(tabURI, false, browser);
   },
 
   _createBrowser(aParams) {
     // Supported parameters:
     // userContextId, remote, remoteType, isPreloadBrowser,
-    // uriIsAboutBlank, sameProcessAsFrameLoader
+    // uriIsAboutBlank, sameProcessAsFrameLoader,
+    // recordExecution, replayExecution
 
     let b = document.createElementNS(this._XUL_NS, "browser");
     b.permanentKey = {};
 
     for (let attribute in this._defaultBrowserAttributes) {
       b.setAttribute(attribute, this._defaultBrowserAttributes[attribute]);
     }
 
@@ -1796,16 +1797,26 @@ window._gBrowser = {
       aParams.remoteType = E10SUtils.DEFAULT_REMOTE_TYPE;
     }
 
     if (aParams.remoteType) {
       b.setAttribute("remoteType", aParams.remoteType);
       b.setAttribute("remote", "true");
     }
 
+    let recordExecution = aParams && aParams.recordExecution;
+    if (recordExecution) {
+      b.setAttribute("recordExecution", recordExecution);
+    }
+
+    let replayExecution = aParams && aParams.replayExecution;
+    if (replayExecution) {
+      b.setAttribute("replayExecution", replayExecution);
+    }
+
     if (aParams.openerWindow) {
       if (aParams.remoteType) {
         throw new Error("Cannot set opener window on a remote browser!");
       }
       b.presetOpenerWindow(aParams.openerWindow);
     }
 
     if (!aParams.isPreloadBrowser) {
@@ -2147,16 +2158,18 @@ window._gBrowser = {
     referrerPolicy,
     referrerURI,
     relatedToCurrent,
     sameProcessAsFrameLoader,
     skipAnimation,
     skipBackgroundNotify,
     triggeringPrincipal,
     userContextId,
+    recordExecution,
+    replayExecution,
   } = {}) {
     // if we're adding tabs, we're past interrupt mode, ditch the owner
     if (this.selectedTab.owner) {
       this.selectedTab.owner = null;
     }
 
     // Find the tab that opened this one, if any. This is used for
     // determining positioning, and inherited attributes such as the
@@ -2326,33 +2339,37 @@ window._gBrowser = {
           preferredRemoteType);
 
       // If we open a new tab with the newtab URL in the default
       // userContext, check if there is a preloaded browser ready.
       // Private windows are not included because both the label and the
       // icon for the tab would be set incorrectly (see bug 1195981).
       if (aURI == BROWSER_NEW_TAB_URL &&
           !userContextId &&
-          !PrivateBrowsingUtils.isWindowPrivate(window)) {
+          !PrivateBrowsingUtils.isWindowPrivate(window) &&
+          !recordExecution &&
+          !replayExecution) {
         b = this._getPreloadedBrowser();
         if (b) {
           usingPreloadedContent = true;
         }
       }
 
       if (!b) {
         // No preloaded browser found, create one.
         b = this._createBrowser({
           remoteType,
           uriIsAboutBlank,
           userContextId,
           sameProcessAsFrameLoader,
           openerWindow: opener,
           nextTabParentId,
           name,
+          recordExecution,
+          replayExecution,
         });
       }
 
       t.linkedBrowser = b;
 
       if (focusUrlBar) {
         b._urlbarFocused = true;
       }
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -307,16 +307,20 @@ These should match what Safari and other
 <!ENTITY downloadsUnix.commandkey     "y">
 <!ENTITY addons.label                 "Add-ons">
 <!ENTITY addons.accesskey             "A">
 <!ENTITY addons.commandkey            "A">
 
 <!ENTITY webDeveloperMenu.label       "Web Developer">
 <!ENTITY webDeveloperMenu.accesskey   "W">
 
+<!ENTITY devtoolsRecordExecution.label "Record Execution">
+<!ENTITY devtoolsSaveRecording.label "Save Recording">
+<!ENTITY devtoolsReplayExecution.label "Replay Execution">
+
 <!ENTITY inspectContextMenu.label     "Inspect Element">
 <!ENTITY inspectContextMenu.accesskey "Q">
 
 <!ENTITY inspectA11YContextMenu.label     "Inspect Accessibility Properties">
 
 <!ENTITY fileMenu.label         "File">
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newUserContext.label             "New Container Tab">
--- a/config/msvc-stl-wrapper.template.h
+++ b/config/msvc-stl-wrapper.template.h
@@ -7,16 +7,21 @@
 
 #ifndef mozilla_${HEADER}_h
 #define mozilla_${HEADER}_h
 
 #if _HAS_EXCEPTIONS
 #  error "STL code can only be used with -fno-exceptions"
 #endif
 
+#if defined(__clang__)
+// Silence "warning: #include_next is a language extension [-Wgnu-include-next]"
+#pragma clang system_header
+#endif
+
 // Include mozalloc after the STL header and all other headers it includes
 // have been preprocessed.
 #if !defined(MOZ_INCLUDE_MOZALLOC_H)
 #  define MOZ_INCLUDE_MOZALLOC_H
 #  define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
 #endif
 
 #ifdef _DEBUG
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -108,16 +108,26 @@ var gDevToolsBrowser = exports.gDevTools
       "devtools.debugger.remote-enabled");
     const remoteEnabled = chromeEnabled && devtoolsRemoteEnabled;
     toggleMenuItem("menu_browserToolbox", remoteEnabled);
     toggleMenuItem("menu_browserContentToolbox",
       remoteEnabled && win.gMultiProcessBrowser);
 
     // Enable DevTools connection screen, if the preference allows this.
     toggleMenuItem("menu_devtools_connect", devtoolsRemoteEnabled);
+
+    // Enable record/replay menu items?
+    try {
+      const recordReplayEnabled = Services.prefs.getBoolPref("devtools.recordreplay.enabled");
+      toggleMenuItem("menu_devtools_recordExecution", recordReplayEnabled);
+      toggleMenuItem("menu_devtools_saveRecording", recordReplayEnabled);
+      toggleMenuItem("menu_devtools_replayExecution", recordReplayEnabled);
+    } catch (e) {
+      // devtools.recordreplay.enabled only exists on certain platforms.
+    }
   },
 
   /**
    * This function makes sure that the "devtoolstheme" attribute is set on the browser
    * window to make it possible to change colors on elements in the browser (like gcli,
    * or the splitter between the toolbox and web content).
    */
   updateDevtoolsThemeAttribute(win) {
--- a/gfx/layers/composite/GPUVideoTextureHost.cpp
+++ b/gfx/layers/composite/GPUVideoTextureHost.cpp
@@ -141,10 +141,17 @@ GPUVideoTextureHost::PushDisplayItems(wr
 
   mWrappedTextureHost->PushDisplayItems(aBuilder,
                                          aBounds,
                                          aClip,
                                          aFilter,
                                          aImageKeys);
 }
 
+bool
+GPUVideoTextureHost::SupportsWrNativeTexture()
+{
+  MOZ_ASSERT(mWrappedTextureHost);
+  return mWrappedTextureHost->SupportsWrNativeTexture();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/GPUVideoTextureHost.h
+++ b/gfx/layers/composite/GPUVideoTextureHost.h
@@ -57,16 +57,18 @@ public:
                                    const wr::ExternalImageId& aExtID) override;
 
   virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
                                 const wr::LayoutRect& aBounds,
                                 const wr::LayoutRect& aClip,
                                 wr::ImageRendering aFilter,
                                 const Range<wr::ImageKey>& aImageKeys) override;
 
+  virtual bool SupportsWrNativeTexture() override;
+
 protected:
   RefPtr<TextureHost> mWrappedTextureHost;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_GPUVIDEOTEXTUREHOST_H
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -669,16 +669,18 @@ public:
 
   /**
    * Some API's can use the cross-process IOSurface directly, such as OpenVR
    */
   virtual MacIOSurface* GetMacIOSurface() { return nullptr; }
 
   virtual bool IsDirectMap() { return false; }
 
+  virtual bool SupportsWrNativeTexture() { return false; }
+
 protected:
   virtual void ReadUnlock();
 
   void RecycleTexture(TextureFlags aFlags);
 
   virtual void MaybeNotifyUnlocked() {}
 
   virtual void UpdatedInternal(const nsIntRegion *Region) {}
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -366,16 +366,18 @@ public:
                                    const wr::ExternalImageId& aExtID) override;
 
   virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
                                 const wr::LayoutRect& aBounds,
                                 const wr::LayoutRect& aClip,
                                 wr::ImageRendering aFilter,
                                 const Range<wr::ImageKey>& aImageKeys) override;
 
+  virtual bool SupportsWrNativeTexture() override { return true; }
+
 protected:
   bool LockInternal();
   void UnlockInternal();
 
   bool EnsureTextureSource();
 
   RefPtr<ID3D11Device> GetDevice();
 
@@ -428,16 +430,18 @@ public:
                                    const wr::ExternalImageId& aExtID) override;
 
   virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
                                 const wr::LayoutRect& aBounds,
                                 const wr::LayoutRect& aClip,
                                 wr::ImageRendering aFilter,
                                 const Range<wr::ImageKey>& aImageKeys) override;
 
+  virtual bool SupportsWrNativeTexture() override { return true; }
+
 private:
   bool EnsureTextureSource();
 
 protected:
   RefPtr<ID3D11Device> GetDevice();
 
   bool EnsureTexture();
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -246,16 +246,17 @@ EXPORTS.mozilla.layers += [
     'wr/WebRenderDrawEventRecorder.h',
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
     'wr/WebRenderScrollData.h',
     'wr/WebRenderScrollDataWrapper.h',
     'wr/WebRenderTextureHost.h',
+    'wr/WebRenderTextureHostWrapper.h',
     'wr/WebRenderUserData.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
@@ -484,16 +485,17 @@ UNIFIED_SOURCES += [
     'wr/WebRenderBridgeParent.cpp',
     'wr/WebRenderCanvasRenderer.cpp',
     'wr/WebRenderCommandBuilder.cpp',
     'wr/WebRenderDrawEventRecorder.cpp',
     'wr/WebRenderImageHost.cpp',
     'wr/WebRenderLayerManager.cpp',
     'wr/WebRenderLayersLogging.cpp',
     'wr/WebRenderScrollData.cpp',
+    'wr/WebRenderTextureHostWrapper.cpp',
     'wr/WebRenderUserData.cpp',
     # XXX here are some unified build error.
     #'wr/WebRenderTextureHost.cpp'
 ]
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -161,56 +161,79 @@ AsyncImagePipelineManager::UpdateAsyncIm
   pipeline->Update(aScBounds,
                    aScTransform,
                    aScaleToSize,
                    aFilter,
                    aMixBlendMode);
 }
 
 Maybe<TextureHost::ResourceUpdateOp>
-AsyncImagePipelineManager::UpdateImageKeys(wr::TransactionBuilder& aResources,
+AsyncImagePipelineManager::UpdateImageKeys(const wr::Epoch& aEpoch,
+                                           const wr::PipelineId& aPipelineId,
+                                           wr::TransactionBuilder& aResources,
                                            AsyncImagePipeline* aPipeline,
                                            nsTArray<wr::ImageKey>& aKeys)
 {
   MOZ_ASSERT(aKeys.IsEmpty());
   MOZ_ASSERT(aPipeline);
 
   TextureHost* texture = aPipeline->mImageHost->GetAsTextureHostForComposite();
   TextureHost* previousTexture = aPipeline->mCurrentTexture.get();
 
   if (texture == previousTexture) {
     // The texture has not changed, just reuse previous ImageKeys.
     aKeys = aPipeline->mKeys;
+    if (aPipeline->mWrTextureWrapper) {
+      HoldExternalImage(aPipelineId, aEpoch, aPipeline->mWrTextureWrapper);
+    }
     return Nothing();
   }
 
   if (!texture) {
     // We don't have a new texture, there isn't much we can do.
     aKeys = aPipeline->mKeys;
+    if (aPipeline->mWrTextureWrapper) {
+      HoldExternalImage(aPipelineId, aEpoch, aPipeline->mWrTextureWrapper);
+    }
     return Nothing();
   }
 
   aPipeline->mCurrentTexture = texture;
 
   WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
 
   bool useExternalImage = !gfxEnv::EnableWebRenderRecording() && wrTexture;
   aPipeline->mUseExternalImage = useExternalImage;
 
+  // Use WebRenderTextureHostWrapper only for video.
+  // And WebRenderTextureHostWrapper could be used only with WebRenderTextureHost
+  // that supports NativeTexture
+  bool useWrTextureWrapper = aPipeline->mImageHost->GetAsyncRef() &&
+                             useExternalImage &&
+                             wrTexture &&
+                             wrTexture->SupportsWrNativeTexture();
+
   // The non-external image code path falls back to converting the texture into
   // an rgb image.
   auto numKeys = useExternalImage ? texture->NumSubTextures() : 1;
 
   // If we already had a texture and the format hasn't changed, better to reuse the image keys
   // than create new ones.
   bool canUpdate = !!previousTexture
                    && previousTexture->GetSize() == texture->GetSize()
                    && previousTexture->GetFormat() == texture->GetFormat()
                    && aPipeline->mKeys.Length() == numKeys;
 
+  // Check if WebRenderTextureHostWrapper could be reused.
+  if (aPipeline->mWrTextureWrapper &&
+      (!useWrTextureWrapper || !canUpdate)) {
+    aPipeline->mWrTextureWrapper = nullptr;
+    canUpdate = false;
+  }
+
   if (!canUpdate) {
     for (auto key : aPipeline->mKeys) {
       aResources.DeleteImage(key);
     }
     aPipeline->mKeys.Clear();
     for (uint32_t i = 0; i < numKeys; ++i) {
       aPipeline->mKeys.AppendElement(GenerateImageKey());
     }
@@ -219,18 +242,37 @@ AsyncImagePipelineManager::UpdateImageKe
   aKeys = aPipeline->mKeys;
 
   auto op = canUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
 
   if (!useExternalImage) {
     return UpdateWithoutExternalImage(aResources, texture, aKeys[0], op);
   }
 
-  Range<wr::ImageKey> keys(&aKeys[0], aKeys.Length());
-  wrTexture->PushResourceUpdates(aResources, op, keys, wrTexture->GetExternalImageKey());
+  if (useWrTextureWrapper && aPipeline->mWrTextureWrapper) {
+    MOZ_ASSERT(canUpdate);
+    // Reuse WebRenderTextureHostWrapper. With it, rendered frame could be updated
+    // without batch re-creation.
+    aPipeline->mWrTextureWrapper->UpdateWebRenderTextureHost(wrTexture);
+    // Ensure frame generation.
+    SetWillGenerateFrame();
+  } else {
+    if (useWrTextureWrapper) {
+      aPipeline->mWrTextureWrapper = new WebRenderTextureHostWrapper(this);
+      aPipeline->mWrTextureWrapper->UpdateWebRenderTextureHost(wrTexture);
+    }
+    Range<wr::ImageKey> keys(&aKeys[0], aKeys.Length());
+    auto externalImageKey =
+      aPipeline->mWrTextureWrapper ? aPipeline->mWrTextureWrapper->GetExternalImageKey() : wrTexture->GetExternalImageKey();
+    wrTexture->PushResourceUpdates(aResources, op, keys, externalImageKey);
+  }
+
+  if (aPipeline->mWrTextureWrapper) {
+    HoldExternalImage(aPipelineId, aEpoch, aPipeline->mWrTextureWrapper);
+  }
 
   return Some(op);
 }
 
 Maybe<TextureHost::ResourceUpdateOp>
 AsyncImagePipelineManager::UpdateWithoutExternalImage(wr::TransactionBuilder& aResources,
                                                       TextureHost* aTexture,
                                                       wr::ImageKey aKey,
@@ -291,17 +333,17 @@ AsyncImagePipelineManager::ApplyAsyncIma
 
 void
 AsyncImagePipelineManager::ApplyAsyncImageForPipeline(const wr::Epoch& aEpoch,
                                                       const wr::PipelineId& aPipelineId,
                                                       AsyncImagePipeline* aPipeline,
                                                       wr::TransactionBuilder& aTxn)
 {
   nsTArray<wr::ImageKey> keys;
-  auto op = UpdateImageKeys(aTxn, aPipeline, keys);
+  auto op = UpdateImageKeys(aEpoch, aPipelineId, aTxn, aPipeline, keys);
 
   bool updateDisplayList = aPipeline->mInitialised &&
                            (aPipeline->mIsChanged || op == Some(TextureHost::ADD_IMAGE)) &&
                            !!aPipeline->mCurrentTexture;
 
   // We will schedule generating a frame after the scene
   // build is done or resource update is done, so we don't need to do it here.
 
@@ -420,16 +462,33 @@ AsyncImagePipelineManager::HoldExternalI
   if (!holder) {
     return;
   }
   // Hold WebRenderTextureHost until end of its usage on RenderThread
   holder->mTextureHosts.push(ForwardingTextureHost(aEpoch, aTexture));
 }
 
 void
+AsyncImagePipelineManager::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHostWrapper* aWrTextureWrapper)
+{
+  if (mDestroyed) {
+    return;
+  }
+  MOZ_ASSERT(aWrTextureWrapper);
+
+  PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
+  MOZ_ASSERT(holder);
+  if (!holder) {
+    return;
+  }
+  // Hold WebRenderTextureHostWrapper until end of its usage on RenderThread
+  holder->mTextureHostWrappers.push(ForwardingTextureHostWrapper(aEpoch, aWrTextureWrapper));
+}
+
+void
 AsyncImagePipelineManager::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, const wr::ExternalImageId& aImageId)
 {
   if (mDestroyed) {
     SharedSurfacesParent::Release(aImageId);
     return;
   }
 
   PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
@@ -505,16 +564,22 @@ AsyncImagePipelineManager::ProcessPipeli
     PipelineTexturesHolder* holder = entry.Data();
     // Release TextureHosts based on Epoch
     while (!holder->mTextureHosts.empty()) {
       if (aEpoch <= holder->mTextureHosts.front().mEpoch) {
         break;
       }
       holder->mTextureHosts.pop();
     }
+    while (!holder->mTextureHostWrappers.empty()) {
+      if (aEpoch <= holder->mTextureHostWrappers.front().mEpoch) {
+        break;
+      }
+      holder->mTextureHostWrappers.pop();
+    }
     while (!holder->mExternalImages.empty()) {
       if (aEpoch <= holder->mExternalImages.front().mEpoch) {
         break;
       }
       DebugOnly<bool> released =
         SharedSurfacesParent::Release(holder->mExternalImages.front().mImageId);
       MOZ_ASSERT(released);
       holder->mExternalImages.pop();
--- a/gfx/layers/wr/AsyncImagePipelineManager.h
+++ b/gfx/layers/wr/AsyncImagePipelineManager.h
@@ -7,16 +7,17 @@
 #ifndef MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
 #define MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
 
 #include <queue>
 
 #include "CompositableHost.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/layers/TextureHost.h"
+#include "mozilla/layers/WebRenderTextureHostWrapper.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsClassHashtable.h"
 
 namespace mozilla {
 
 namespace wr {
@@ -25,16 +26,17 @@ class WebRenderAPI;
 }
 
 namespace layers {
 
 class CompositableHost;
 class CompositorVsyncScheduler;
 class WebRenderImageHost;
 class WebRenderTextureHost;
+class WebRenderTextureHostWrapper;
 
 class AsyncImagePipelineManager final
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncImagePipelineManager)
 
   explicit AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi);
 
@@ -43,16 +45,17 @@ protected:
 
 public:
   void Destroy();
 
   void AddPipeline(const wr::PipelineId& aPipelineId);
   void RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
 
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
+  void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHostWrapper* aWrTextureWrapper);
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, const wr::ExternalImageId& aImageId);
 
   // This is called from the Renderer thread to notify this class about the
   // pipelines in the most recently completed render. A copy of the update
   // information is put into mUpdatesQueue.
   void NotifyPipelinesUpdated(wr::WrPipelineInfo aInfo);
 
   // This is run on the compositor thread to process mUpdatesQueue. We make
@@ -101,16 +104,20 @@ public:
   void FlushImageNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
   {
     aNotifications->AppendElements(std::move(mImageCompositeNotifications));
   }
 
   void SetWillGenerateFrame();
   bool GetAndResetWillGenerateFrame();
 
+  wr::ExternalImageId GetNextExternalImageId() {
+    return wr::ToExternalImageId(GetNextResourceId());
+  }
+
 private:
   void ProcessPipelineRendered(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
   void ProcessPipelineRemoved(const wr::PipelineId& aPipelineId);
 
   wr::Epoch GetNextImageEpoch();
   uint32_t GetNextResourceId() { return ++mResourceId; }
   wr::IdNamespace GetNamespace() { return mIdNamespace; }
   wr::ImageKey GenerateImageKey()
@@ -125,28 +132,38 @@ private:
     ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
       : mEpoch(aEpoch)
       , mTexture(aTexture)
     {}
     wr::Epoch mEpoch;
     CompositableTextureHostRef mTexture;
   };
 
+  struct ForwardingTextureHostWrapper {
+    ForwardingTextureHostWrapper(const wr::Epoch& aEpoch, WebRenderTextureHostWrapper* aWrTextureWrapper)
+      : mEpoch(aEpoch)
+      , mWrTextureWrapper(aWrTextureWrapper)
+    {}
+    wr::Epoch mEpoch;
+    RefPtr<WebRenderTextureHostWrapper> mWrTextureWrapper;
+  };
+
   struct ForwardingExternalImage {
     ForwardingExternalImage(const wr::Epoch& aEpoch, const wr::ExternalImageId& aImageId)
       : mEpoch(aEpoch)
       , mImageId(aImageId)
     {}
     wr::Epoch mEpoch;
     wr::ExternalImageId mImageId;
   };
 
   struct PipelineTexturesHolder {
     // Holds forwarding WebRenderTextureHosts.
     std::queue<ForwardingTextureHost> mTextureHosts;
+    std::queue<ForwardingTextureHostWrapper> mTextureHostWrappers;
     std::queue<ForwardingExternalImage> mExternalImages;
     Maybe<wr::Epoch> mDestroyedEpoch;
   };
 
   struct AsyncImagePipeline {
     AsyncImagePipeline();
     void Update(const LayoutDeviceRect& aScBounds,
                 const gfx::Matrix4x4& aScTransform,
@@ -171,25 +188,28 @@ private:
     bool mUseExternalImage;
     LayoutDeviceRect mScBounds;
     gfx::Matrix4x4 mScTransform;
     gfx::MaybeIntSize mScaleToSize;
     wr::ImageRendering mFilter;
     wr::MixBlendMode mMixBlendMode;
     RefPtr<WebRenderImageHost> mImageHost;
     CompositableTextureHostRef mCurrentTexture;
+    RefPtr<WebRenderTextureHostWrapper> mWrTextureWrapper;
     nsTArray<wr::ImageKey> mKeys;
   };
 
   void ApplyAsyncImageForPipeline(const wr::Epoch& aEpoch,
                                   const wr::PipelineId& aPipelineId,
                                   AsyncImagePipeline* aPipeline,
                                   wr::TransactionBuilder& aTxn);
   Maybe<TextureHost::ResourceUpdateOp>
-  UpdateImageKeys(wr::TransactionBuilder& aResourceUpdates,
+  UpdateImageKeys(const wr::Epoch& aEpoch,
+                  const wr::PipelineId& aPipelineId,
+                  wr::TransactionBuilder& aResourceUpdates,
                   AsyncImagePipeline* aPipeline,
                   nsTArray<wr::ImageKey>& aKeys);
   Maybe<TextureHost::ResourceUpdateOp>
   UpdateWithoutExternalImage(wr::TransactionBuilder& aResources,
                              TextureHost* aTexture,
                              wr::ImageKey aKey,
                              TextureHost::ResourceUpdateOp);
 
--- a/gfx/layers/wr/WebRenderTextureHost.cpp
+++ b/gfx/layers/wr/WebRenderTextureHost.cpp
@@ -144,17 +144,17 @@ WebRenderTextureHost::NumSubTextures() c
 
 void
 WebRenderTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
                                           ResourceUpdateOp aOp,
                                           const Range<wr::ImageKey>& aImageKeys,
                                           const wr::ExternalImageId& aExtID)
 {
   MOZ_ASSERT(mWrappedTextureHost);
-  MOZ_ASSERT(mExternalImageId == aExtID);
+  MOZ_ASSERT(mExternalImageId == aExtID || SupportsWrNativeTexture());
 
   mWrappedTextureHost->PushResourceUpdates(aResources, aOp, aImageKeys, aExtID);
 }
 
 void
 WebRenderTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
                                        const wr::LayoutRect& aBounds,
                                        const wr::LayoutRect& aClip,
@@ -166,10 +166,16 @@ WebRenderTextureHost::PushDisplayItems(w
 
   mWrappedTextureHost->PushDisplayItems(aBuilder,
                                          aBounds,
                                          aClip,
                                          aFilter,
                                          aImageKeys);
 }
 
+bool
+WebRenderTextureHost::SupportsWrNativeTexture()
+{
+  return mWrappedTextureHost->SupportsWrNativeTexture();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderTextureHost.h
+++ b/gfx/layers/wr/WebRenderTextureHost.h
@@ -72,16 +72,18 @@ public:
                                    const wr::ExternalImageId& aExtID) override;
 
   virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
                                 const wr::LayoutRect& aBounds,
                                 const wr::LayoutRect& aClip,
                                 wr::ImageRendering aFilter,
                                 const Range<wr::ImageKey>& aImageKeys) override;
 
+  virtual bool SupportsWrNativeTexture() override;
+
 protected:
   void CreateRenderTextureHost(const SurfaceDescriptor& aDesc, TextureHost* aTexture);
 
   RefPtr<TextureHost> mWrappedTextureHost;
   wr::ExternalImageId mExternalImageId;
 };
 
 } // namespace layers
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderTextureHostWrapper.cpp
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "WebRenderTextureHostWrapper.h"
+
+#include "mozilla/layers/AsyncImagePipelineManager.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
+#include "mozilla/webrender/RenderTextureHostWrapper.h"
+#include "mozilla/webrender/RenderThread.h"
+
+namespace mozilla {
+namespace layers {
+
+WebRenderTextureHostWrapper::WebRenderTextureHostWrapper(AsyncImagePipelineManager* aManager)
+  : mExternalImageId(aManager->GetNextExternalImageId())
+{
+  MOZ_ASSERT(aManager);
+  MOZ_COUNT_CTOR(WebRenderTextureHostWrapper);
+
+  RefPtr<wr::RenderTextureHost> texture = new wr::RenderTextureHostWrapper();
+  wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(mExternalImageId), texture.forget());
+}
+
+WebRenderTextureHostWrapper::~WebRenderTextureHostWrapper()
+{
+  MOZ_COUNT_DTOR(WebRenderTextureHostWrapper);
+  wr::RenderThread::Get()->UnregisterExternalImage(wr::AsUint64(mExternalImageId));
+}
+
+void
+WebRenderTextureHostWrapper::UpdateWebRenderTextureHost(WebRenderTextureHost* aTextureHost) {
+  MOZ_ASSERT(aTextureHost);
+  mWrTextureHost = aTextureHost;
+  wr::RenderThread::Get()->UpdateRenderTextureHost(wr::AsUint64(mExternalImageId), wr::AsUint64(aTextureHost->GetExternalImageKey()));
+}
+
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderTextureHostWrapper.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 MOZILLA_GFX_WEBRENDERTEXTUREHOSTWRAPPER_H
+#define MOZILLA_GFX_WEBRENDERTEXTUREHOSTWRAPPER_H
+
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderTextureHost;
+class AsyncImagePipelineManager;
+
+class WebRenderTextureHostWrapper
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderTextureHostWrapper)
+
+public:
+  explicit WebRenderTextureHostWrapper(AsyncImagePipelineManager* aManager);
+
+  void UpdateWebRenderTextureHost(WebRenderTextureHost* aTextureHost);
+
+  wr::ExternalImageId GetExternalImageKey() { return mExternalImageId; }
+
+protected:
+  virtual ~WebRenderTextureHostWrapper();
+
+  RefPtr<WebRenderTextureHost> mWrTextureHost;
+  wr::ExternalImageId mExternalImageId;
+};
+
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_WEBRENDERTEXTUREHOSTWRAPPER_H
--- a/gfx/webrender_bindings/RenderTextureHost.h
+++ b/gfx/webrender_bindings/RenderTextureHost.h
@@ -17,27 +17,30 @@ namespace mozilla {
 namespace gl {
 class GLContext;
 }
 
 namespace wr {
 
 class RenderBufferTextureHost;
 class RenderTextureHostOGL;
+class RenderTextureHostWrapper;
 
 class RenderTextureHost
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RenderTextureHost)
 
 public:
   RenderTextureHost();
 
   virtual wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL) = 0;
   virtual void Unlock() = 0;
   virtual void ClearCachedResources() {}
+
+  virtual RenderTextureHostWrapper* AsRenderTextureHostWrapper() { return nullptr; }
 protected:
   virtual ~RenderTextureHost();
 };
 
 } // namespace wr
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_RENDERTEXTUREHOST_H
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderTextureHostWrapper.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "RenderTextureHostWrapper.h"
+
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/SourceSurfaceSharedData.h"
+#include "mozilla/webrender/RenderThread.h"
+
+namespace mozilla {
+namespace wr {
+
+RenderTextureHostWrapper::RenderTextureHostWrapper()
+  : mInited(false)
+  , mLocked(false)
+{
+  MOZ_COUNT_CTOR_INHERITED(RenderTextureHostWrapper, RenderTextureHost);
+}
+
+RenderTextureHostWrapper::~RenderTextureHostWrapper()
+{
+  MOZ_COUNT_DTOR_INHERITED(RenderTextureHostWrapper, RenderTextureHost);
+}
+
+wr::WrExternalImage
+RenderTextureHostWrapper::Lock(uint8_t aChannelIndex, gl::GLContext* aGL)
+{
+  if (!mTextureHost) {
+    MOZ_ASSERT_UNREACHABLE("unexpected to happen");
+    return InvalidToWrExternalImage();
+  }
+
+  mLocked = true;
+  return mTextureHost->Lock(aChannelIndex, aGL);
+}
+
+void
+RenderTextureHostWrapper::Unlock()
+{
+  if (mTextureHost) {
+    mTextureHost->Unlock();
+  }
+  mLocked = false;
+}
+
+void
+RenderTextureHostWrapper::ClearCachedResources()
+{
+  if (mTextureHost) {
+    mTextureHost->ClearCachedResources();
+  }
+}
+
+void
+RenderTextureHostWrapper::UpdateRenderTextureHost(RenderTextureHost* aTextureHost)
+{
+  MOZ_ASSERT(!mInited || RenderThread::IsInRenderThread());
+  MOZ_RELEASE_ASSERT(!mLocked);
+
+  mInited = true;
+  mTextureHost = aTextureHost;
+}
+
+} // namespace wr
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderTextureHostWrapper.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 MOZILLA_GFX_RENDERTEXTUREHOSTWRAPPER_H
+#define MOZILLA_GFX_RENDERTEXTUREHOSTWRAPPER_H
+
+#include "RenderTextureHost.h"
+
+namespace mozilla {
+
+namespace wr {
+
+class RenderTextureHostWrapper final : public RenderTextureHost
+{
+public:
+  explicit RenderTextureHostWrapper();
+
+  wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL) override;
+  void Unlock() override;
+  void ClearCachedResources() override;
+
+  RenderTextureHostWrapper* AsRenderTextureHostWrapper() override { return this; }
+
+  void UpdateRenderTextureHost(RenderTextureHost* aTextureHost);
+  bool IsInited() { return mInited; }
+
+private:
+  ~RenderTextureHostWrapper() override;
+
+  bool mInited;
+  bool mLocked;
+  RefPtr<RenderTextureHost> mTextureHost;
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_RENDERTEXTUREHOSTWRAPPER_H
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -537,16 +537,48 @@ RenderThread::UnregisterExternalImage(ui
       this, &RenderThread::DeferredRenderTextureHostDestroy
     ));
   } else {
     mRenderTextures.erase(it);
   }
 }
 
 void
+RenderThread::UpdateRenderTextureHost(uint64_t aSrcExternalImageId, uint64_t aWrappedExternalImageId)
+{
+  MOZ_ASSERT(aSrcExternalImageId != aWrappedExternalImageId);
+
+  MutexAutoLock lock(mRenderTextureMapLock);
+  if (mHasShutdown) {
+    return;
+  }
+  auto src = mRenderTextures.find(aSrcExternalImageId);
+  auto wrapped = mRenderTextures.find(aWrappedExternalImageId);
+  if (src == mRenderTextures.end() || wrapped == mRenderTextures.end()) {
+    return;
+  }
+  MOZ_ASSERT(src->second->AsRenderTextureHostWrapper());
+  MOZ_ASSERT(!wrapped->second->AsRenderTextureHostWrapper());
+  RenderTextureHostWrapper* wrapper = src->second->AsRenderTextureHostWrapper();
+  if (!wrapper) {
+    MOZ_ASSERT_UNREACHABLE("unexpected to happen");
+    return;
+  }
+  if (!wrapper->IsInited()) {
+    wrapper->UpdateRenderTextureHost(wrapped->second);
+    MOZ_ASSERT(wrapper->IsInited());
+  } else {
+    Loop()->PostTask(NewRunnableMethod<RenderTextureHost*>(
+      "RenderThread::DeferredRenderTextureHostDestroy",
+      wrapper, &RenderTextureHostWrapper::UpdateRenderTextureHost, wrapped->second
+    ));
+  }
+}
+
+void
 RenderThread::UnregisterExternalImageDuringShutdown(uint64_t aExternalImageId)
 {
   MOZ_ASSERT(IsInRenderThread());
   MutexAutoLock lock(mRenderTextureMapLock);
   MOZ_ASSERT(mHasShutdown);
   MOZ_ASSERT(mRenderTextures.find(aExternalImageId) != mRenderTextures.end());
   mRenderTextures.erase(aExternalImageId);
 }
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -136,16 +136,19 @@ public:
   bool Resume(wr::WindowId aWindowId);
 
   /// Can be called from any thread.
   void RegisterExternalImage(uint64_t aExternalImageId, already_AddRefed<RenderTextureHost> aTexture);
 
   /// Can be called from any thread.
   void UnregisterExternalImage(uint64_t aExternalImageId);
 
+  /// Can be called from any thread.
+  void UpdateRenderTextureHost(uint64_t aSrcExternalImageId, uint64_t aWrappedExternalImageId);
+
   /// Can only be called from the render thread.
   void UnregisterExternalImageDuringShutdown(uint64_t aExternalImageId);
 
   /// Can only be called from the render thread.
   RenderTextureHost* GetRenderTexture(WrExternalImageId aExternalImageId);
 
   /// Can be called from any thread.
   bool IsDestroyed(wr::WindowId aWindowId);
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -10,32 +10,34 @@ with Files('**'):
 EXPORTS.mozilla.webrender += [
     'RenderBufferTextureHost.h',
     'RenderCompositor.h',
     'RenderCompositorOGL.h',
     'RendererOGL.h',
     'RenderSharedSurfaceTextureHost.h',
     'RenderTextureHost.h',
     'RenderTextureHostOGL.h',
+    'RenderTextureHostWrapper.h',
     'RenderThread.h',
     'webrender_ffi.h',
     'webrender_ffi_generated.h',
     'WebRenderAPI.h',
     'WebRenderTypes.h',
 ]
 
 UNIFIED_SOURCES += [
     'Moz2DImageRenderer.cpp',
     'RenderBufferTextureHost.cpp',
     'RenderCompositor.cpp',
     'RenderCompositorOGL.cpp',
     'RendererOGL.cpp',
     'RenderSharedSurfaceTextureHost.cpp',
     'RenderTextureHost.cpp',
     'RenderTextureHostOGL.cpp',
+    'RenderTextureHostWrapper.cpp',
     'RenderThread.cpp',
     'WebRenderAPI.cpp',
     'WebRenderTypes.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.webrender += [
         'RenderMacIOSurfaceTextureHostOGL.h',
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1575,17 +1575,17 @@ ActivationEntryMonitor::ActivationEntryM
 
 /*****************************************************************************/
 
 jit::JitActivation::JitActivation(JSContext* cx)
   : Activation(cx, Jit),
     packedExitFP_(nullptr),
     encodedWasmExitReason_(0),
     prevJitActivation_(cx->jitActivation),
-    rematerializedFrames_(nullptr),
+    rematerializedFrames_(),
     ionRecovery_(cx),
     bailoutData_(nullptr),
     lastProfilingFrame_(nullptr),
     lastProfilingCallSite_(nullptr)
 {
     cx->jitActivation = this;
     registerProfiling();
 }
@@ -1602,17 +1602,16 @@ jit::JitActivation::~JitActivation()
     // The BailoutFrameInfo should have unregistered itself from the
     // JitActivations.
     MOZ_ASSERT(!bailoutData_);
 
     // Traps get handled immediately.
     MOZ_ASSERT(!isWasmTrapping());
 
     clearRematerializedFrames();
-    js_delete(rematerializedFrames_);
 }
 
 void
 jit::JitActivation::setBailoutData(jit::BailoutFrameInfo* bailoutData)
 {
     MOZ_ASSERT(!bailoutData_);
     bailoutData_ = bailoutData;
 }
@@ -1651,21 +1650,21 @@ jit::JitActivation::clearRematerializedF
 jit::RematerializedFrame*
 jit::JitActivation::getRematerializedFrame(JSContext* cx, const JSJitFrameIter& iter,
                                            size_t inlineDepth)
 {
     MOZ_ASSERT(iter.activation() == this);
     MOZ_ASSERT(iter.isIonScripted());
 
     if (!rematerializedFrames_) {
-        rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
+        rematerializedFrames_ = cx->make_unique<RematerializedFrameTable>(cx);
         if (!rematerializedFrames_)
             return nullptr;
         if (!rematerializedFrames_->init()) {
-            rematerializedFrames_ = nullptr;
+            rematerializedFrames_.reset();
             ReportOutOfMemory(cx);
             return nullptr;
         }
     }
 
     uint8_t* top = iter.fp();
     RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
     if (!p) {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -18,16 +18,17 @@
 
 #include "gc/Rooting.h"
 #ifdef CHECK_OSIPOINT_REGISTERS
 #include "jit/Registers.h" // for RegisterDump
 #endif
 #include "jit/JSJitFrameIter.h"
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
+#include "js/UniquePtr.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/SavedFrame.h"
 #include "wasm/WasmFrameIter.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmTypes.h"
 
@@ -1629,17 +1630,17 @@ class JitActivation : public Activation
 
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
     // frame pointers (i.e. packedExitFP_) to a vector of rematerializations of all
     // inline frames associated with that frame.
     //
     // This table is lazily initialized by calling getRematerializedFrame.
     typedef GCVector<RematerializedFrame*> RematerializedFrameVector;
     typedef HashMap<uint8_t*, RematerializedFrameVector> RematerializedFrameTable;
-    RematerializedFrameTable* rematerializedFrames_;
+    js::UniquePtr<RematerializedFrameTable> rematerializedFrames_;
 
     // This vector is used to remember the outcome of the evaluation of recover
     // instructions.
     //
     // RInstructionResults are appended into this vector when Snapshot values
     // have to be read, or when the evaluation has to run before some mutating
     // code.  Each RInstructionResults belongs to one frame which has to bailout
     // as soon as we get back to it.
--- a/media/gmp-clearkey/0.1/moz.build
+++ b/media/gmp-clearkey/0.1/moz.build
@@ -53,21 +53,28 @@ TEST_DIRS += [
 ]
 
 DisableStlWrapping()
 DEFINES['MOZ_NO_MOZALLOC'] = True
 
 USE_LIBS += ['psshparser']
 
 # Suppress warnings in third-party code.
-if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
+if CONFIG['CC_TYPE'] in ('clang', 'clang-cl', 'gcc'):
     CFLAGS += [
         '-Wno-missing-braces',
         '-Wno-pointer-to-int-cast',
         '-Wno-sign-compare',
+    ]
+elif CONFIG['CC_TYPE'] == 'msvc':
+    CFLAGS += [
+        '-wd4090',                  # '=' : different 'const' qualifiers
+    ]
+
+if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
+    CFLAGS += [
         '-include', 'stdio.h',      # for sprintf() prototype
         '-include', 'unistd.h',     # for getpid() prototype
     ]
 elif CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
     CFLAGS += [
         '-FI', 'stdio.h',           # for sprintf() prototype
-        '-wd4090',                  # '=' : different 'const' qualifiers
     ]
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1047,16 +1047,22 @@ pref("toolkit.asyncshutdown.log", false)
 pref("browser.dom.window.dump.enabled", false, sticky);
 #else
 pref("browser.dom.window.dump.enabled", true, sticky);
 #endif
 
 // Controls whether EventEmitter module throws dump message on each emit
 pref("toolkit.dump.emit", false);
 
+// Enable recording/replaying executions.
+#if defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
+pref("devtools.recordreplay.enabled", false);
+pref("devtools.recordreplay.enableRewinding", true);
+#endif
+
 // view source
 pref("view_source.syntax_highlight", true);
 pref("view_source.wrap_long_lines", false);
 pref("view_source.editor.path", "");
 // allows to add further arguments to the editor; use the %LINE% placeholder
 // for jumping to a specific line (e.g. "/line:%LINE%" or "--goto %LINE%")
 pref("view_source.editor.args", "");
 
--- a/security/nss.symbols
+++ b/security/nss.symbols
@@ -105,16 +105,17 @@ CERT_FindUserCertsByUsage
 CERT_FinishCertificateRequestAttributes
 CERT_FinishExtensions
 CERT_ForcePostMethodForOCSP
 CERT_FreeNicknames
 CERT_GenTime2FormattedAscii_Util
 CERT_GetCertChainFromCert
 CERT_GetCertEmailAddress
 CERT_GetCertificateRequestExtensions
+CERT_GetCertKeyType
 CERT_GetCertTimes
 CERT_GetCertTrust
 CERT_GetCommonName
 CERT_GetConstrainedCertificateNames
 CERT_GetCountryName
 CERT_GetDefaultCertDB
 CERT_GetFirstEmailAddress
 CERT_GetGeneralNameTypeFromString
@@ -272,16 +273,17 @@ NSS_SetDomesticPolicy
 NSS_Shutdown
 NSSSMIME_GetVersion
 NSS_SMIMESignerInfo_SaveSMIMEProfile
 NSS_SMIMEUtil_FindBulkAlgForRecipients
 NSSSSL_GetVersion
 #ifdef XP_WIN
 _NSSUTIL_Access
 #endif
+NSSUTIL_AddNSSFlagToModuleSpec
 NSSUTIL_ArgDecodeNumber
 NSSUTIL_ArgFetchValue
 NSSUTIL_ArgGetLabel
 NSSUTIL_ArgGetParamValue
 NSSUTIL_ArgHasFlag
 NSSUTIL_ArgIsBlank
 NSSUTIL_ArgParseCipherFlags
 NSSUTIL_ArgParseModuleSpec
@@ -369,16 +371,17 @@ PK11_GetLowLevelKeyIDForPrivateKey
 PK11_GetMechanism
 PK11_GetModInfo
 PK11_GetModuleURI
 PK11_GetNextSafe
 PK11_GetNextSymKey
 PK11_GetPadMechanism
 PK11_GetPrivateKeyNickname
 PK11_GetPrivateModulusLen
+PK11_GetSlotFromPrivateKey
 PK11_GetSlotID
 PK11_GetSlotInfo
 PK11_GetSlotName
 PK11_GetSlotSeries
 PK11_GetSymKeyNickname
 PK11_GetTokenInfo
 PK11_GetTokenName
 PK11_GetTokenURI
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-53c2ee896c57
+4a086733554e
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -0,0 +1,5 @@
+
+1 Added function:
+
+  'function KeyType CERT_GetCertKeyType(const CERTSubjectPublicKeyInfo*)'    {CERT_GetCertKeyType@@NSS_3.39}
+
--- a/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
@@ -0,0 +1,5 @@
+
+1 Added function:
+
+  'function char* NSSUTIL_AddNSSFlagToModuleSpec(char*, char*)'    {NSSUTIL_AddNSSFlagToModuleSpec@@NSSUTIL_3.39}
+
--- a/security/nss/automation/release/nspr-version.txt
+++ b/security/nss/automation/release/nspr-version.txt
@@ -1,9 +1,9 @@
-4.19
+4.20
 
 # The first line of this file must contain the human readable NSPR
 # version number, which is the minimum required version of NSPR
 # that is supported by this version of NSS.
 #
 # This information is used by release automation,
 # when creating an NSS source archive.
 #
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -923,16 +923,19 @@ function scheduleTests(task_build, task_
     name: "EC tests", symbol: "EC", tests: "ec"
   }));
   queue.scheduleTask(merge(no_cert_base, {
     name: "Lowhash tests", symbol: "Lowhash", tests: "lowhash"
   }));
   queue.scheduleTask(merge(no_cert_base, {
     name: "SDR tests", symbol: "SDR", tests: "sdr"
   }));
+  queue.scheduleTask(merge(no_cert_base, {
+    name: "Policy tests", symbol: "Policy", tests: "policy"
+  }));
 
   // Schedule tests that need certificates.
   let cert_base = merge(test_base, {parent: task_cert});
   queue.scheduleTask(merge(cert_base, {
     name: "CRMF tests", symbol: "CRMF", tests: "crmf"
   }));
   queue.scheduleTask(merge(cert_base, {
     name: "DB tests", symbol: "DB", tests: "dbtests"
--- a/security/nss/automation/taskcluster/graph/src/try_syntax.js
+++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js
@@ -32,17 +32,17 @@ function parseOptions(opts) {
   if (platforms.length == 0 && opts.platform != "none") {
     platforms = allPlatforms;
   }
 
   // Parse unit tests.
   let aliases = {"gtests": "gtest"};
   let allUnitTests = ["bogo", "crmf", "chains", "cipher", "db", "ec", "fips",
                       "gtest", "interop", "lowhash", "merge", "sdr", "smime", "tools",
-                      "ssl", "mpi", "scert", "spki"];
+                      "ssl", "mpi", "scert", "spki", "policy"];
   let unittests = intersect(opts.unittests.split(/\s*,\s*/).map(t => {
     return aliases[t] || t;
   }), allUnitTests);
 
   // If the given value is "all" run all tests.
   // If it's nonsense then don't run any tests.
   if (opts.unittests == "all") {
     unittests = allUnitTests;
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -851,51 +851,69 @@ SECItemToHex(const SECItem *item, char *
         for (; len > 0; --len, dst += 2) {
             sprintf(dst, "%02x", *src++);
         }
         *dst = '\0';
     }
 }
 
 static const char *const keyTypeName[] = {
-    "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec", "rsaPss"
+    "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec", "rsaPss", "rsaOaep"
 };
 
 #define MAX_CKA_ID_BIN_LEN 20
 #define MAX_CKA_ID_STR_LEN 40
 
+/* output human readable key ID in buffer, which should have at least
+ * MAX_CKA_ID_STR_LEN + 3 octets (quotations and a null terminator) */
+static void
+formatPrivateKeyID(SECKEYPrivateKey *privkey, char *buffer)
+{
+    SECItem *ckaID;
+
+    ckaID = PK11_GetLowLevelKeyIDForPrivateKey(privkey);
+    if (!ckaID) {
+        strcpy(buffer, "(no CKA_ID)");
+    } else if (ItemIsPrintableASCII(ckaID)) {
+        int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
+        buffer[0] = '"';
+        memcpy(buffer + 1, ckaID->data, len);
+        buffer[1 + len] = '"';
+        buffer[2 + len] = '\0';
+    } else {
+        /* print ckaid in hex */
+        SECItem idItem = *ckaID;
+        if (idItem.len > MAX_CKA_ID_BIN_LEN)
+            idItem.len = MAX_CKA_ID_BIN_LEN;
+        SECItemToHex(&idItem, buffer);
+    }
+    SECITEM_ZfreeItem(ckaID, PR_TRUE);
+}
+
 /* print key number, key ID (in hex or ASCII), key label (nickname) */
 static SECStatus
 PrintKey(PRFileDesc *out, const char *nickName, int count,
          SECKEYPrivateKey *key, void *pwarg)
 {
-    SECItem *ckaID;
     char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
+    CERTCertificate *cert;
+    KeyType keyType;
 
     pwarg = NULL;
-    ckaID = PK11_GetLowLevelKeyIDForPrivateKey(key);
-    if (!ckaID) {
-        strcpy(ckaIDbuf, "(no CKA_ID)");
-    } else if (ItemIsPrintableASCII(ckaID)) {
-        int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
-        ckaIDbuf[0] = '"';
-        memcpy(ckaIDbuf + 1, ckaID->data, len);
-        ckaIDbuf[1 + len] = '"';
-        ckaIDbuf[2 + len] = '\0';
+
+    formatPrivateKeyID(key, ckaIDbuf);
+    cert = PK11_GetCertFromPrivateKey(key);
+    if (cert) {
+        keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
+        CERT_DestroyCertificate(cert);
     } else {
-        /* print ckaid in hex */
-        SECItem idItem = *ckaID;
-        if (idItem.len > MAX_CKA_ID_BIN_LEN)
-            idItem.len = MAX_CKA_ID_BIN_LEN;
-        SECItemToHex(&idItem, ckaIDbuf);
+        keyType = key->keyType;
     }
-
     PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count,
-               keyTypeName[key->keyType], ckaIDbuf, nickName);
-    SECITEM_ZfreeItem(ckaID, PR_TRUE);
+               keyTypeName[keyType], ckaIDbuf, nickName);
 
     return SECSuccess;
 }
 
 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
 static SECStatus
 ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType,
                void *pwarg)
@@ -997,17 +1015,17 @@ ListKeys(PK11SlotInfo *slot, const char 
         PR_fprintf(PR_STDOUT, fmt, progName, PK11_GetTokenName(slot),
                    PK11_GetSlotName(slot));
         rv = ListKeysInSlot(slot, nickName, keyType, pwdata);
     }
     return rv;
 }
 
 static SECStatus
-DeleteKey(char *nickname, secuPWData *pwdata)
+DeleteCertAndKey(char *nickname, secuPWData *pwdata)
 {
     SECStatus rv;
     CERTCertificate *cert;
     PK11SlotInfo *slot;
 
     slot = PK11_GetInternalKeySlot();
     if (PK11_NeedLogin(slot)) {
         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
@@ -1026,16 +1044,71 @@ DeleteKey(char *nickname, secuPWData *pw
     if (rv != SECSuccess) {
         SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
     }
     CERT_DestroyCertificate(cert);
     PK11_FreeSlot(slot);
     return rv;
 }
 
+static SECKEYPrivateKey *
+findPrivateKeyByID(PK11SlotInfo *slot, const char *ckaID, secuPWData *pwarg)
+{
+    PORTCheapArenaPool arena;
+    SECItem ckaIDItem = { 0 };
+    SECKEYPrivateKey *privkey = NULL;
+    SECStatus rv;
+
+    if (PK11_NeedLogin(slot)) {
+        rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "could not authenticate to token %s.",
+                            PK11_GetTokenName(slot));
+            return NULL;
+        }
+    }
+
+    if (0 == PL_strncasecmp("0x", ckaID, 2)) {
+        ckaID += 2; /* skip leading "0x" */
+    }
+    PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
+    if (SECU_HexString2SECItem(&arena.arena, &ckaIDItem, ckaID)) {
+        privkey = PK11_FindKeyByKeyID(slot, &ckaIDItem, pwarg);
+    }
+    PORT_DestroyCheapArena(&arena);
+    return privkey;
+}
+
+static SECStatus
+DeleteKey(SECKEYPrivateKey *privkey, secuPWData *pwarg)
+{
+    SECStatus rv;
+    PK11SlotInfo *slot;
+
+    slot = PK11_GetSlotFromPrivateKey(privkey);
+    if (PK11_NeedLogin(slot)) {
+        rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "could not authenticate to token %s.",
+                            PK11_GetTokenName(slot));
+            return SECFailure;
+        }
+    }
+
+    rv = PK11_DeleteTokenPrivateKey(privkey, PR_TRUE);
+    if (rv != SECSuccess) {
+        char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
+        formatPrivateKeyID(privkey, ckaIDbuf);
+        SECU_PrintError("problem deleting private key \"%s\"\n", ckaIDbuf);
+    }
+
+    PK11_FreeSlot(slot);
+    return rv;
+}
+
 /*
  *  L i s t M o d u l e s
  *
  *  Print a list of the PKCS11 modules that are
  *  available. This is useful for smartcard people to
  *  make sure they have the drivers loaded.
  *
  */
@@ -1095,17 +1168,19 @@ PrintSyntax()
         "\t\t [-6 | --extKeyUsage [extKeyUsageKeyword,...]] [-7 emailAddrs]\n"
         "\t\t [-8 dns-names] [-a]\n",
         progName);
     FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s --rename -n cert-name --new-n new-cert-name\n"
         "\t\t [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
         progName);
-    FPS "\t%s -F -n nickname [-d certdir] [-P dbprefix]\n",
+    FPS "\t%s -F -n cert-name [-d certdir] [-P dbprefix]\n",
+        progName);
+    FPS "\t%s -F -k key-id [-d certdir] [-P dbprefix]\n",
         progName);
     FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
         "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
         "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
         "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
@@ -1385,16 +1460,18 @@ luF(enum usage_level ul, const char *com
     int is_my_command = (command && 0 == strcmp(command, "F"));
     if (ul == usage_all || !command || is_my_command)
     FPS "%-15s Delete a key and associated certificate from the database\n",
         "-F");
     if (ul == usage_selected && !is_my_command)
         return;
     FPS "%-20s The nickname of the key to delete\n",
         "   -n cert-name");
+    FPS "%-20s The key id of the key to delete, obtained using -K\n",
+        "   -k key-id");
     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
         "   -d certdir");
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
     FPS "\n");
 }
 
 static void
@@ -2939,20 +3016,19 @@ certutil_main(int argc, char **argv, PRB
         certutil.commands[cmd_PrintHelp].activated ||
         certutil.commands[cmd_ListKeys].activated ||
         certutil.commands[cmd_ListModules].activated ||
         certutil.commands[cmd_CheckCertValidity].activated ||
         certutil.commands[cmd_Version].activated) {
         readOnly = !certutil.options[opt_RW].activated;
     }
 
-    /*  -A, -D, -F, -M, -S, -V, and all require -n  */
+    /*  -A, -D, -M, -S, -V, and all require -n  */
     if ((certutil.commands[cmd_AddCert].activated ||
          certutil.commands[cmd_DeleteCert].activated ||
-         certutil.commands[cmd_DeleteKey].activated ||
          certutil.commands[cmd_DumpChain].activated ||
          certutil.commands[cmd_ModifyCertTrust].activated ||
          certutil.commands[cmd_CreateAndAddCert].activated ||
          certutil.commands[cmd_CheckCertValidity].activated) &&
         !certutil.options[opt_Nickname].activated) {
         PR_fprintf(PR_STDERR,
                    "%s -%c: nickname is required for this command (-n).\n",
                    progName, commandToRun);
@@ -3029,16 +3105,26 @@ certutil_main(int argc, char **argv, PRB
 
         PR_fprintf(PR_STDERR,
                    "%s --rename: specify an old nickname (-n) and\n"
                    "   a new nickname (--new-n).\n",
                    progName);
         return 255;
     }
 
+    /* Delete needs a nickname or a key ID */
+    if (certutil.commands[cmd_DeleteKey].activated &&
+        !(certutil.options[opt_Nickname].activated || keysource)) {
+        PR_fprintf(PR_STDERR,
+                   "%s -%c: specify a nickname (-n) or\n"
+                   "   a key ID (-k).\n",
+                   commandToRun, progName);
+        return 255;
+    }
+
     /* Upgrade/Merge needs a source database and a upgrade id. */
     if (certutil.commands[cmd_UpgradeMerge].activated &&
         !(certutil.options[opt_SourceDir].activated &&
           certutil.options[opt_UpgradeID].activated)) {
 
         PR_fprintf(PR_STDERR,
                    "%s --upgrade-merge: specify an upgrade database directory "
                    "(--source-dir) and\n"
@@ -3391,17 +3477,29 @@ certutil_main(int argc, char **argv, PRB
     }
     /*  Rename cert (--rename)  */
     if (certutil.commands[cmd_Rename].activated) {
         rv = RenameCert(certHandle, name, newName, &pwdata);
         goto shutdown;
     }
     /*  Delete key (-F)  */
     if (certutil.commands[cmd_DeleteKey].activated) {
-        rv = DeleteKey(name, &pwdata);
+        if (certutil.options[opt_Nickname].activated) {
+            rv = DeleteCertAndKey(name, &pwdata);
+        } else {
+            privkey = findPrivateKeyByID(slot, keysource, &pwdata);
+            if (!privkey) {
+                SECU_PrintError(progName, "%s is not a key-id", keysource);
+                rv = SECFailure;
+            } else {
+                rv = DeleteKey(privkey, &pwdata);
+                /* already destroyed by PK11_DeleteTokenPrivateKey */
+                privkey = NULL;
+            }
+        }
         goto shutdown;
     }
     /*  Modify trust attribute for cert (-M)  */
     if (certutil.commands[cmd_ModifyCertTrust].activated) {
         rv = ChangeTrustAttributes(certHandle, slot, name,
                                    certutil.options[opt_Trust].arg, &pwdata);
         goto shutdown;
     }
@@ -3463,40 +3561,18 @@ certutil_main(int argc, char **argv, PRB
             keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource);
             if (!keycert) {
                 keycert = PK11_FindCertFromNickname(keysource, NULL);
             }
 
             if (keycert) {
                 privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata);
             } else {
-                PLArenaPool *arena = NULL;
-                SECItem keyidItem = { 0 };
-                char *keysourcePtr = keysource;
                 /* Interpret keysource as CKA_ID */
-                if (PK11_NeedLogin(slot)) {
-                    rv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
-                    if (rv != SECSuccess) {
-                        SECU_PrintError(progName, "could not authenticate to token %s.",
-                                        PK11_GetTokenName(slot));
-                        return SECFailure;
-                    }
-                }
-                if (0 == PL_strncasecmp("0x", keysource, 2)) {
-                    keysourcePtr = keysource + 2; // skip leading "0x"
-                }
-                arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-                if (!arena) {
-                    SECU_PrintError(progName, "unable to allocate arena");
-                    return SECFailure;
-                }
-                if (SECU_HexString2SECItem(arena, &keyidItem, keysourcePtr)) {
-                    privkey = PK11_FindKeyByKeyID(slot, &keyidItem, &pwdata);
-                }
-                PORT_FreeArena(arena, PR_FALSE);
+                privkey = findPrivateKeyByID(slot, keysource, &pwdata);
             }
 
             if (!privkey) {
                 SECU_PrintError(
                     progName,
                     "%s is neither a key-type nor a nickname nor a key-id", keysource);
                 return SECFailure;
             }
--- a/security/nss/cmd/manifest.mn
+++ b/security/nss/cmd/manifest.mn
@@ -42,16 +42,17 @@ NSS_SRCDIRS = \
  crmftest \
  dbtest \
  derdump  \
  digest  \
  httpserv  \
  listsuites \
  makepqg  \
  multinit \
+ nss-policy-check \
  ocspclnt  \
  ocspresp \
  oidcalc  \
  p7content  \
  p7env  \
  p7sign  \
  p7verify  \
  pk12util \
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/nss-policy-check/Makefile
@@ -0,0 +1,47 @@
+#! gmake
+#
+# 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/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY).   #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL)          #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL)       #
+#######################################################################
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
+#######################################################################
+
+include ../platlibs.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL)                              #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL)                           #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL).                              #
+#######################################################################
+
+
+include ../platrules.mk
+
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/nss-policy-check/manifest.mn
@@ -0,0 +1,15 @@
+#
+# 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/.
+
+CORE_DEPTH = ../..
+
+MODULE = nss
+
+CSRCS = nss-policy-check.c
+
+REQUIRES = seccmd
+
+PROGRAM = nss-policy-check
+
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/nss-policy-check/nss-policy-check.c
@@ -0,0 +1,206 @@
+/* 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 program can be used to check the validity of a NSS crypto policy
+ * configuration file, specified using a config= line.
+ *
+ * Exit codes:
+ *  failure: 2
+ *  warning: 1
+ *  success: 0
+ */
+
+#include <limits.h>
+#include <errno.h>
+#include <stdio.h>
+#include "utilparst.h"
+#include "nss.h"
+#include "secport.h"
+#include "secutil.h"
+#include "secmod.h"
+#include "ssl.h"
+#include "prenv.h"
+
+const char *sWarn = "WARN";
+const char *sInfo = "INFO";
+
+void
+get_tls_info(SSLProtocolVariant protocolVariant, const char *display)
+{
+    SSLVersionRange vrange_supported, vrange_enabled;
+    unsigned num_enabled = 0;
+    PRBool failed = PR_FALSE;
+
+    /* We assume SSL v2 is inactive, and therefore SSL_VersionRangeGetDefault
+     * gives complete information. */
+    if ((SSL_VersionRangeGetSupported(protocolVariant, &vrange_supported) != SECSuccess) ||
+        (SSL_VersionRangeGetDefault(protocolVariant, &vrange_enabled) != SECSuccess) ||
+        !vrange_enabled.min ||
+        !vrange_enabled.max ||
+        vrange_enabled.max < vrange_supported.min ||
+        vrange_enabled.min > vrange_supported.max) {
+        failed = PR_TRUE;
+    } else {
+        if (vrange_enabled.min < vrange_supported.min) {
+            vrange_enabled.min = vrange_supported.min;
+        }
+        if (vrange_enabled.max > vrange_supported.max) {
+            vrange_enabled.max = vrange_supported.max;
+        }
+        if (vrange_enabled.min > vrange_enabled.max) {
+            failed = PR_TRUE;
+        }
+    }
+    if (failed) {
+        num_enabled = 0;
+    } else {
+        num_enabled = vrange_enabled.max - vrange_enabled.min + 1;
+    }
+    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s-VERSIONS: %u\n",
+            num_enabled ? sInfo : sWarn, display, num_enabled);
+    if (!num_enabled) {
+        PR_SetEnv("NSS_POLICY_WARN=1");
+    }
+}
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+int
+main(int argc, char **argv)
+{
+    const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
+    int i;
+    SECStatus rv;
+    SECMODModule *module = NULL;
+    char path[PATH_MAX];
+    const char *filename;
+    char moduleSpec[1024 + PATH_MAX];
+    unsigned num_enabled = 0;
+    int result = 0;
+    int fullPathLen;
+
+    if (argc != 2) {
+        fprintf(stderr, "Syntax: nss-policy-check <path-to-policy-file>\n");
+        result = 2;
+        goto loser_no_shutdown;
+    }
+
+    fullPathLen = strlen(argv[1]);
+
+    if (!fullPathLen || PR_Access(argv[1], PR_ACCESS_READ_OK) != PR_SUCCESS) {
+        fprintf(stderr, "Error: cannot read file %s\n", argv[1]);
+        result = 2;
+        goto loser_no_shutdown;
+    }
+
+    if (fullPathLen >= PATH_MAX) {
+        fprintf(stderr, "Error: filename parameter is too long\n");
+        result = 2;
+        goto loser_no_shutdown;
+    }
+
+    path[0] = 0;
+    filename = argv[1] + fullPathLen - 1;
+    while ((filename > argv[1]) && (*filename != NSSUTIL_PATH_SEPARATOR[0])) {
+        filename--;
+    }
+
+    if (filename == argv[1]) {
+        PORT_Strcpy(path, ".");
+    } else {
+        filename++; /* Go past the path separator. */
+        PORT_Strncat(path, argv[1], (filename - argv[1]));
+    }
+
+    PR_SetEnv("NSS_IGNORE_SYSTEM_POLICY=1");
+    rv = NSS_NoDB_Init(NULL);
+    if (rv != SECSuccess) {
+        fprintf(stderr, "NSS_Init failed: %s\n", PORT_ErrorToString(PR_GetError()));
+        result = 2;
+        goto loser_no_shutdown;
+    }
+
+    PR_SetEnv("NSS_POLICY_LOADED=0");
+    PR_SetEnv("NSS_POLICY_FAIL=0");
+    PR_SetEnv("NSS_POLICY_WARN=0");
+
+    sprintf(moduleSpec,
+            "name=\"Policy File\" "
+            "parameters=\"configdir='sql:%s' "
+            "secmod='%s' "
+            "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
+            "NSS=\"flags=internal,moduleDB,skipFirst,moduleDBOnly,critical,printPolicyFeedback\"",
+            path, filename);
+
+    module = SECMOD_LoadModule(moduleSpec, NULL, PR_TRUE);
+    if (!module || !module->loaded || atoi(PR_GetEnvSecure("NSS_POLICY_LOADED")) != 1) {
+        fprintf(stderr, "Error: failed to load policy file\n");
+        result = 2;
+        goto loser;
+    }
+
+    rv = SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE);
+    if (rv != SECSuccess) {
+        fprintf(stderr, "enable SSL_SECURITY failed: %s\n", PORT_ErrorToString(PR_GetError()));
+        result = 2;
+        goto loser;
+    }
+
+    for (i = 0; i < SSL_NumImplementedCiphers; i++) {
+        PRUint16 suite = cipherSuites[i];
+        PRBool enabled;
+        SSLCipherSuiteInfo info;
+
+        rv = SSL_CipherPrefGetDefault(suite, &enabled);
+        if (rv != SECSuccess) {
+            fprintf(stderr,
+                    "SSL_CipherPrefGetDefault didn't like value 0x%04x (i = %d): %s\n",
+                    suite, i, PORT_ErrorToString(PR_GetError()));
+            continue;
+        }
+        rv = SSL_GetCipherSuiteInfo(suite, &info, (int)(sizeof info));
+        if (rv != SECSuccess) {
+            fprintf(stderr,
+                    "SSL_GetCipherSuiteInfo didn't like value 0x%04x (i = %d): %s\n",
+                    suite, i, PORT_ErrorToString(PR_GetError()));
+            continue;
+        }
+        if (enabled) {
+            ++num_enabled;
+            fprintf(stderr, "NSS-POLICY-INFO: ciphersuite %s is enabled\n", info.cipherSuiteName);
+        }
+    }
+    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CIPHERSUITES: %u\n", num_enabled ? sInfo : sWarn, num_enabled);
+    if (!num_enabled) {
+        PR_SetEnv("NSS_POLICY_WARN=1");
+    }
+
+    get_tls_info(ssl_variant_stream, "TLS");
+    get_tls_info(ssl_variant_datagram, "DTLS");
+
+    if (atoi(PR_GetEnvSecure("NSS_POLICY_FAIL")) != 0) {
+        result = 2;
+    } else if (atoi(PR_GetEnvSecure("NSS_POLICY_WARN")) != 0) {
+        result = 1;
+    }
+
+loser:
+    if (module) {
+        SECMOD_DestroyModule(module);
+    }
+    rv = NSS_Shutdown();
+    if (rv != SECSuccess) {
+        fprintf(stderr, "NSS_Shutdown failed: %s\n", PORT_ErrorToString(PR_GetError()));
+        result = 2;
+    }
+loser_no_shutdown:
+    if (result == 2) {
+        fprintf(stderr, "NSS-POLICY-FAIL\n");
+    } else if (result == 1) {
+        fprintf(stderr, "NSS-POLICY-WARN\n");
+    }
+    return result;
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/nss-policy-check/nss-policy-check.gyp
@@ -0,0 +1,24 @@
+# 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/.
+{
+  'includes': [
+    '../../coreconf/config.gypi',
+    '../../cmd/platlibs.gypi'
+  ],
+  'targets': [
+    {
+      'target_name': 'nss-policy-check',
+      'type': 'executable',
+      'sources': [
+        'nss-policy-check.c'
+      ],
+      'dependencies': [
+        '<(DEPTH)/exports.gyp:nss_exports'
+      ]
+    }
+  ],
+  'variables': {
+    'module': 'nss'
+  }
+}
\ No newline at end of file
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/doc/certutil.xml
+++ b/security/nss/doc/certutil.xml
@@ -79,17 +79,17 @@
 
       <varlistentry>
         <term>-E </term>
         <listitem><para>Add an email certificate to the certificate database.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term>-F</term>
-        <listitem><para>Delete a private key and the associated certificate from a database. Specify the key to delete with the -n argument. Specify the database from which to delete the key with the 
+        <listitem><para>Delete a private key and the associated certificate from a database. Specify the key to delete with the -n argument or the -k argument. Specify the database from which to delete the key with the
 <option>-d</option> argument.
 </para>
 <para>
 Some smart cards do not let you remove a public key you have generated. In such a case, only the private key is deleted from the key pair.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term>-G </term>
--- a/security/nss/doc/html/certutil.html
+++ b/security/nss/doc/html/certutil.html
@@ -1,13 +1,13 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>CERTUTIL</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"><link rel="home" href="index.html" title="CERTUTIL"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">CERTUTIL</th></tr></table><hr></div><div class="refentry"><a name="certutil"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>certutil — Manage keys and certificate in both NSS databases and other NSS tokens</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">certutil</code>  [<em class="replaceable"><code>options</code></em>] [[<em class="replaceable"><code>arguments</code></em>]]</p></div></div><div class="refsection"><a name="idm140440587239488"></a><h2>STATUS</h2><p>This documentation is still work in progress. Please contribute to the initial review in <a class="ulink" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836477" target="_top">Mozilla NSS bug 836477</a>
-    </p></div><div class="refsection"><a name="description"></a><h2>Description</h2><p>The Certificate Database Tool, <span class="command"><strong>certutil</strong></span>, is a command-line utility that can create and modify certificate and key databases. It can specifically list, generate, modify, or delete certificates, create or change the password, generate new public and private key pairs, display the contents of the key database, or delete key pairs within the key database.</p><p>Certificate issuance, part of the key and certificate management process, requires that keys and certificates be created in the key database. This document discusses certificate and key database management. For information on the security module database management, see the <span class="command"><strong>modutil</strong></span> manpage.</p></div><div class="refsection"><a name="options"></a><h2>Command Options and Arguments</h2><p>Running <span class="command"><strong>certutil</strong></span> always requires one and only one command option to specify the type of certificate operation. Each command option may take zero or more arguments. The command option <code class="option">-H</code> will list all the command options and their relevant arguments.</p><p><span class="command"><strong>Command Options</strong></span></p><div class="variablelist"><dl class="variablelist"><dt><span class="term">-A </span></dt><dd><p>Add an existing certificate to a certificate database. The certificate database should already exist; if one is not present, this command option will initialize one by default.</p></dd><dt><span class="term">-B</span></dt><dd><p>Run a series of commands from the specified batch file. This requires the <code class="option">-i</code> argument.</p></dd><dt><span class="term">-C </span></dt><dd><p>Create a new binary certificate file from a binary certificate request file. Use the <code class="option">-i</code> argument to specify the certificate request file. If this argument is not used, <span class="command"><strong>certutil</strong></span> prompts for a filename. </p></dd><dt><span class="term">-D </span></dt><dd><p>Delete a certificate from the certificate database.</p></dd><dt><span class="term">--rename </span></dt><dd><p>Change the database nickname of a certificate.</p></dd><dt><span class="term">-E </span></dt><dd><p>Add an email certificate to the certificate database.</p></dd><dt><span class="term">-F</span></dt><dd><p>Delete a private key from a key database. Specify the key to delete with the -n argument. Specify the database from which to delete the key with the 
-<code class="option">-d</code> argument. Use the <code class="option">-k</code> argument to specify explicitly whether to delete a DSA, RSA, or ECC key. If you don't use the <code class="option">-k</code> argument, the option looks for an RSA key matching the specified nickname. 
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>CERTUTIL</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"><link rel="home" href="index.html" title="CERTUTIL"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">CERTUTIL</th></tr></table><hr></div><div class="refentry"><a name="certutil"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>certutil — Manage keys and certificate in both NSS databases and other NSS tokens</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">certutil</code>  [<em class="replaceable"><code>options</code></em>] [[<em class="replaceable"><code>arguments</code></em>]]</p></div></div><div class="refsection"><a name="idm45522631704896"></a><h2>STATUS</h2><p>This documentation is still work in progress. Please contribute to the initial review in <a class="ulink" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836477" target="_top">Mozilla NSS bug 836477</a>
+    </p></div><div class="refsection"><a name="description"></a><h2>Description</h2><p>The Certificate Database Tool, <span class="command"><strong>certutil</strong></span>, is a command-line utility that can create and modify certificate and key databases. It can specifically list, generate, modify, or delete certificates, create or change the password, generate new public and private key pairs, display the contents of the key database, or delete key pairs within the key database.</p><p>Certificate issuance, part of the key and certificate management process, requires that keys and certificates be created in the key database. This document discusses certificate and key database management. For information on the security module database management, see the <span class="command"><strong>modutil</strong></span> manpage.</p></div><div class="refsection"><a name="options"></a><h2>Command Options and Arguments</h2><p>Running <span class="command"><strong>certutil</strong></span> always requires one and only one command option to specify the type of certificate operation. Each command option may take zero or more arguments. The command option <code class="option">-H</code> will list all the command options and their relevant arguments.</p><p><span class="command"><strong>Command Options</strong></span></p><div class="variablelist"><dl class="variablelist"><dt><span class="term">-A </span></dt><dd><p>Add an existing certificate to a certificate database. The certificate database should already exist; if one is not present, this command option will initialize one by default.</p></dd><dt><span class="term">-B</span></dt><dd><p>Run a series of commands from the specified batch file. This requires the <code class="option">-i</code> argument.</p></dd><dt><span class="term">-C </span></dt><dd><p>Create a new binary certificate file from a binary certificate request file. Use the <code class="option">-i</code> argument to specify the certificate request file. If this argument is not used, <span class="command"><strong>certutil</strong></span> prompts for a filename. </p></dd><dt><span class="term">-D </span></dt><dd><p>Delete a certificate from the certificate database.</p></dd><dt><span class="term">--rename </span></dt><dd><p>Change the database nickname of a certificate.</p></dd><dt><span class="term">-E </span></dt><dd><p>Add an email certificate to the certificate database.</p></dd><dt><span class="term">-F</span></dt><dd><p>Delete a private key and the associated certificate from a database. Specify the key to delete with the -n argument or the -k argument. Specify the database from which to delete the key with the
+<code class="option">-d</code> argument.
 </p><p>
-When you delete keys, be sure to also remove any certificates associated with those keys from the certificate database, by using -D. Some smart cards do not let you remove a public key you have generated. In such a case, only the private key is deleted from the key pair. You can display the public key with the command certutil -K -h tokenname. </p></dd><dt><span class="term">-G </span></dt><dd><p>Generate a new public and private key pair within a key database. The key database should already exist; if one is not present, this command option will initialize one by default. Some smart cards can store only one key pair. If you create a new key pair for such a card, the previous pair is overwritten.</p></dd><dt><span class="term">-H </span></dt><dd><p>Display a list of the command options and arguments.</p></dd><dt><span class="term">-K </span></dt><dd><p>List the key ID of keys in the key database. A key ID is the modulus of the RSA key or the publicValue of the DSA key. IDs are displayed in hexadecimal ("0x" is not shown).</p></dd><dt><span class="term">-L </span></dt><dd><p>List all the certificates, or display information about a named certificate, in a certificate database.
+Some smart cards do not let you remove a public key you have generated. In such a case, only the private key is deleted from the key pair.</p></dd><dt><span class="term">-G </span></dt><dd><p>Generate a new public and private key pair within a key database. The key database should already exist; if one is not present, this command option will initialize one by default. Some smart cards can store only one key pair. If you create a new key pair for such a card, the previous pair is overwritten.</p></dd><dt><span class="term">-H </span></dt><dd><p>Display a list of the command options and arguments.</p></dd><dt><span class="term">-K </span></dt><dd><p>List the key ID of keys in the key database. A key ID is the modulus of the RSA key or the publicValue of the DSA key. IDs are displayed in hexadecimal ("0x" is not shown).</p></dd><dt><span class="term">-L </span></dt><dd><p>List all the certificates, or display information about a named certificate, in a certificate database.
 Use the -h tokenname argument to specify the certificate database on a particular hardware or software token.</p></dd><dt><span class="term">-M </span></dt><dd><p>Modify a certificate's trust attributes using the values of the -t argument.</p></dd><dt><span class="term">-N</span></dt><dd><p>Create new certificate and key databases.</p></dd><dt><span class="term">-O </span></dt><dd><p>Print the certificate chain.</p></dd><dt><span class="term">-R</span></dt><dd><p>Create a certificate request file that can be submitted to a Certificate Authority (CA) for processing into a finished certificate. Output defaults to standard out unless you use -o output-file argument.
 
 Use the -a argument to specify ASCII output.</p></dd><dt><span class="term">-S </span></dt><dd><p>Create an individual certificate and add it to a certificate database.</p></dd><dt><span class="term">-T </span></dt><dd><p>Reset the key database or token.</p></dd><dt><span class="term">-U </span></dt><dd><p>List all available modules or print a single named module.</p></dd><dt><span class="term">-V </span></dt><dd><p>Check the validity of a certificate and its attributes.</p></dd><dt><span class="term">-W </span></dt><dd><p>Change the password to a key database.</p></dd><dt><span class="term">--merge</span></dt><dd><p>Merge two databases into one.</p></dd><dt><span class="term">--upgrade-merge</span></dt><dd><p>Upgrade an old database and merge it into a new database. This is used to migrate legacy NSS databases (<code class="filename">cert8.db</code> and <code class="filename">key3.db</code>) into the newer SQLite databases (<code class="filename">cert9.db</code> and <code class="filename">key4.db</code>).</p></dd></dl></div><p><span class="command"><strong>Arguments</strong></span></p><p>Arguments modify a command option and are usually lower case, numbers, or symbols.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">-a</span></dt><dd><p>Use ASCII format or allow the use of ASCII format for input or output. This formatting follows RFC 1113. 
 For certificate requests, ASCII output defaults to standard output unless redirected.</p></dd><dt><span class="term">-b validity-time</span></dt><dd><p>Specify a time at which a certificate is required to be valid. Use when checking certificate validity with the <code class="option">-V</code> option. The format of the <span class="emphasis"><em>validity-time</em></span> argument is <span class="emphasis"><em>YYMMDDHHMMSS[+HHMM|-HHMM|Z]</em></span>, which allows offsets to be set relative to the validity end time. Specifying seconds (<span class="emphasis"><em>SS</em></span>) is optional. When specifying an explicit time, use a Z at the end of the term, <span class="emphasis"><em>YYMMDDHHMMSSZ</em></span>, to close it. When specifying an offset time, use <span class="emphasis"><em>YYMMDDHHMMSS+HHMM</em></span> or <span class="emphasis"><em>YYMMDDHHMMSS-HHMM</em></span> for adding or subtracting time, respectively.
 </p><p>
 If this option is not used, the validity check defaults to the current system time.</p></dd><dt><span class="term">-c issuer</span></dt><dd><p>Identify the certificate of the CA from which a new certificate will derive its authenticity. 
  Use the exact nickname or alias of the CA certificate, or use the CA's email address. Bracket the issuer string 
  with quotation marks if it contains spaces. </p></dd><dt><span class="term">-d [prefix]directory</span></dt><dd><p>Specify the database directory containing the certificate and key database files.</p><p><span class="command"><strong>certutil</strong></span> supports two types of databases: the legacy security databases (<code class="filename">cert8.db</code>, <code class="filename">key3.db</code>, and <code class="filename">secmod.db</code>) and new SQLite databases (<code class="filename">cert9.db</code>, <code class="filename">key4.db</code>, and <code class="filename">pkcs11.txt</code>). </p><p>NSS recognizes the following prefixes:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p><span class="command"><strong>sql:</strong></span> requests the newer database</p></li><li class="listitem"><p><span class="command"><strong>dbm:</strong></span> requests the legacy database</p></li></ul></div><p>If no prefix is specified the default type is retrieved from NSS_DEFAULT_DB_TYPE. If NSS_DEFAULT_DB_TYPE is not set then <span class="command"><strong>dbm:</strong></span> is the default.</p></dd><dt><span class="term">--dump-ext-val OID </span></dt><dd><p>For single cert, print binary DER encoding of extension OID.</p></dd><dt><span class="term">-e </span></dt><dd><p>Check a certificate's signature during the process of validating a certificate.</p></dd><dt><span class="term">--email email-address</span></dt><dd><p>Specify the email address of a certificate to list. Used with the -L command option.</p></dd><dt><span class="term">--extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]... </span></dt><dd><p>
--- a/security/nss/doc/nroff/certutil.1
+++ b/security/nss/doc/nroff/certutil.1
@@ -1,18 +1,18 @@
 '\" t
 .\"     Title: CERTUTIL
 .\"    Author: [see the "Authors" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 27 October 2017
+.\"      Date:  5 October 2017
 .\"    Manual: NSS Security Tools
 .\"    Source: nss-tools
 .\"  Language: English
 .\"
-.TH "CERTUTIL" "1" "27 October 2017" "nss-tools" "NSS Security Tools"
+.TH "CERTUTIL" "1" "5 October 2017" "nss-tools" "NSS Security Tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
 .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 .\" http://bugs.debian.org/507673
 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
 .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 .ie \n(.g .ds Aq \(aq
@@ -87,25 +87,21 @@ Change the database nickname of a certif
 .PP
 \-E
 .RS 4
 Add an email certificate to the certificate database\&.
 .RE
 .PP
 \-F
 .RS 4
-Delete a private key from a key database\&. Specify the key to delete with the \-n argument\&. Specify the database from which to delete the key with the
+Delete a private key and the associated certificate from a database\&. Specify the key to delete with the \-n argument or the \-k argument\&. Specify the database from which to delete the key with the
 \fB\-d\fR
-argument\&. Use the
-\fB\-k\fR
-argument to specify explicitly whether to delete a DSA, RSA, or ECC key\&. If you don\*(Aqt use the
-\fB\-k\fR
-argument, the option looks for an RSA key matching the specified nickname\&.
+argument\&.
 .sp
-When you delete keys, be sure to also remove any certificates associated with those keys from the certificate database, by using \-D\&. Some smart cards do not let you remove a public key you have generated\&. In such a case, only the private key is deleted from the key pair\&. You can display the public key with the command certutil \-K \-h tokenname\&.
+Some smart cards do not let you remove a public key you have generated\&. In such a case, only the private key is deleted from the key pair\&.
 .RE
 .PP
 \-G
 .RS 4
 Generate a new public and private key pair within a key database\&. The key database should already exist; if one is not present, this command option will initialize one by default\&. Some smart cards can store only one key pair\&. If you create a new key pair for such a card, the previous pair is overwritten\&.
 .RE
 .PP
 \-H
--- a/security/nss/gtests/util_gtest/util_pkcs11uri_unittest.cc
+++ b/security/nss/gtests/util_gtest/util_pkcs11uri_unittest.cc
@@ -155,16 +155,17 @@ TEST_F(PK11URITest, ParseRetrieveTest) {
   TestParseRetrieve(
       "pkcs11:token=aaa;manufacturer=bbb;vendor=ccc?pin-source=|"
       "grep%20foo%20/etc/passwd&pin-value=secret&vendor=ddd",
       pattrs, PR_ARRAY_SIZE(pattrs), qattrs, PR_ARRAY_SIZE(qattrs));
 }
 
 TEST_F(PK11URITest, ParseFormatTest) {
   TestParseFormat("pkcs11:", "pkcs11:");
+  TestParseFormat("PKCS11:", "pkcs11:");
   TestParseFormat("pkcs11:token=aaa", "pkcs11:token=aaa");
   TestParseFormat("pkcs11:token=aaa;manufacturer=bbb",
                   "pkcs11:token=aaa;manufacturer=bbb");
   TestParseFormat("pkcs11:manufacturer=bbb;token=aaa",
                   "pkcs11:token=aaa;manufacturer=bbb");
   TestParseFormat("pkcs11:manufacturer=bbb;token=aaa;vendor2=ddd;vendor1=ccc",
                   "pkcs11:token=aaa;manufacturer=bbb;vendor1=ccc;vendor2=ddd");
   TestParseFormat("pkcs11:?pin-value=secret", "pkcs11:?pin-value=secret");
--- a/security/nss/lib/base/error.c
+++ b/security/nss/lib/base/error.c
@@ -10,16 +10,20 @@
  */
 
 #ifndef BASE_H
 #include "base.h"
 #endif              /* BASE_H */
 #include <limits.h> /* for UINT_MAX */
 #include <string.h> /* for memmove */
 
+#if defined(__MINGW32__)
+#include <windows.h>
+#endif
+
 #define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
 
 /*
  * The stack itself has a header, and a sequence of integers.
  * The header records the amount of space (as measured in stack
  * slots) already allocated for the stack, and the count of the
  * number of records currently being used.
  */
@@ -60,17 +64,42 @@ static const PRCallOnceType error_call_a
 /*
  * error_once_function
  *
  * This is the once-called callback.
  */
 static PRStatus
 error_once_function(void)
 {
+
+/*
+ * This #ifdef function is redundant. It performs the same thing as the
+ * else case.
+ *
+ * However, the MinGW version looks up the function from nss3's export
+ * table, and on MinGW _that_ behaves differently than passing a
+ * function pointer in a different module because MinGW has
+ * -mnop-fun-dllimport specified, which generates function thunks for
+ * cross-module calls. And when a module (like nssckbi) gets unloaded,
+ * and you try to call into that thunk (which is now missing) you'll
+ * crash. So we do this bit of ugly to avoid that crash. Fortunately
+ * this is the only place we've had to do this.
+ */
+#if defined(__MINGW32__)
+    HMODULE nss3 = GetModuleHandleW(L"nss3");
+    if (nss3) {
+        FARPROC freePtr = GetProcAddress(nss3, "PR_Free");
+        if (freePtr) {
+            return PR_NewThreadPrivateIndex(&error_stack_index, freePtr);
+        }
+    }
     return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
+#else
+    return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
+#endif
 }
 
 /*
  * error_get_my_stack
  *
  * This routine returns the calling thread's error stack, creating
  * it if necessary.  It may return NULL upon error, which implicitly
  * means that it ran out of memory.
--- a/security/nss/lib/freebl/mpi/mpi_arm.c
+++ b/security/nss/lib/freebl/mpi/mpi_arm.c
@@ -34,17 +34,17 @@ s_mpv_mul_d(const mp_digit *a, mp_size a
         "mov     r5, r4\n"
 
         "subs    %1, #1\n"
         "bne     1b\n"
 
         "2:\n"
         "str     r5, [%3]\n"
         :
-        : "r"(a), "r"(a_len), "r"(b), "r"(c)
+        : "r"(a), "l"(a_len), "r"(b), "r"(c)
         : "memory", "cc", "%r4", "%r5", "%r6");
 }
 
 void
 s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
 {
     __asm__ __volatile__(
         "mov     r5, #0\n"
@@ -67,17 +67,17 @@ s_mpv_mul_d_add(const mp_digit *a, mp_si
         "mov     r5, r4\n"
 
         "subs    %1, #1\n"
         "bne     1b\n"
 
         "2:\n"
         "str     r5, [%3]\n"
         :
-        : "r"(a), "r"(a_len), "r"(b), "r"(c)
+        : "r"(a), "l"(a_len), "r"(b), "r"(c)
         : "memory", "cc", "%r4", "%r5", "%r6");
 }
 
 void
 s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
 {
     if (!a_len)
         return;
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -1128,8 +1128,14 @@ CERT_FindCertByNicknameOrEmailAddrForUsa
 PK11_CreateManagedGenericObject;
 SGN_NewContextWithAlgorithmID;
 SEC_SignDataWithAlgorithmID;
 SEC_DerSignDataWithAlgorithmID;
 SEC_CreateSignatureAlgorithmParameters;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.39 { 	# NSS 3.39 release
+;+    global:
+CERT_GetCertKeyType;
+;+    local:
+;+       *;
+;+};
--- a/security/nss/lib/nss/nssinit.c
+++ b/security/nss/lib/nss/nssinit.c
@@ -49,17 +49,17 @@ char *
 nss_mktemp(char *path)
 {
     return _mktemp(path);
 }
 #endif
 
 #define NSS_MAX_FLAG_SIZE sizeof("readOnly") + sizeof("noCertDB") +                                  \
                               sizeof("noModDB") + sizeof("forceOpen") + sizeof("passwordRequired") + \
-                              sizeof("optimizeSpace")
+                              sizeof("optimizeSpace") + sizeof("printPolicyFeedback")
 #define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
 
 static char *
 nss_makeFlags(PRBool readOnly, PRBool noCertDB,
               PRBool noModDB, PRBool forceOpen,
               PRBool passwordRequired, PRBool optimizeSpace)
 {
     char *flags = (char *)PORT_Alloc(NSS_MAX_FLAG_SIZE);
--- a/security/nss/lib/pk11wrap/pk11akey.c
+++ b/security/nss/lib/pk11wrap/pk11akey.c
@@ -799,40 +799,22 @@ PK11_MakePrivKey(PK11SlotInfo *slot, Key
     PLArenaPool *arena;
     SECKEYPrivateKey *privKey;
     PRBool isPrivate;
     SECStatus rv;
 
     /* don't know? look it up */
     if (keyType == nullKey) {
         CK_KEY_TYPE pk11Type = CKK_RSA;
-        SECItem info;
 
         pk11Type = PK11_ReadULongAttribute(slot, privID, CKA_KEY_TYPE);
         isTemp = (PRBool)!PK11_HasAttributeSet(slot, privID, CKA_TOKEN, PR_FALSE);
         switch (pk11Type) {
             case CKK_RSA:
                 keyType = rsaKey;
-                /* determine RSA key type from the CKA_PUBLIC_KEY_INFO if present */
-                rv = PK11_ReadAttribute(slot, privID, CKA_PUBLIC_KEY_INFO, NULL, &info);
-                if (rv == SECSuccess) {
-                    CERTSubjectPublicKeyInfo *spki;
-
-                    spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&info);
-                    if (spki) {
-                        SECOidTag tag;
-
-                        tag = SECOID_GetAlgorithmTag(&spki->algorithm);
-                        if (tag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE)
-                            keyType = rsaPssKey;
-                        SECKEY_DestroySubjectPublicKeyInfo(spki);
-                    }
-                    SECITEM_FreeItem(&info, PR_FALSE);
-                }
-
                 break;
             case CKK_DSA:
                 keyType = dsaKey;
                 break;
             case CKK_DH:
                 keyType = dhKey;
                 break;
             case CKK_KEA:
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -736,17 +736,17 @@ find_certs_from_nickname(const char *nic
     NSSToken *token = NULL;
     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
     PK11SlotInfo *slot = NULL;
     SECStatus rv;
     char *nickCopy;
     char *delimit = NULL;
     char *tokenName;
 
-    if (!strncmp(nickname, "pkcs11:", strlen("pkcs11:"))) {
+    if (!PORT_Strncasecmp(nickname, "pkcs11:", strlen("pkcs11:"))) {
         certs = find_certs_from_uri(nickname, wincx);
         if (certs)
             return certs;
     }
     nickCopy = PORT_Strdup(nickname);
     if (!nickCopy) {
         /* error code is set */
         return NULL;
--- a/security/nss/lib/pk11wrap/pk11pars.c
+++ b/security/nss/lib/pk11wrap/pk11pars.c
@@ -189,17 +189,17 @@ typedef struct {
     unsigned name_size;
     PRUint32 flag;
 } policyFlagDef;
 
 /*
  *  This table should be merged with the SECOID table.
  */
 #define CIPHER_NAME(x) x, (sizeof(x) - 1)
-static const oidValDef algOptList[] = {
+static const oidValDef curveOptList[] = {
     /* Curves */
     { CIPHER_NAME("PRIME192V1"), SEC_OID_ANSIX962_EC_PRIME192V1,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("PRIME192V2"), SEC_OID_ANSIX962_EC_PRIME192V2,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("PRIME192V3"), SEC_OID_ANSIX962_EC_PRIME192V3,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("PRIME239V1"), SEC_OID_ANSIX962_EC_PRIME239V1,
@@ -311,17 +311,19 @@ static const oidValDef algOptList[] = {
     { CIPHER_NAME("SECT409K1"), SEC_OID_SECG_EC_SECT409K1,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SECT409R1"), SEC_OID_SECG_EC_SECT409R1,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SECT571K1"), SEC_OID_SECG_EC_SECT571K1,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SECT571R1"), SEC_OID_SECG_EC_SECT571R1,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
+};
 
+static const oidValDef hashOptList[] = {
     /* Hashes */
     { CIPHER_NAME("MD2"), SEC_OID_MD2,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("MD4"), SEC_OID_MD4,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("MD5"), SEC_OID_MD5,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SHA1"), SEC_OID_SHA1,
@@ -329,25 +331,29 @@ static const oidValDef algOptList[] = {
     { CIPHER_NAME("SHA224"), SEC_OID_SHA224,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SHA256"), SEC_OID_SHA256,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SHA384"), SEC_OID_SHA384,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
     { CIPHER_NAME("SHA512"), SEC_OID_SHA512,
       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
+};
 
+static const oidValDef macOptList[] = {
     /* MACs */
     { CIPHER_NAME("HMAC-SHA1"), SEC_OID_HMAC_SHA1, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("HMAC-SHA224"), SEC_OID_HMAC_SHA224, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("HMAC-SHA256"), SEC_OID_HMAC_SHA256, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("HMAC-SHA384"), SEC_OID_HMAC_SHA384, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("HMAC-SHA512"), SEC_OID_HMAC_SHA512, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("HMAC-MD5"), SEC_OID_HMAC_MD5, NSS_USE_ALG_IN_SSL },
+};
 
+static const oidValDef cipherOptList[] = {
     /* Ciphers */
     { CIPHER_NAME("AES128-CBC"), SEC_OID_AES_128_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("AES192-CBC"), SEC_OID_AES_192_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("AES256-CBC"), SEC_OID_AES_256_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("AES128-GCM"), SEC_OID_AES_128_GCM, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("AES192-GCM"), SEC_OID_AES_192_GCM, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("AES256-GCM"), SEC_OID_AES_256_GCM, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("CAMELLIA128-CBC"), SEC_OID_CAMELLIA_128_CBC, NSS_USE_ALG_IN_SSL },
@@ -357,30 +363,46 @@ static const oidValDef algOptList[] = {
     { CIPHER_NAME("SEED-CBC"), SEC_OID_SEED_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("DES-EDE3-CBC"), SEC_OID_DES_EDE3_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("DES-40-CBC"), SEC_OID_DES_40_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("DES-CBC"), SEC_OID_DES_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("NULL-CIPHER"), SEC_OID_NULL_CIPHER, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("RC2"), SEC_OID_RC2_CBC, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("RC4"), SEC_OID_RC4, NSS_USE_ALG_IN_SSL },
     { CIPHER_NAME("IDEA"), SEC_OID_IDEA_CBC, NSS_USE_ALG_IN_SSL },
+};
 
+static const oidValDef kxOptList[] = {
     /* Key exchange */
     { CIPHER_NAME("RSA"), SEC_OID_TLS_RSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("RSA-EXPORT"), SEC_OID_TLS_RSA_EXPORT, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("DHE-RSA"), SEC_OID_TLS_DHE_RSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("DHE-DSS"), SEC_OID_TLS_DHE_DSS, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("DH-RSA"), SEC_OID_TLS_DH_RSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("DH-DSS"), SEC_OID_TLS_DH_DSS, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDHE-ECDSA"), SEC_OID_TLS_ECDHE_ECDSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDHE-RSA"), SEC_OID_TLS_ECDHE_RSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDH-ECDSA"), SEC_OID_TLS_ECDH_ECDSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDH-RSA"), SEC_OID_TLS_ECDH_RSA, NSS_USE_ALG_IN_SSL_KX },
 };
 
+typedef struct {
+    const oidValDef *list;
+    PRUint32 entries;
+    const char *description;
+} algListsDef;
+
+static const algListsDef algOptLists[] = {
+    { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC" },
+    { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH" },
+    { macOptList, PR_ARRAY_SIZE(macOptList), "MAC" },
+    { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER" },
+    { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX" },
+};
+
 static const optionFreeDef sslOptList[] = {
     /* Versions */
     { CIPHER_NAME("SSL2.0"), 0x002 },
     { CIPHER_NAME("SSL3.0"), 0x300 },
     { CIPHER_NAME("SSL3.1"), 0x301 },
     { CIPHER_NAME("TLS1.0"), 0x301 },
     { CIPHER_NAME("TLS1.1"), 0x302 },
     { CIPHER_NAME("TLS1.2"), 0x303 },
@@ -442,71 +464,81 @@ secmod_ArgGetSubValue(const char *cipher
         }
     }
     *next = NULL;
     *len = cipher - start;
     return start;
 }
 
 static PRUint32
-secmod_parsePolicyValue(const char *policyFlags, int policyLength)
+secmod_parsePolicyValue(const char *policyFlags, int policyLength,
+                        PRBool printPolicyFeedback)
 {
     const char *flag, *currentString;
     PRUint32 flags = 0;
     int i;
 
     for (currentString = policyFlags; currentString &&
                                       currentString < policyFlags + policyLength;) {
         int length;
+        PRBool unknown = PR_TRUE;
         flag = secmod_ArgGetSubValue(currentString, ',', ':', &length,
                                      &currentString);
         if (length == 0) {
             continue;
         }
         for (i = 0; i < PR_ARRAY_SIZE(policyFlagList); i++) {
             const policyFlagDef *policy = &policyFlagList[i];
             unsigned name_size = policy->name_size;
             if ((policy->name_size == length) &&
                 PORT_Strncasecmp(policy->name, flag, name_size) == 0) {
                 flags |= policy->flag;
+                unknown = PR_FALSE;
                 break;
             }
         }
+        if (unknown && printPolicyFeedback) {
+            PR_SetEnv("NSS_POLICY_FAIL=1");
+            fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
+                    policyLength, policyFlags, length, flag);
+        }
     }
     return flags;
 }
 
 /* allow symbolic names for values. The only ones currently defines or
  * SSL protocol versions. */
-static PRInt32
-secmod_getPolicyOptValue(const char *policyValue, int policyValueLength)
+static SECStatus
+secmod_getPolicyOptValue(const char *policyValue, int policyValueLength,
+                         PRInt32 *result)
 {
     PRInt32 val = atoi(policyValue);
     int i;
 
     if ((val != 0) || (*policyValue == '0')) {
-        return val;
+        *result = val;
+        return SECSuccess;
     }
     for (i = 0; i < PR_ARRAY_SIZE(sslOptList); i++) {
         if (policyValueLength == sslOptList[i].name_size &&
             PORT_Strncasecmp(sslOptList[i].name, policyValue,
                              sslOptList[i].name_size) == 0) {
-            val = sslOptList[i].option;
-            break;
+            *result = sslOptList[i].option;
+            return SECSuccess;
         }
     }
-    return val;
+    return SECFailure;
 }
 
 static SECStatus
-secmod_applyCryptoPolicy(const char *policyString,
-                         PRBool allow)
+secmod_applyCryptoPolicy(const char *policyString, PRBool allow,
+                         PRBool printPolicyFeedback)
 {
     const char *cipher, *currentString;
-    unsigned i;
+    unsigned i, j;
     SECStatus rv = SECSuccess;
     PRBool unknown;
 
     if (policyString == NULL || policyString[0] == 0) {
         return SECSuccess; /* do nothing */
     }
 
     /* if we change any of these, make sure it gets applied in ssl as well */
@@ -521,144 +553,247 @@ secmod_applyCryptoPolicy(const char *pol
         unknown = PR_TRUE;
         if (length >= 3 && cipher[3] == '/') {
             newValue = PR_TRUE;
         }
         if ((newValue || (length == 3)) && PORT_Strncasecmp(cipher, "all", 3) == 0) {
             /* disable or enable all options by default */
             PRUint32 value = 0;
             if (newValue) {
-                value = secmod_parsePolicyValue(&cipher[3] + 1, length - 3 - 1);
+                value = secmod_parsePolicyValue(&cipher[3] + 1, length - 3 - 1, printPolicyFeedback);
             }
-            for (i = 0; i < PR_ARRAY_SIZE(algOptList); i++) {
-                PRUint32 enable, disable;
-                if (!newValue) {
-                    value = algOptList[i].val;
+            for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+                const algListsDef *algOptList = &algOptLists[i];
+                for (j = 0; j < algOptList->entries; j++) {
+                    PRUint32 enable, disable;
+                    if (!newValue) {
+                        value = algOptList->list[j].val;
+                    }
+                    if (allow) {
+                        enable = value;
+                        disable = 0;
+                    } else {
+                        enable = 0;
+                        disable = value;
+                    }
+                    NSS_SetAlgorithmPolicy(algOptList->list[j].oid, enable, disable);
                 }
-                if (allow) {
-                    enable = value;
-                    disable = 0;
-                } else {
-                    enable = 0;
-                    disable = value;
-                }
-                NSS_SetAlgorithmPolicy(algOptList[i].oid, enable, disable);
             }
             continue;
         }
 
-        for (i = 0; i < PR_ARRAY_SIZE(algOptList); i++) {
-            const oidValDef *algOpt = &algOptList[i];
-            unsigned name_size = algOpt->name_size;
-            PRBool newOption = PR_FALSE;
+        for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+            const algListsDef *algOptList = &algOptLists[i];
+            for (j = 0; j < algOptList->entries; j++) {
+                const oidValDef *algOpt = &algOptList->list[j];
+                unsigned name_size = algOpt->name_size;
+                PRBool newOption = PR_FALSE;
 
-            if ((length >= name_size) && (cipher[name_size] == '/')) {
-                newOption = PR_TRUE;
-            }
-            if ((newOption || algOpt->name_size == length) &&
-                PORT_Strncasecmp(algOpt->name, cipher, name_size) == 0) {
-                PRUint32 value = algOpt->val;
-                PRUint32 enable, disable;
-                if (newOption) {
-                    value = secmod_parsePolicyValue(&cipher[name_size] + 1,
-                                                    length - name_size - 1);
+                if ((length >= name_size) && (cipher[name_size] == '/')) {
+                    newOption = PR_TRUE;
                 }
-                if (allow) {
-                    enable = value;
-                    disable = 0;
-                } else {
-                    enable = 0;
-                    disable = value;
+                if ((newOption || algOpt->name_size == length) &&
+                    PORT_Strncasecmp(algOpt->name, cipher, name_size) == 0) {
+                    PRUint32 value = algOpt->val;
+                    PRUint32 enable, disable;
+                    if (newOption) {
+                        value = secmod_parsePolicyValue(&cipher[name_size] + 1,
+                                                        length - name_size - 1,
+                                                        printPolicyFeedback);
+                    }
+                    if (allow) {
+                        enable = value;
+                        disable = 0;
+                    } else {
+                        enable = 0;
+                        disable = value;
+                    }
+                    rv = NSS_SetAlgorithmPolicy(algOpt->oid, enable, disable);
+                    if (rv != SECSuccess) {
+                        /* could not enable option */
+                        /* NSS_SetAlgorithPolicy should have set the error code */
+                        return SECFailure;
+                    }
+                    unknown = PR_FALSE;
+                    break;
                 }
-                rv = NSS_SetAlgorithmPolicy(algOpt->oid, enable, disable);
-                if (rv != SECSuccess) {
-                    /* could not enable option */
-                    /* NSS_SetAlgorithPolicy should have set the error code */
-                    return SECFailure;
-                }
-                unknown = PR_FALSE;
-                break;
             }
         }
         if (!unknown) {
             continue;
         }
 
         for (i = 0; i < PR_ARRAY_SIZE(freeOptList); i++) {
             const optionFreeDef *freeOpt = &freeOptList[i];
             unsigned name_size = freeOpt->name_size;
 
             if ((length > name_size) && cipher[name_size] == '=' &&
                 PORT_Strncasecmp(freeOpt->name, cipher, name_size) == 0) {
-                PRInt32 val = secmod_getPolicyOptValue(&cipher[name_size + 1],
-                                                       length - name_size - 1);
-
+                PRInt32 val;
+                const char *policyValue = &cipher[name_size + 1];
+                int policyValueLength = length - name_size - 1;
+                rv = secmod_getPolicyOptValue(policyValue, policyValueLength,
+                                              &val);
+                if (rv != SECSuccess) {
+                    if (printPolicyFeedback) {
+                        PR_SetEnv("NSS_POLICY_FAIL=1");
+                        fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
+                                length, cipher, policyValueLength, policyValue);
+                    }
+                    return SECFailure;
+                }
                 rv = NSS_OptionSet(freeOpt->option, val);
                 if (rv != SECSuccess) {
                     /* could not enable option */
                     /* NSS_OptionSet should have set the error code */
                     return SECFailure;
                 }
                 /* to allow the policy to expand in the future. ignore ciphers
                  * we don't understand */
                 unknown = PR_FALSE;
                 break;
             }
         }
+
+        if (unknown && printPolicyFeedback) {
+            PR_SetEnv("NSS_POLICY_FAIL=1");
+            fprintf(stderr, "NSS-POLICY-FAIL %s: unknown identifier: %.*s\n",
+                    allow ? "allow" : "disallow", length, cipher);
+        }
     }
     return rv;
 }
 
+static void
+secmod_sanityCheckCryptoPolicy(void)
+{
+    unsigned i, j;
+    SECStatus rv = SECSuccess;
+    unsigned num_kx_enabled = 0;
+    unsigned num_ssl_enabled = 0;
+    unsigned num_sig_enabled = 0;
+    unsigned enabledCount[PR_ARRAY_SIZE(algOptLists)];
+    const char *sWarn = "WARN";
+    const char *sInfo = "INFO";
+    PRBool haveWarning = PR_FALSE;
+
+    for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+        const algListsDef *algOptList = &algOptLists[i];
+        enabledCount[i] = 0;
+        for (j = 0; j < algOptList->entries; j++) {
+            const oidValDef *algOpt = &algOptList->list[j];
+            PRUint32 value;
+            PRBool anyEnabled = PR_FALSE;
+            rv = NSS_GetAlgorithmPolicy(algOpt->oid, &value);
+            if (rv != SECSuccess) {
+                PR_SetEnv("NSS_POLICY_FAIL=1");
+                fprintf(stderr, "NSS-POLICY-FAIL: internal failure with NSS_GetAlgorithmPolicy at %u\n", i);
+                return;
+            }
+
+            if ((algOpt->val & NSS_USE_ALG_IN_SSL_KX) && (value & NSS_USE_ALG_IN_SSL_KX)) {
+                ++num_kx_enabled;
+                anyEnabled = PR_TRUE;
+                fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for KX\n", algOpt->name);
+            }
+            if ((algOpt->val & NSS_USE_ALG_IN_SSL) && (value & NSS_USE_ALG_IN_SSL)) {
+                ++num_ssl_enabled;
+                anyEnabled = PR_TRUE;
+                fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for SSL\n", algOpt->name);
+            }
+            if ((algOpt->val & NSS_USE_ALG_IN_CERT_SIGNATURE) && (value & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
+                ++num_sig_enabled;
+                anyEnabled = PR_TRUE;
+                fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for CERT-SIGNATURE\n", algOpt->name);
+            }
+            if (anyEnabled) {
+                ++enabledCount[i];
+            }
+        }
+    }
+    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG-KX: %u\n", num_kx_enabled ? sInfo : sWarn, num_kx_enabled);
+    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG: %u\n", num_ssl_enabled ? sInfo : sWarn, num_ssl_enabled);
+    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CERT-SIG: %u\n", num_sig_enabled ? sInfo : sWarn, num_sig_enabled);
+    if (!num_kx_enabled || !num_ssl_enabled || !num_sig_enabled) {
+        haveWarning = PR_TRUE;
+    }
+    for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+        const algListsDef *algOptList = &algOptLists[i];
+        fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s: %u\n", enabledCount[i] ? sInfo : sWarn, algOptList->description, enabledCount[i]);
+        if (!enabledCount[i]) {
+            haveWarning = PR_TRUE;
+        }
+    }
+    if (haveWarning) {
+        PR_SetEnv("NSS_POLICY_WARN=1");
+    }
+}
+
 static SECStatus
-secmod_parseCryptoPolicy(const char *policyConfig)
+secmod_parseCryptoPolicy(const char *policyConfig, PRBool printPolicyFeedback)
 {
     char *disallow, *allow;
     SECStatus rv;
 
     if (policyConfig == NULL) {
         return SECSuccess; /* no policy given */
     }
     /* make sure we initialize the oid table and set all the default policy
      * values first so we can override them here */
     rv = SECOID_Init();
     if (rv != SECSuccess) {
         return rv;
     }
     disallow = NSSUTIL_ArgGetParamValue("disallow", policyConfig);
-    rv = secmod_applyCryptoPolicy(disallow, PR_FALSE);
+    rv = secmod_applyCryptoPolicy(disallow, PR_FALSE, printPolicyFeedback);
     if (disallow)
         PORT_Free(disallow);
     if (rv != SECSuccess) {
         return rv;
     }
     allow = NSSUTIL_ArgGetParamValue("allow", policyConfig);
-    rv = secmod_applyCryptoPolicy(allow, PR_TRUE);
+    rv = secmod_applyCryptoPolicy(allow, PR_TRUE, printPolicyFeedback);
     if (allow)
         PORT_Free(allow);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+    if (printPolicyFeedback) {
+        /* This helps to distinguish configurations that don't contain any
+         * policy config= statement. */
+        PR_SetEnv("NSS_POLICY_LOADED=1");
+        fprintf(stderr, "NSS-POLICY-INFO: LOADED-SUCCESSFULLY\n");
+        secmod_sanityCheckCryptoPolicy();
+    }
     return rv;
 }
 
 /*
  * for 3.4 we continue to use the old SECMODModule structure
  */
 SECMODModule *
 SECMOD_CreateModuleEx(const char *library, const char *moduleName,
                       const char *parameters, const char *nss,
                       const char *config)
 {
     SECMODModule *mod;
     SECStatus rv;
     char *slotParams, *ciphers;
     /* pk11pars.h still does not have const char * interfaces */
     char *nssc = (char *)nss;
+    PRBool printPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nssc);
 
-    rv = secmod_parseCryptoPolicy(config);
+    rv = secmod_parseCryptoPolicy(config, printPolicyFeedback);
 
     /* do not load the module if policy parsing fails */
     if (rv != SECSuccess) {
+        if (printPolicyFeedback) {
+            PR_SetEnv("NSS_POLICY_FAIL=1");
+            fprintf(stderr, "NSS-POLICY-FAIL: policy config parsing failed, not loading module %s\n", moduleName);
+        }
         return NULL;
     }
 
     mod = secmod_NewModule();
     if (mod == NULL)
         return NULL;
 
     mod->commonName = PORT_ArenaStrdup(mod->arena, moduleName ? moduleName : "");
@@ -1642,28 +1777,30 @@ SECMODModule *
 SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
 {
     char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss = NULL;
     char *config = NULL;
     SECStatus status;
     SECMODModule *module = NULL;
     SECMODModule *oldModule = NULL;
     SECStatus rv;
+    PRBool forwardPolicyFeedback = PR_FALSE;
 
     /* initialize the underlying module structures */
     SECMOD_Init();
 
     status = NSSUTIL_ArgParseModuleSpecEx(modulespec, &library, &moduleName,
                                           &parameters, &nss,
                                           &config);
     if (status != SECSuccess) {
         goto loser;
     }
 
     module = SECMOD_CreateModuleEx(library, moduleName, parameters, nss, config);
+    forwardPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nss);
     if (library)
         PORT_Free(library);
     if (moduleName)
         PORT_Free(moduleName);
     if (parameters)
         PORT_Free(parameters);
     if (nss)
         PORT_Free(nss);
@@ -1716,17 +1853,25 @@ SECMOD_LoadModule(char *modulespec, SECM
             for (; *index; index++) {
                 SECMODModule *child;
                 if (0 == PORT_Strcmp(*index, modulespec)) {
                     /* avoid trivial infinite recursion */
                     PORT_SetError(SEC_ERROR_NO_MODULE);
                     rv = SECFailure;
                     break;
                 }
-                child = SECMOD_LoadModule(*index, module, PR_TRUE);
+                if (!forwardPolicyFeedback) {
+                    child = SECMOD_LoadModule(*index, module, PR_TRUE);
+                } else {
+                    /* Add printPolicyFeedback to the nss flags */
+                    char *specWithForwards =
+                        NSSUTIL_AddNSSFlagToModuleSpec(*index, "printPolicyFeedback");
+                    child = SECMOD_LoadModule(specWithForwards, module, PR_TRUE);
+                    PORT_Free(specWithForwards);
+                }
                 if (!child)
                     break;
                 if (child->isCritical && !child->loaded) {
                     int err = PORT_GetError();
                     if (!err)
                         err = SEC_ERROR_NO_MODULE;
                     SECMOD_DestroyModule(child);
                     PORT_SetError(err);
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -602,41 +602,57 @@ PK11_FindSlotsByNames(const char *dllNam
 
     if (SECFailure == rv) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     }
 
     return slotList;
 }
 
-PK11SlotInfo *
-PK11_FindSlotByName(const char *name)
+typedef PRBool (*PK11SlotMatchFunc)(PK11SlotInfo *slot, const void *arg);
+
+static PRBool
+pk11_MatchSlotByTokenName(PK11SlotInfo *slot, const void *arg)
+{
+    return PORT_Strcmp(slot->token_name, arg) == 0;
+}
+
+static PRBool
+pk11_MatchSlotBySerial(PK11SlotInfo *slot, const void *arg)
 {
+    return PORT_Memcmp(slot->serial, arg, sizeof(slot->serial)) == 0;
+}
+
+static PRBool
+pk11_MatchSlotByTokenURI(PK11SlotInfo *slot, const void *arg)
+{
+    return pk11_MatchUriTokenInfo(slot, (PK11URI *)arg);
+}
+
+static PK11SlotInfo *
+pk11_FindSlot(const void *arg, PK11SlotMatchFunc func)
+{
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
     SECMODModuleList *mlp;
     SECMODModuleList *modules;
-    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
     int i;
     PK11SlotInfo *slot = NULL;
 
     if (!moduleLock) {
         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
         return slot;
     }
-    if ((name == NULL) || (*name == 0)) {
-        return PK11_GetInternalKeySlot();
-    }
-
     /* work through all the slots */
     SECMOD_GetReadLock(moduleLock);
     modules = SECMOD_GetDefaultModuleList();
     for (mlp = modules; mlp != NULL; mlp = mlp->next) {
         for (i = 0; i < mlp->module->slotCount; i++) {
             PK11SlotInfo *tmpSlot = mlp->module->slots[i];
             if (PK11_IsPresent(tmpSlot)) {
-                if (PORT_Strcmp(tmpSlot->token_name, name) == 0) {
+                if (func(tmpSlot, arg)) {
                     slot = PK11_ReferenceSlot(tmpSlot);
                     break;
                 }
             }
         }
         if (slot != NULL)
             break;
     }
@@ -644,53 +660,51 @@ PK11_FindSlotByName(const char *name)
 
     if (slot == NULL) {
         PORT_SetError(SEC_ERROR_NO_TOKEN);
     }
 
     return slot;
 }
 
+static PK11SlotInfo *
+pk11_FindSlotByTokenURI(const char *uriString)
+{
+    PK11SlotInfo *slot = NULL;
+    PK11URI *uri;
+
+    uri = PK11URI_ParseURI(uriString);
+    if (!uri) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return slot;
+    }
+
+    slot = pk11_FindSlot(uri, pk11_MatchSlotByTokenURI);
+    PK11URI_DestroyURI(uri);
+    return slot;
+}
+
+PK11SlotInfo *
+PK11_FindSlotByName(const char *name)
+{
+    if ((name == NULL) || (*name == 0)) {
+        return PK11_GetInternalKeySlot();
+    }
+
+    if (!PORT_Strncasecmp(name, "pkcs11:", strlen("pkcs11:"))) {
+        return pk11_FindSlotByTokenURI(name);
+    }
+
+    return pk11_FindSlot(name, pk11_MatchSlotByTokenName);
+}
+
 PK11SlotInfo *
 PK11_FindSlotBySerial(char *serial)
 {
-    SECMODModuleList *mlp;
-    SECMODModuleList *modules;
-    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
-    int i;
-    PK11SlotInfo *slot = NULL;
-
-    if (!moduleLock) {
-        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
-        return slot;
-    }
-    /* work through all the slots */
-    SECMOD_GetReadLock(moduleLock);
-    modules = SECMOD_GetDefaultModuleList();
-    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
-        for (i = 0; i < mlp->module->slotCount; i++) {
-            PK11SlotInfo *tmpSlot = mlp->module->slots[i];
-            if (PK11_IsPresent(tmpSlot)) {
-                if (PORT_Memcmp(tmpSlot->serial, serial,
-                                sizeof(tmpSlot->serial)) == 0) {
-                    slot = PK11_ReferenceSlot(tmpSlot);
-                    break;
-                }
-            }
-        }
-        if (slot != NULL)
-            break;
-    }
-    SECMOD_ReleaseReadLock(moduleLock);
-
-    if (slot == NULL) {
-        PORT_SetError(SEC_ERROR_NO_TOKEN);
-    }
-
-    return slot;
+    return pk11_FindSlot(serial, pk11_MatchSlotBySerial);
 }
 
 /*
  * notification stub. If we ever get interested in any events that
  * the pkcs11 functions may pass back to use, we can catch them here...
  * currently pdata is a slotinfo structure.
  */
 CK_RV
--- a/security/nss/lib/util/nssutil.def
+++ b/security/nss/lib/util/nssutil.def
@@ -323,8 +323,14 @@ NSS_SecureMemcmpZero;
 ;-    local:
 ;-       *;
 ;+NSSUTIL_3.38 {         # NSS Utilities 3.38 release
 ;+    global:
 SECITEM_MakeItem;
 ;+    local:
 ;+       *;
 ;+};
+;+NSSUTIL_3.39 {         # NSS Utilities 3.39 release
+;+    global:
+NSSUTIL_AddNSSFlagToModuleSpec;
+;+    local:
+;+       *;
+;+};
--- a/security/nss/lib/util/pkcs11uri.c
+++ b/security/nss/lib/util/pkcs11uri.c
@@ -669,17 +669,17 @@ pk11uri_ParseAttributes(const char **str
 
 PK11URI *
 PK11URI_ParseURI(const char *string)
 {
     PK11URI *result;
     const char *p = string;
     SECStatus ret;
 
-    if (strncmp("pkcs11:", p, 7) != 0) {
+    if (PORT_Strncasecmp("pkcs11:", p, 7) != 0) {
         return NULL;
     }
     p += 7;
 
     result = pk11uri_AllocURI();
     if (result == NULL) {
         return NULL;
     }
--- a/security/nss/lib/util/utilpars.c
+++ b/security/nss/lib/util/utilpars.c
@@ -908,16 +908,102 @@ NSSUTIL_MkModuleSpecEx(char *dllName, ch
  * make a new module spec from it's components */
 char *
 NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
                      char *NSS)
 {
     return NSSUTIL_MkModuleSpecEx(dllName, commonName, parameters, NSS, NULL);
 }
 
+/************************************************************************
+ * add a single flag to the Flags= section inside the spec's NSS= section */
+char *
+NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag)
+{
+    const char *prefix = "flags=";
+    const size_t prefixLen = strlen(prefix);
+    char *lib = NULL, *name = NULL, *param = NULL, *nss = NULL, *conf = NULL;
+    char *nss2 = NULL, *result = NULL;
+    SECStatus rv;
+
+    rv = NSSUTIL_ArgParseModuleSpecEx(spec, &lib, &name, &param, &nss, &conf);
+    if (rv != SECSuccess) {
+        return NULL;
+    }
+
+    if (nss && NSSUTIL_ArgHasFlag("flags", addFlag, nss)) {
+        /* It's already there, nothing to do! */
+        PORT_Free(lib);
+        PORT_Free(name);
+        PORT_Free(param);
+        PORT_Free(nss);
+        PORT_Free(conf);
+        return PORT_Strdup(spec);
+    }
+
+    if (!nss || !strlen(nss)) {
+        nss2 = PORT_Alloc(prefixLen + strlen(addFlag) + 1);
+        PORT_Strcpy(nss2, prefix);
+        PORT_Strcat(nss2, addFlag);
+    } else {
+        const char *iNss = nss;
+        PRBool alreadyAdded = PR_FALSE;
+        size_t maxSize = strlen(nss) + strlen(addFlag) + prefixLen + 2; /* space and null terminator */
+        nss2 = PORT_Alloc(maxSize);
+        *nss2 = 0;
+        while (*iNss) {
+            iNss = NSSUTIL_ArgStrip(iNss);
+            if (PORT_Strncasecmp(iNss, prefix, prefixLen) == 0) {
+                /* We found an existing Flags= section. */
+                char *oldFlags;
+                const char *valPtr;
+                int valSize;
+                valPtr = iNss + prefixLen;
+                oldFlags = NSSUTIL_ArgFetchValue(valPtr, &valSize);
+                iNss = valPtr + valSize;
+                PORT_Strcat(nss2, prefix);
+                PORT_Strcat(nss2, oldFlags);
+                PORT_Strcat(nss2, ",");
+                PORT_Strcat(nss2, addFlag);
+                PORT_Strcat(nss2, " ");
+                PORT_Free(oldFlags);
+                alreadyAdded = PR_TRUE;
+                iNss = NSSUTIL_ArgStrip(iNss);
+                PORT_Strcat(nss2, iNss); /* remainder of input */
+                break;
+            } else {
+                /* Append this other name=value pair and continue. */
+                const char *startOfNext = NSSUTIL_ArgSkipParameter(iNss);
+                PORT_Strncat(nss2, iNss, (startOfNext - iNss));
+                if (nss2[strlen(nss2) - 1] != ' ') {
+                    PORT_Strcat(nss2, " ");
+                }
+                iNss = startOfNext;
+            }
+            iNss = NSSUTIL_ArgStrip(iNss);
+        }
+        if (!alreadyAdded) {
+            /* nss wasn't empty, and it didn't contain a Flags section. We can
+             * assume that other content from nss has already been added to
+             * nss2, which means we already have a trailing space separator. */
+            PORT_Strcat(nss2, prefix);
+            PORT_Strcat(nss2, addFlag);
+        }
+    }
+
+    result = NSSUTIL_MkModuleSpecEx(lib, name, param, nss2, conf);
+    PORT_Free(lib);
+    PORT_Free(name);
+    PORT_Free(param);
+    PORT_Free(nss);
+    PORT_Free(nss2);
+    PORT_Free(conf);
+    return result;
+}
+
 #define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA"
 /******************************************************************************
  * Parse the cipher flags from the NSS parameter
  */
 void
 NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers, const char *cipherList)
 {
     newCiphers[0] = newCiphers[1] = 0;
--- a/security/nss/lib/util/utilpars.h
+++ b/security/nss/lib/util/utilpars.h
@@ -41,16 +41,17 @@ char *NSSUTIL_MkSlotString(unsigned long
 SECStatus NSSUTIL_ArgParseModuleSpec(const char *modulespec, char **lib,
                                      char **mod, char **parameters, char **nss);
 SECStatus NSSUTIL_ArgParseModuleSpecEx(const char *modulespec, char **lib,
                                        char **mod, char **parameters, char **nss, char **config);
 char *NSSUTIL_MkModuleSpec(char *dllName, char *commonName,
                            char *parameters, char *NSS);
 char *NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName,
                              char *parameters, char *NSS, char *config);
+char *NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag);
 void NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers,
                                  const char *cipherList);
 char *NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,
                           PRBool isFIPS, PRBool isModuleDB, PRBool isModuleDBOnly,
                           PRBool isCritical, unsigned long trustOrder,
                           unsigned long cipherOrder, unsigned long ssl0, unsigned long ssl1);
 
 /*
--- a/security/nss/mach
+++ b/security/nss/mach
@@ -242,17 +242,17 @@ def parse_arguments():
         help="Specify files or directories to run clang-format on",
         action=cfAction)
 
     parser_test = subparsers.add_parser(
         'tests', help='Run tests through tests/all.sh.')
     tests = [
         "cipher", "lowhash", "chains", "cert", "dbtests", "tools", "fips",
         "sdr", "crmf", "smime", "ssl", "ocsp", "merge", "pkits", "ec",
-        "gtests", "ssl_gtests", "bogo", "interop"
+        "gtests", "ssl_gtests", "bogo", "interop", "policy"
     ]
     parser_test.add_argument(
         'test', choices=tests, help="Available tests", action=testAction)
 
     parser_cov = subparsers.add_parser(
         'coverage', help='Generate coverage report')
     cov_modules = ["ssl_gtests"]
     parser_cov.add_argument(
--- a/security/nss/nss.gyp
+++ b/security/nss/nss.gyp
@@ -130,16 +130,17 @@
             'cmd/derdump/derdump.gyp:derdump',
             'cmd/digest/digest.gyp:digest',
             'cmd/ecperf/ecperf.gyp:ecperf',
             'cmd/fbectest/fbectest.gyp:fbectest',
             'cmd/httpserv/httpserv.gyp:httpserv',
             'cmd/listsuites/listsuites.gyp:listsuites',
             'cmd/makepqg/makepqg.gyp:makepqg',
             'cmd/multinit/multinit.gyp:multinit',
+            'cmd/nss-policy-check/nss-policy-check.gyp:nss-policy-check',
             'cmd/ocspclnt/ocspclnt.gyp:ocspclnt',
             'cmd/ocspresp/ocspresp.gyp:ocspresp',
             'cmd/oidcalc/oidcalc.gyp:oidcalc',
             'cmd/p7content/p7content.gyp:p7content',
             'cmd/p7env/p7env.gyp:p7env',
             'cmd/p7sign/p7sign.gyp:p7sign',
             'cmd/p7verify/p7verify.gyp:p7verify',
             'cmd/pk11ectest/pk11ectest.gyp:pk11ectest',
--- a/security/nss/readme.md
+++ b/security/nss/readme.md
@@ -92,17 +92,17 @@ Make sure that all environment variables
 the tests as well.  Test results are published in the folder
 `../../test_results/`.
 
 Individual tests can be run with the `NSS_TESTS` environment variable,
 e.g. `NSS_TESTS=ssl_gtests ./all.sh` or by changing into the according directory
 and running the bash script there `cd ssl_gtests && ./ssl_gtests.sh`.  The
 following tests are available:
 
-    cipher lowhash libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits chains ec gtests ssl_gtests bogo
+    cipher lowhash libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits chains ec gtests ssl_gtests bogo policy
 
 To make tests run faster it's recommended to set `NSS_CYCLES=standard` to run
 only the standard cycle.
 
 ## Releases
 
 NSS releases can be found at [Mozilla's download
 server](https://ftp.mozilla.org/pub/security/nss/releases/). Because NSS depends
--- a/security/nss/tests/all.sh
+++ b/security/nss/tests/all.sh
@@ -32,16 +32,17 @@
 #   merge.sh     - tests merging old and new shareable databases
 #   pkits.sh     - NIST/PKITS tests
 #   chains.sh    - PKIX cert chains tests
 #   dbupgrade.sh - upgrade databases to new shareable version (used
 #                  only in upgrade test cycle)
 #   memleak.sh   - memory leak testing (optional)
 #   ssl_gtests.sh- Gtest based unit tests for ssl
 #   gtests.sh    - Gtest based unit tests for everything else
+#   policy.sh    - Crypto Policy tests
 #   bogo.sh      - Bogo interop tests (disabled by default)
 #                  https://boringssl.googlesource.com/boringssl/+/master/ssl/test/PORTING.md
 #   interop.sh   - Interoperability tests (disabled by default)
 #                  https://github.com/ekr/tls_interop
 #
 # NSS testing is now devided to 4 cycles:
 # ---------------------------------------
 #   standard     - run test suites with defaults settings
@@ -295,17 +296,17 @@ fi
 cycles="standard pkix upgradedb sharedb"
 CYCLES=${NSS_CYCLES:-$cycles}
 
 NO_INIT_SUPPORT=`certutil --build-flags |grep -cw NSS_NO_INIT_SUPPORT`
 if [ $NO_INIT_SUPPORT -eq 0 ]; then
     RUN_FIPS="fips"
 fi
 
-tests="cipher lowhash libpkix cert dbtests tools $RUN_FIPS sdr crmf smime ssl ocsp merge pkits ec gtests ssl_gtests"
+tests="cipher lowhash libpkix cert dbtests tools $RUN_FIPS sdr crmf smime ssl ocsp merge pkits ec gtests ssl_gtests policy"
 # Don't run chains tests when we have a gyp build.
 if [ "$OBJDIR" != "Debug" -a "$OBJDIR" != "Release" ]; then
   tests="$tests chains"
 fi
 TESTS=${NSS_TESTS:-$tests}
 
 ALL_TESTS=${TESTS}
 
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f0e8d24d628769fcb94fce940d5822db2f9fd772
GIT binary patch
literal 2598
zc$`&~cQ_l08pabMM6D7#_Kp=Jii4`r)@qGdwT=<%n4yRjLaCM(Jq>Dv+FF}ZyJnr1
zqN3<Aj?tjDq-vC-&vWlR_x$mG@AJLy_x<}r;2A|}fV2oaWDN{~C*4dsWCqd$3-OQ{
z5FSFhh{q9l(CvRJa3LO~dl6~T009?<{J$pz49xhSg$W2ouz(og*s1n|^Ob5E8U{cd
z9>nmx>7Ct(tA2;Fb*gpyj$!Pyvq#A`6OTm&8Vu?B1!lrJcaND3g>kg7P$8wUmHTKC
z%rJ6USCh2Pu!(bHn_|ZyIwj?#8p~%3a0gnKZiQ|%gFx9COo;Ki|FGq8<K)9L#8EW&
zr>ref(}?Sdp{ZC;RuZ7@-5|VI0PsrBOS3p!x4nC%su_c&m-7#JX&#!jHgHGgyKa<-
zzV{)yDNN<0$%OgS{h(M&g6Dl1wdKsNq`Ya3rb{`1)t)fU28p4&m8bNN`B#>Mgt_#Z
z#r?kUbKBTxo($;n!aPMq&VIao|Kv(jj)1tZ&K!;=S-sW9kOh^|1UbxAPX)uNvV8Z-
zI-V1q)Y|)q)_V0#)4nUoUn677bV0kqgpJJZzXpBlb-wl|%lm0e%m?{d_YANlT9B7#
zT0ZJ0!qR0?;zJMRVqW%6iO?Fg@AGk=QdH`W$yX}kaz-uSC)y(^ErXL<n~-Q({LV08
z@s?54y(e0K);nq?5;Mk1XeCiu-b@Cpsqa0=<Gt7Bq9Z$dQiR;>b$QDhn|KU(Lfl~w
z^cY{{PK+&-wAU#=fE^Dh-AJzKyyN9RDAN(0zv$m-wob5!j_~&w_>jpmjtn$FD0Lp$
zuXX~hk`)<Lo+1bSLQ}TOMw0K-Q|YZ6d+oD~t3D08u`kgk@!k+BJZ{vOsKx5o1q_2N
zIBZRe$8pnn7$-lOT4e<&QZZXIY1}f;7IUAg74AHc?&G-jet+MeN_T)=evg&WAI!Z5
zTTlu7)oyw0CQIGQHZbgo80Kxd&S8+WZzhta<%nci5@_&6<M@?L^J+Nu!DNc+kw7K6
z$<~Eyi%-3aYB(=KO;0Ut`TApLz&SyZeko^?1K6#@A6%GA@%78prt*3sqOL?$Bt(7?
zcm6f%(YW9Gv_^W(DRptJAm`d2P^<byAC4xX!j}M*iHy0K^%=c+k6C@SQZ|<xA=cSp
zFN<3=JkQ$wSvBo<bF^M}TE7;onI&K)aKW?3{7SbvM~d}*%QM47;%!}9GR~`7_roEB
zW8s1c#2{hS0M0+7Gg?&;NGLBgImI$p`dLOq)oQ6-&4{PnB<c7=(RI<j_k9~%Pw=CO
zzk~{*M0c9!qn@&jV;W4H7Z?~6zhPde^%m6z%VjlEjO6QOPlFkOBD8$1{@Ggqjs%ry
zcyDgD{K?>;;zRBkSNt1ctB#m=uj(&F-h;UP1{x83f;uN_Z;A43J6LiL${+(79kM?1
z_D~~N6?-->^R6FZJkuz?-rILa2fXfg>5hF)lJxUKHbyAcw?JR7r+oZnN|q|4`S`0&
zVGlko=IrB9?WGy7VfFS$4JH*I`Ykq@xY)+LA8wcny`vSFk9ZBSP11O&Z@uq<z|%$k
zi#Bw>f$(%*7qR<=T)>z9ixEa3%>{41T!3cjUv#1UNf%qZlAu@f65mg{fbgK6BD0(P
zNCu)X_dBD$w=m|>#W!-+5weq&8T)_OE%Ra>D9(nhTw+5~venmtGdX;79yWK=R(O$i
zxp!<6>a!Jl-sUGHw>6)|+rTAo{9L5T)GPd)JK!i-yDy4gscirf7wx&Lyv#i1y;2yn
z$!9R+6mZl#om^f^BK8j1>@51U#@EhPPjH=w^vW8tJGs3IZucyA{9cwTCdZUhQOA<z
zcd*CG-Tf`~UXS$kM1p#g$<D6IO<Lsqw~df&;qO82LVK>YTs7Z=cs4@Vk^=91yR=7X
z$&uD<pQ7$WD}2To(d|Nq9dL2rO#VibF~0Ds;+EA|+;H`&d04aeCLyLAl}1>+I!87t
zFhFDNItZD~Z)&2R^-B7h&vL00RaDsTQwTa#SK@So^GzEga{4`{=Q#UvNjnpt2Z~7@
zA9)A<;CPysO#!fqKg2pLShok?@U|&$6OXl)$a|<@=YLIe?g~2jG1O|~4r%FEdfR*l
zS#$5xSd>De)oDqd;<&L^QmrnK*+N9VRR2$2)k)2iaKSy(Z1@g(NtcDd*4C^V5a9RR
zzt6|u*o^scdi;pz66jI5M1yJ~mgCv-t-;>r^plFU^IdTX%!|<9UvPTwl9!47>NV@^
zYQAxp`~e?<gtIqS(WK?j-t1v_-c@-Dc|H%NyjbheW}`Ycsb2;D6wfF`Ct2x|Z`w~*
zVc|5ot+?bz|J7m_R3P9nnStFxZ?g}8kSk*o^93SqU&EXE4zzG38eEP!{#(Nk7W%m{
z6Y^Db<5n?U`XOrti!fR+Q9k8#eF)VRw{((}oiPlbg2MJRsxh}IVLsPkF7o&pwJ<`L
z{gjtmvzW8@mcwa8OPN^}Ztrsg_**c8B-~e=DVAhtIV?6;%TtlI<LW`T;TvxrZLHnS
z#LMH6Hns|BM~Rf4MZ@(;rhdOi+EiXvpQB6<on@OB@JH=0^5hWxpp=u(o6^Hkf}SVJ
z$+2as#p{^-o10bI>6MFc!&|An0mh*q*J)9lix+_i`@H(4D&PU(;4RE=d!z13rWDzh
zsYO$FX*6nqBxFAQsQibM%8R@3ED2CO)bLy~m(hw`<eere)o(PhZB;!YLJe$olTDxT
zI#7t?LKWXA6D>8S&69@4qe=T%rfs2AIm7<yFSlu)JfAOe9>K{gWtAp&|F$g3?&OLM
ze5Ni%z17mtHGf!zKFnI%x~}JXO?iPV;_TgBJWu$(NCOmjesWo^__hIGQYx&*YOU*R
zucz~abM~r~KG!H@4lS(qv^4-}D@s;&Q8le&mCoVokU?01O`bU(Xj|DY8c(?WVA3?3
zWipzVS`OpN<L+#<^rb3yMG;?^PTOd?snu#60cj8KEJp$2(8(tV_4)j^j?VsDA)|w4
za!>Pvr?Hl<g^dUAhlm}9Vb1O>U|7>_T~s{#=DSL(BE6p1a-ZB;1tVl(<iJNvJB}20
zb}O91$m+a+l&)YwBBGC!HYd0eBoFMPW5x+h3A<!2hbah;?<m)vEwL5Q>a}qmpZs3Q
zyt=t#98A<Xx<O2aBFitYtP}I9SaJL=G>XHLk*30ZM=5X}Yf+|yN1c6Tp5*Wc3PN!T
z+d=4<f~SEdsOd{eo(Qr3Q4zwa#07#{aTuJ>UIuf1G}mt4e5n!|?4kA@arK`gsFJcE
z0)PUb0U>};fc3>h126#j3xxn&FFfeNLoVD05OC4|>;eHn2qlCF0s^L!Wuc|vqXU4T
lgwJrAf|yO={DE`Ij6BXsh~<PC#6XEmh%cN7tN4l6zX3P~!t4M5
--- a/security/nss/tests/cert/cert.sh
+++ b/security/nss/tests/cert/cert.sh
@@ -443,16 +443,37 @@ cert_add_cert()
 	CU_ACTION="Import $CERTNAME's mixed EC Cert"
 	certu -A -n "${CERTNAME}-ecmixed" -t "u,u,u" -d "${PROFILEDIR}" \
 	    -f "${R_PWFILE}" -i "${CERTNAME}-ecmixed.cert" 2>&1
 	if [ "$RET" -ne 0 ]; then
             return $RET
 	fi
 	cert_log "SUCCESS: $CERTNAME's mixed EC Cert Created"
 
+	echo "Importing RSA-PSS server certificate"
+	pk12u -i ${QADIR}/cert/TestUser-rsa-pss-interop.p12 -k ${R_PWFILE} -w ${R_PWFILE} -d ${PROFILEDIR}
+	# Let's get the key ID of the imported private key.
+	KEYID=`${BINDIR}/certutil -d ${PROFILEDIR} -K -f ${R_PWFILE} | \
+		grep 'TestUser-rsa-pss-interop$' | sed -n 's/^<.*> [^ ]\{1,\} *\([^ ]\{1,\}\).*/\1/p'`
+
+	CU_ACTION="Generate RSA-PSS Cert Request for $CERTNAME"
+	CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-rsa-pss@bogus.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
+	certu -R -d "${PROFILEDIR}" -k ${KEYID} -f "${R_PWFILE}" \
+	-z "${R_NOISE_FILE}" -o req 2>&1
+
+	CU_ACTION="Sign ${CERTNAME}'s RSA-PSS Request"
+	NEWSERIAL=`expr ${CERTSERIAL} + 30000`
+	certu -C -c "TestCA" -m "$NEWSERIAL" -v 60 -d "${P_R_CADIR}" \
+	      -i req -o "${CERTNAME}-rsa-pss.cert" -f "${R_PWFILE}" "$1" 2>&1
+
+	CU_ACTION="Import $CERTNAME's RSA-PSS Cert -t u,u,u"
+	certu -A -n "$CERTNAME-rsa-pss" -t "u,u,u" -d "${PROFILEDIR}" -f "${R_PWFILE}" \
+	      -i "${CERTNAME}-rsa-pss.cert" 2>&1
+	cert_log "SUCCESS: $CERTNAME's RSA-PSS Cert Created"
+
     return 0
 }
 
 ################################# cert_all_CA ################################
 # local shell function to build the additional Temp. Certificate Authority (CA)
 # used for the "real life" ssl test with 2 different CA's in the
 # client and in the server's dir
 ##########################################################################
@@ -2098,16 +2119,33 @@ cert_test_implicit_db_init()
 {
   echo "$SCRIPTNAME: test implicit database init"
 
   CU_ACTION="Add cert with trust flags to db with implicit init"
   mkdir ${IMPLICIT_INIT_DIR}
   certu -A -n ca -t 'C,C,C' -d ${P_R_IMPLICIT_INIT_DIR} -i "${SERVER_CADIR}/serverCA.ca.cert"
 }
 
+cert_test_token_uri()
+{
+  echo "$SCRIPTNAME: specify token with PKCS#11 URI"
+
+  CERTIFICATE_DB_URI=`${BINDIR}/certutil -U -f "${R_PWFILE}" -d ${P_R_SERVERDIR} | sed -n 's/^ *uri: \(.*NSS%20Certificate%20DB.*\)/\1/p'`
+  BUILTIN_OBJECTS_URI=`${BINDIR}/certutil -U -f "${R_PWFILE}" -d ${P_R_SERVERDIR} | sed -n 's/^ *uri: \(.*Builtin%20Object%20Token.*\)/\1/p'`
+
+  CU_ACTION="List keys in NSS Certificate DB"
+  certu -K -f "${R_PWFILE}" -d ${P_R_SERVERDIR} -h ${CERTIFICATE_DB_URI}
+
+  # This token shouldn't have any keys
+  CU_ACTION="List keys in NSS Builtin Objects"
+  RETEXPECTED=255
+  certu -K -f "${R_PWFILE}" -d ${P_R_SERVERDIR} -h ${BUILTIN_OBJECTS_URI}
+  RETEXPECTED=0
+}
+
 check_sign_algo()
 {
   certu -L -n "$CERTNAME" -d "${PROFILEDIR}" -f "${R_PWFILE}" | \
       sed -n '/^ *Data:/,/^$/{
 /^        Signature Algorithm/,/^ *Salt length/s/^        //p
 }' > ${TMP}/signalgo.txt
 
   diff ${TMP}/signalgo.exp ${TMP}/signalgo.txt
@@ -2470,16 +2508,39 @@ EOF
 
   CU_ACTION="Sign ${CERTNAME}'s Request"
   RETEXPECTED=255
   certu -C -c "TestCA-rsa-pss-sha1" --pss-sign -Z SHA256 -m "${CERTSERIAL}" -v 60 -d "${P_R_CADIR}" \
         -i req -o "${CERTNAME}.cert" -f "${R_PWFILE}" "$1" 2>&1
   RETEXPECTED=0
 }
 
+cert_test_orphan_key_delete()
+{
+  CU_ACTION="Create orphan key in serverdir"
+  certu -G -k ec -q nistp256 -f "${R_PWFILE}" -z ${R_NOISE_FILE} -d ${PROFILEDIR}
+  # Let's get the key ID of the first orphan key.
+  # The output of certutil -K (list keys) isn't well formatted.
+  # The initial <key-number> part may or may not contain white space, which
+  # makes the use of awk to filter the column unreliable.
+  # To fix that, we remove the initial <number> field using sed, then select the
+  # column that contains the key ID.
+  ORPHAN=`${BINDIR}/certutil -d ${PROFILEDIR} -K -f ${R_PWFILE} | \
+          sed 's/^<.*>//g' | grep -w orphan | head -1 | awk '{print $2}'`
+  CU_ACTION="Delete orphan key"
+  certu -F -f "${R_PWFILE}" -k ${ORPHAN} -d ${PROFILEDIR}
+  # Ensure that the key is removed
+  certu -K -f "${R_PWFILE}" -d ${PROFILEDIR} | grep ${ORPHAN}
+  RET=$?
+  if [ "$RET" -eq 0 ]; then
+    html_failed "Deleting orphan key ($RET)"
+    cert_log "ERROR: Deleting orphan key failed $RET"
+  fi
+}
+
 cert_test_orphan_key_reuse()
 {
   CU_ACTION="Create orphan key in serverdir"
   certu -G -f "${R_PWFILE}" -z ${R_NOISE_FILE} -d ${PROFILEDIR}
   # Let's get the key ID of the first orphan key.
   # The output of certutil -K (list keys) isn't well formatted.
   # The initial <key-number> part may or may not contain white space, which
   # makes the use of awk to filter the column unreliable.
@@ -2514,31 +2575,33 @@ cert_cleanup()
 
 ################## main #################################################
 
 cert_init
 cert_all_CA
 cert_test_implicit_db_init
 cert_extended_ssl
 cert_ssl
+cert_test_orphan_key_delete
 cert_test_orphan_key_reuse
 cert_smime_client
 IS_FIPS_DISABLED=`certutil --build-flags |grep -cw NSS_FIPS_DISABLED`
 if [ $IS_FIPS_DISABLED -ne 0 ]; then
   cert_rsa_exponent_nonfips
 else
   cert_fips
 fi
 cert_eccurves
 cert_extensions
 cert_san_and_generic_extensions
 cert_test_password
 cert_test_distrust
 cert_test_ocspresp
 cert_test_rsapss
+cert_test_token_uri
 
 if [ -z "$NSS_TEST_DISABLE_CRL" ] ; then
     cert_crl_ssl
 else
     echo "$SCRIPTNAME: Skipping CRL Tests"
 fi
 
 if [ -n "$DO_DIST_ST" -a "$DO_DIST_ST" = "TRUE" ] ; then
new file mode 100644
--- /dev/null
+++ b/security/nss/tests/policy/crypto-policy.txt
@@ -0,0 +1,19 @@
+# col 1: expected return value of nss-policy-check
+# col 2: policy config statement, using _ instead of space
+# col 3: an extended regular expression, expected to match the output
+# col 4: description of the test
+#
+0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA1:HMAC-SHA384:HMAC-SHA512:SECP256R1:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:aes256-cbc:camellia256-cbc:aes128-gcm:aes128-cbc:camellia128-cbc:SHA256:SHA384:SHA512:SHA1:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:tls-version-min=tls1.0:dtls-version-min=dtls1.0:DH-MIN=1023:DSA-MIN=2048:RSA-MIN=2048 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Standard policy
+0 disallow=ALL_allow=HMAC-SHA1:HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP256R1:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:aes256-cbc:camellia256-cbc:aes128-gcm:aes128-cbc:camellia128-cbc:des-ede3-cbc:rc4:SHA256:SHA384:SHA512:SHA1:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:DHE-DSS:tls-version-min=tls1.0:dtls-version-min=tls1.0:DH-MIN=1023:DSA-MIN=1023:RSA-MIN=1023 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Legacy policy
+0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:SHA384:SHA512:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Reduced policy
+2 disallow=ALL_allow=dtls-version-min=:dtls-version-max= NSS-POLICY-FAIL Missing value
+2 disallow=ALL_allow=RSA-MIN=whatever NSS-POLICY-FAIL Invalid value
+2 disallow=ALL_allow=flower NSS-POLICY-FAIL Invalid identifier
+1 disallow=all NSS-POLICY-WARN.*NUMBER-OF-CERT-SIG disallow all
+1 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072 NSS-POLICY-WARN.*NUMBER-OF-HASH No Hashes
+1 disallow=ALL_allow=tls-version-min=0:tls-version-max=0 NSS-POLICY-WARN.*NUMBER-OF-TLS-VERSIONS All TLS versions disabled
+1 disallow=ALL_allow=dtls-version-min=0:dtls-version-max=0 NSS-POLICY-WARN.*NUMBER-OF-DTLS-VERSIONS All DTLS versions disabled
+1 disallow=ALL_allow=tls-version-min=tls1.2:tls-version-max=tls1.1 NSS-POLICY-WARN.*NUMBER-OF-TLS-VERSIONS Invalid range of TLS versions
+1 disallow=ALL_allow=dtls-version-min=tls1.2:dtls-version-max=tls1.1 NSS-POLICY-WARN.*NUMBER-OF-DTLS-VERSIONS Invalid range of DTLS versions
+1 disallow=ALL_allow=tls-version-min=tls1.1:tls-version-max=tls1.2 NSS-POLICY-INFO.*NUMBER-OF-TLS-VERSIONS Valid range of TLS versions
+1 disallow=ALL_allow=dtls-version-min=tls1.1:dtls-version-max=tls1.2 NSS-POLICY-INFO.*NUMBER-OF-DTLS-VERSIONS Valid range of DTLS versions
new file mode 100644
--- /dev/null
+++ b/security/nss/tests/policy/policy.sh
@@ -0,0 +1,58 @@
+#! /bin/bash
+#
+# 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/.
+
+########################################################################
+#
+# mozilla/security/nss/tests/policy/policy.sh
+#
+# Script to test NSS crypto policy code
+#
+########################################################################
+
+ignore_blank_lines()
+{
+  LC_ALL=C grep -v '^[[:space:]]*\(#\|$\)' "$1"
+}
+
+policy_run_tests()
+{
+  html_head "CRYPTO-POLICY"
+
+  POLICY_INPUT=${QADIR}/policy/crypto-policy.txt
+
+  ignore_blank_lines ${POLICY_INPUT} | \
+  while read value policy match testname
+  do
+    echo "$SCRIPTNAME: running \"$testname\" ----------------------------"
+    policy=`echo ${policy} | sed -e 's;_; ;g'`
+    match=`echo ${match} | sed -e 's;_; ;g'`
+    POLICY_FILE="${TMP}/nss-policy"
+
+    echo "$SCRIPTNAME: policy: \"$policy\""
+
+    cat > "$POLICY_FILE" << ++EOF++
+library=
+name=Policy
+NSS=flags=policyOnly,moduleDB
+++EOF++
+    echo "config=\"${policy}\"" >> "$POLICY_FILE"
+    echo "" >> "$POLICY_FILE"
+
+    nss-policy-check "$POLICY_FILE" >${TMP}/$HOST.tmp.$$ 2>&1
+    ret=$?
+    cat ${TMP}/$HOST.tmp.$$
+
+    html_msg $ret $value "\"${testname}\"" \
+        "produced a returncode of $ret, expected is $value"
+
+    egrep "${match}" ${TMP}/$HOST.tmp.$$
+    ret=$?
+    html_msg $ret 0 "\"${testname}\" output is expected to match \"${match}\""
+
+  done
+}
+
+policy_run_tests
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -206,32 +206,37 @@ kill_selfserv()
 # also: wait until the server is up and running
 ########################################################################
 start_selfserv()
 {
   if [ -n "$testname" ] ; then
       echo "$SCRIPTNAME: $testname ----"
   fi
   sparam=`echo $sparam | sed -e 's;_; ;g'`
-  if [ -z "$NO_ECC_CERTS" -o "$NO_ECC_CERTS" != "1"  ] ; then
+  if [ -z "$NO_ECC_CERTS" -o "$NO_ECC_CERTS" != "1" ] ; then
       ECC_OPTIONS="-e ${HOSTADDR}-ecmixed -e ${HOSTADDR}-ec"
   else
       ECC_OPTIONS=""
   fi
+  if [ -z "$RSA_PSS_CERT" -o "$RSA_PSS_CERT" != "1" ] ; then
+      RSA_OPTIONS="-n ${HOSTADDR}"
+  else
+      RSA_OPTIONS="-n ${HOSTADDR}-rsa-pss"
+  fi
   echo "selfserv starting at `date`"
-  echo "selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} -n ${HOSTADDR} ${SERVER_OPTIONS} \\"
+  echo "selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \\"
   echo "         ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss ${sparam} -i ${R_SERVERPID}\\"
   echo "         -V ssl3:tls1.2 $verbose -H 1 &"
   if [ ${fileout} -eq 1 ]; then
-      ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} -n ${HOSTADDR} ${SERVER_OPTIONS} \
+      ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \
                ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss ${sparam} -i ${R_SERVERPID} -V ssl3:tls1.2 $verbose -H 1 \
                > ${SERVEROUTFILE} 2>&1 &
       RET=$?
   else
-      ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} -n ${HOSTADDR} ${SERVER_OPTIONS} \
+      ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \
                ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss ${sparam} -i ${R_SERVERPID} -V ssl3:tls1.2 $verbose -H 1 &
       RET=$?
   fi
 
   # The PID $! returned by the MKS or Cygwin shell is not the PID of
   # the real background process, but rather the PID of a helper
   # process (sh.exe).  MKS's kill command has a bug: invoking kill
   # on the helper process does not terminate the real background
@@ -278,16 +283,23 @@ ssl_cov()
   VMAX="tls1.1"
 
   ignore_blank_lines ${SSLCOV} | \
   while read ectype testmax param testname
   do
       echo "${testname}" | grep "EXPORT" > /dev/null
       EXP=$?
 
+      # RSA-PSS tests are handled in a separate function
+      case $testname in
+	*RSA-PSS)
+	  continue
+          ;;
+      esac
+
       echo "$SCRIPTNAME: running $testname ----------------------------"
       VMAX="ssl3"
       if [ "$testmax" = "TLS10" ]; then
           VMAX="tls1.0"
       fi
       if [ "$testmax" = "TLS11" ]; then
           VMAX="tls1.1"
       fi
@@ -308,16 +320,69 @@ ssl_cov()
       html_msg $ret 0 "${testname}" \
                "produced a returncode of $ret, expected is 0"
   done
 
   kill_selfserv
   html "</TABLE><BR>"
 }
 
+ssl_cov_rsa_pss()
+{
+  #verbose="-v"
+  html_head "SSL Cipher Coverage (RSA-PSS) $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
+
+  testname=""
+  sparam="$CIPHER_SUITES"
+
+  if [ "$NORM_EXT" = "Extended Test" ] ; then
+      echo "$SCRIPTNAME: skipping SSL Cipher Coverage (RSA-PSS) for $NORM_EXT"
+      return 0
+  fi
+
+  RSA_PSS_CERT=1
+  NO_ECC_CERTS=1
+  start_selfserv # Launch the server
+  RSA_PSS_CERT=0
+  NO_ECC_CERTS=0
+
+  VMIN="tls1.2"
+  VMAX="tls1.2"
+
+  ignore_blank_lines ${SSLCOV} | \
+  while read ectype testmax param testname
+  do
+      case $testname in
+	*RSA-PSS)
+          ;;
+	*)
+	  continue
+	  ;;
+      esac
+
+      echo "$SCRIPTNAME: running $testname (RSA-PSS) ----------------------------"
+
+      echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
+      echo "        -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}"
+
+      rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
+      ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
+              -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE} \
+              >${TMP}/$HOST.tmp.$$  2>&1
+      ret=$?
+      cat ${TMP}/$HOST.tmp.$$
+      rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
+      html_msg $ret 0 "${testname}" \
+               "produced a returncode of $ret, expected is 0"
+  done
+
+  kill_selfserv
+  html "</TABLE><BR>"
+}
+
 ############################## ssl_auth ################################
 # local shell function to perform SSL  Client Authentication tests
 ########################################################################
 ssl_auth()
 {
   #verbose="-v"
   html_head "SSL Client Authentication $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
@@ -1147,16 +1212,17 @@ ssl_run()
               ssl_stapling
             fi
             ;;
         "signed_cert_timestamps")
             ssl_signed_cert_timestamps
             ;;
         "cov")
             ssl_cov
+            ssl_cov_rsa_pss
             ;;
         "auth")
             ssl_auth
             ;;
         "stress")
             ssl_stress
             ;;
         "dtls")
--- a/security/nss/tests/ssl/sslcov.txt
+++ b/security/nss/tests/ssl/sslcov.txt
@@ -136,8 +136,13 @@
    ECC   TLS12  :C027 TLS12_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    ECC   TLS12  :C028 TLS12_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    ECC   TLS12  :C02B TLS12_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    ECC   TLS12  :C02C TLS12_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    ECC   TLS12  :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    ECC   TLS12  :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    ECC   TLS12  :CCA8 TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    ECC   TLS12  :CCA9 TLS12_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+#
+# Test against server with RSA-PSS server certificate
+#
+   ECC   TLS12  :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - RSA-PSS
+   ECC   TLS12  :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - RSA-PSS
--- a/taskcluster/taskgraph/util/partials.py
+++ b/taskcluster/taskgraph/util/partials.py
@@ -40,29 +40,29 @@ BALROG_PLATFORM_MAP = {
         "WINNT_x86-msvc-x86",
         "WINNT_x86-msvc-x64"
     ],
     "win64": [
         "WINNT_x86_64-msvc",
         "WINNT_x86_64-msvc-x64"
     ],
     "win64-asan-reporter": [
-        "WINNT_x86_64-clangcl-asan"
+        "WINNT_x86_64-msvc-x64-asan"
     ]
 }
 
 FTP_PLATFORM_MAP = {
     "Darwin_x86-gcc3": "mac",
     "Darwin_x86-gcc3-u-i386-x86_64": "mac",
     "Darwin_x86_64-gcc3": "mac",
     "Darwin_x86_64-gcc3-u-i386-x86_64": "mac",
     "Linux_x86-gcc3": "linux-i686",
     "Linux_x86_64-gcc3": "linux-x86_64",
     "Linux_x86_64-gcc3-asan": "linux-x86_64-asan-reporter",
-    "WINNT_x86_64-clangcl-asan": "win64-asan-reporter",
+    "WINNT_x86_64-msvc-x64-asan": "win64-asan-reporter",
     "WINNT_x86-msvc": "win32",
     "WINNT_x86-msvc-x64": "win32",
     "WINNT_x86-msvc-x86": "win32",
     "WINNT_x86_64-msvc": "win64",
     "WINNT_x86_64-msvc-x64": "win64",
 }
 
 
--- a/testing/geckodriver/src/marionette.rs
+++ b/testing/geckodriver/src/marionette.rs
@@ -1125,21 +1125,16 @@ impl MarionetteCommand {
                 let caps = capabilities
                     .expect("Tried to create new session without processing capabilities");
 
                 let mut data = BTreeMap::new();
                 for (k, v) in caps.iter() {
                     data.insert(k.to_string(), v.to_json());
                 }
 
-                // duplicate in capabilities.desiredCapabilities for legacy compat
-                let mut legacy_caps = BTreeMap::new();
-                legacy_caps.insert("desiredCapabilities".to_string(), caps.to_json());
-                data.insert("capabilities".to_string(), legacy_caps.to_json());
-
                 (Some("WebDriver:NewSession"), Some(Ok(data)))
             }
             PerformActions(ref x) => (Some("WebDriver:PerformActions"), Some(x.to_marionette())),
             Refresh => (Some("WebDriver:Refresh"), None),
             ReleaseActions => (Some("WebDriver:ReleaseActions"), None),
             SendAlertText(ref x) => {
                 let mut data = BTreeMap::new();
                 data.insert("text".to_string(), x.text.to_json());