Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Thu, 23 May 2019 07:41:02 +0300
changeset 475112 840b7106d8ae3158aeba8268d2ac0b40c3682bcb
parent 475014 d12917561f27e4c4b4808707b55e88973dc4a385 (current diff)
parent 475111 f287bb6c18942c75aca41d54987006951270628d (diff)
child 475113 9fb72f8a2fe5f7446a0ddd1e5990ba6d3568b896
child 475222 490fd8b22deae669be2ee735757b0c8d5e417406
push id86153
push userbtara@mozilla.com
push dateThu, 23 May 2019 04:44:02 +0000
treeherderautoland@9fb72f8a2fe5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone69.0a1
first release with
nightly linux32
840b7106d8ae / 69.0a1 / 20190523044159 / files
nightly linux64
840b7106d8ae / 69.0a1 / 20190523044159 / files
nightly mac
840b7106d8ae / 69.0a1 / 20190523044159 / files
nightly win32
840b7106d8ae / 69.0a1 / 20190523044159 / files
nightly win64
840b7106d8ae / 69.0a1 / 20190523044159 / 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 inbound to mozilla-central. a=merge
dom/ipc/BrowserBridgeChild.cpp
dom/ipc/BrowserParent.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
netwerk/protocol/http/nsHttpChannel.cpp
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8897,45 +8897,16 @@ JitCode* JitRealm::generateStringConcatS
 #endif
 #ifdef MOZ_VTUNE
   vtune::MarkStub(code, "StringConcatStub");
 #endif
 
   return code;
 }
 
-void JitRuntime::generateMallocStub(MacroAssembler& masm) {
-  const Register regReturn = CallTempReg0;
-  const Register regZone = CallTempReg0;
-  const Register regNBytes = CallTempReg1;
-
-  mallocStubOffset_ = startTrampolineCode(masm);
-
-  AllocatableRegisterSet regs(RegisterSet::Volatile());
-#ifdef JS_USE_LINK_REGISTER
-  masm.pushReturnAddress();
-#endif
-  regs.takeUnchecked(regZone);
-  regs.takeUnchecked(regNBytes);
-  LiveRegisterSet save(regs.asLiveSet());
-  masm.PushRegsInMask(save);
-
-  const Register regTemp = regs.takeAnyGeneral();
-  MOZ_ASSERT(regTemp != regNBytes && regTemp != regZone);
-
-  masm.setupUnalignedABICall(regTemp);
-  masm.passABIArg(regZone);
-  masm.passABIArg(regNBytes);
-  masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MallocWrapper));
-  masm.storeCallPointerResult(regReturn);
-
-  masm.PopRegsInMask(save);
-  masm.ret();
-}
-
 void JitRuntime::generateFreeStub(MacroAssembler& masm) {
   const Register regSlots = CallTempReg0;
 
   freeStubOffset_ = startTrampolineCode(masm);
 
 #ifdef JS_USE_LINK_REGISTER
   masm.pushReturnAddress();
 #endif
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -281,19 +281,16 @@ bool JitRuntime::generateTrampolines(JSC
 
   JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Shape");
   shapePreBarrierOffset_ = generatePreBarrier(cx, masm, MIRType::Shape);
 
   JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for ObjectGroup");
   objectGroupPreBarrierOffset_ =
       generatePreBarrier(cx, masm, MIRType::ObjectGroup);
 
-  JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
-  generateMallocStub(masm);
-
   JitSpew(JitSpew_Codegen, "# Emitting free stub");
   generateFreeStub(masm);
 
   JitSpew(JitSpew_Codegen, "# Emitting lazy link stub");
   generateLazyLinkStub(masm);
 
   JitSpew(JitSpew_Codegen, "# Emitting interpreter stub");
   generateInterpreterStub(masm);
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -173,17 +173,16 @@ class JitRuntime {
   // Thunk that calls the GC pre barrier.
   WriteOnceData<uint32_t> valuePreBarrierOffset_;
   WriteOnceData<uint32_t> stringPreBarrierOffset_;
   WriteOnceData<uint32_t> objectPreBarrierOffset_;
   WriteOnceData<uint32_t> shapePreBarrierOffset_;
   WriteOnceData<uint32_t> objectGroupPreBarrierOffset_;
 
   // Thunk to call malloc/free.
-  WriteOnceData<uint32_t> mallocStubOffset_;
   WriteOnceData<uint32_t> freeStubOffset_;
 
   // Thunk called to finish compilation of an IonScript.
   WriteOnceData<uint32_t> lazyLinkStubOffset_;
 
   // Thunk to enter the interpreter from JIT code.
   WriteOnceData<uint32_t> interpreterStubOffset_;
 
@@ -261,17 +260,16 @@ class JitRuntime {
   void generateEnterJIT(JSContext* cx, MacroAssembler& masm);
   void generateArgumentsRectifier(MacroAssembler& masm);
   BailoutTable generateBailoutTable(MacroAssembler& masm, Label* bailoutTail,
                                     uint32_t frameClass);
   void generateBailoutHandler(MacroAssembler& masm, Label* bailoutTail);
   void generateInvalidator(MacroAssembler& masm, Label* bailoutTail);
   uint32_t generatePreBarrier(JSContext* cx, MacroAssembler& masm,
                               MIRType type);
-  void generateMallocStub(MacroAssembler& masm);
   void generateFreeStub(MacroAssembler& masm);
   JitCode* generateDebugTrapHandler(JSContext* cx, DebugTrapHandlerKind kind);
   JitCode* generateBaselineDebugModeOSRHandler(
       JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
 
   bool generateVMWrapper(JSContext* cx, MacroAssembler& masm,
                          const VMFunctionData& f, void* nativeFun,
                          uint32_t* wrapperOffset);
@@ -384,18 +382,16 @@ class JitRuntime {
         return trampolineCode(shapePreBarrierOffset_);
       case MIRType::ObjectGroup:
         return trampolineCode(objectGroupPreBarrierOffset_);
       default:
         MOZ_CRASH();
     }
   }
 
-  TrampolinePtr mallocStub() const { return trampolineCode(mallocStubOffset_); }
-
   TrampolinePtr freeStub() const { return trampolineCode(freeStubOffset_); }
 
   TrampolinePtr lazyLinkStub() const {
     return trampolineCode(lazyLinkStubOffset_);
   }
   TrampolinePtr interpreterStub() const {
     return trampolineCode(interpreterStubOffset_);
   }
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -620,50 +620,16 @@ void MacroAssembler::freeListAllocate(Re
   if (GetJitContext()->runtime->geckoProfiler().enabled()) {
     uint32_t* countAddress =
         GetJitContext()->runtime->addressOfTenuredAllocCount();
     movePtr(ImmPtr(countAddress), temp);
     add32(Imm32(1), Address(temp, 0));
   }
 }
 
-void MacroAssembler::callMallocStub(size_t nbytes, Register result,
-                                    Label* fail) {
-  // These registers must match the ones in JitRuntime::generateMallocStub.
-  const Register regReturn = CallTempReg0;
-  const Register regZone = CallTempReg0;
-  const Register regNBytes = CallTempReg1;
-
-  MOZ_ASSERT(nbytes > 0);
-  MOZ_ASSERT(nbytes <= INT32_MAX);
-
-  if (regZone != result) {
-    push(regZone);
-  }
-  if (regNBytes != result) {
-    push(regNBytes);
-  }
-
-  move32(Imm32(nbytes), regNBytes);
-  movePtr(ImmPtr(GetJitContext()->realm()->zone()), regZone);
-  call(GetJitContext()->runtime->jitRuntime()->mallocStub());
-  if (regReturn != result) {
-    movePtr(regReturn, result);
-  }
-
-  if (regNBytes != result) {
-    pop(regNBytes);
-  }
-  if (regZone != result) {
-    pop(regZone);
-  }
-
-  branchTest32(Assembler::Zero, result, result, fail);
-}
-
 void MacroAssembler::callFreeStub(Register slots) {
   // This register must match the one in JitRuntime::generateFreeStub.
   const Register regSlots = CallTempReg0;
 
   push(regSlots);
   movePtr(slots, regSlots);
   call(GetJitContext()->runtime->jitRuntime()->freeStub());
   pop(regSlots);
@@ -678,41 +644,24 @@ void MacroAssembler::allocateObject(Regi
 
   checkAllocatorState(fail);
 
   if (shouldNurseryAllocate(allocKind, initialHeap)) {
     MOZ_ASSERT(initialHeap == gc::DefaultHeap);
     return nurseryAllocateObject(result, temp, allocKind, nDynamicSlots, fail);
   }
 
-  if (!nDynamicSlots) {
-    return freeListAllocate(result, temp, allocKind, fail);
+  // Fall back to calling into the VM to allocate objects in the tenured heap
+  // that have dynamic slots.
+  if (nDynamicSlots) {
+    jump(fail);
+    return;
   }
 
-  // Only NativeObject can have nDynamicSlots > 0 and reach here.
-
-  callMallocStub(nDynamicSlots * sizeof(GCPtrValue), temp, fail);
-
-  Label failAlloc;
-  Label success;
-
-  push(temp);
-  freeListAllocate(result, temp, allocKind, &failAlloc);
-
-  pop(temp);
-  storePtr(temp, Address(result, NativeObject::offsetOfSlots()));
-
-  jump(&success);
-
-  bind(&failAlloc);
-  pop(temp);
-  callFreeStub(temp);
-  jump(fail);
-
-  bind(&success);
+  return freeListAllocate(result, temp, allocKind, fail);
 }
 
 void MacroAssembler::createGCObject(Register obj, Register temp,
                                     const TemplateObject& templateObj,
                                     gc::InitialHeap initialHeap, Label* fail,
                                     bool initContents) {
   gc::AllocKind allocKind = templateObj.getAllocKind();
   MOZ_ASSERT(gc::IsObjectAllocKind(allocKind));
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -2806,17 +2806,16 @@ class MacroAssembler : public MacroAssem
                               uint32_t end);
   void fillSlotsWithUninitialized(Address addr, Register temp, uint32_t start,
                                   uint32_t end);
 
   void initGCSlots(Register obj, Register temp,
                    const NativeTemplateObject& templateObj, bool initContents);
 
  public:
-  void callMallocStub(size_t nbytes, Register result, Label* fail);
   void callFreeStub(Register slots);
   void createGCObject(Register result, Register temp,
                       const TemplateObject& templateObj,
                       gc::InitialHeap initialHeap, Label* fail,
                       bool initContents = true);
 
   void initGCThing(Register obj, Register temp,
                    const TemplateObject& templateObj, bool initContents = true);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -638,21 +638,16 @@ bool SetProperty(JSContext* cx, HandleOb
 }
 
 bool InterruptCheck(JSContext* cx) {
   gc::MaybeVerifyBarriers(cx);
 
   return CheckForInterrupt(cx);
 }
 
-void* MallocWrapper(JS::Zone* zone, size_t nbytes) {
-  AutoUnsafeCallWithABI unsafe;
-  return zone->pod_malloc<uint8_t>(nbytes);
-}
-
 JSObject* NewCallObject(JSContext* cx, HandleShape shape,
                         HandleObjectGroup group) {
   JSObject* obj = CallObject::create(cx, shape, group);
   if (!obj) {
     return nullptr;
   }
 
   // The JIT creates call objects in the nursery, so elides barriers for
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -882,17 +882,16 @@ JSFlatString* StringFromCharCode(JSConte
 JSString* StringFromCodePoint(JSContext* cx, int32_t codePoint);
 
 MOZ_MUST_USE bool SetProperty(JSContext* cx, HandleObject obj,
                               HandlePropertyName name, HandleValue value,
                               bool strict, jsbytecode* pc);
 
 MOZ_MUST_USE bool InterruptCheck(JSContext* cx);
 
-void* MallocWrapper(JS::Zone* zone, size_t nbytes);
 JSObject* NewCallObject(JSContext* cx, HandleShape shape,
                         HandleObjectGroup group);
 JSObject* NewStringObject(JSContext* cx, HandleString str);
 
 bool OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out);
 bool OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out);
 
 MOZ_MUST_USE bool GetIntrinsicValue(JSContext* cx, HandlePropertyName name,
--- a/js/src/jsapi-tests/testScriptObject.cpp
+++ b/js/src/jsapi-tests/testScriptObject.cpp
@@ -2,17 +2,17 @@
  * 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 "mozilla/Utf8.h"  // mozilla::Utf8Unit
 
-#include "js/CompilationAndEvaluation.h"  // JS::Compile{,DontInflate,Utf8{FileDontInflate,Path}}
+#include "js/CompilationAndEvaluation.h"  // JS::Compile{,{,Utf8{File,Path}}DontInflate}
 #include "js/SourceText.h"  // JS::Source{Ownership,Text}
 #include "jsapi-tests/tests.h"
 
 struct ScriptObjectFixture : public JSAPITest {
   static const int code_size;
   static const char code[];
   static char16_t uc_code[];
 
@@ -130,36 +130,36 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, 
   static const char script_filename[] = "temp-bug438633_JS_CompileFile";
   FILE* script_stream = tempScript.open(script_filename);
   CHECK(fputs(code, script_stream) != EOF);
   tempScript.close();
 
   JS::CompileOptions options(cx);
   options.setFileAndLine(script_filename, 1);
 
-  JS::RootedScript script(cx,
-                          JS::CompileUtf8Path(cx, options, script_filename));
+  JS::RootedScript script(
+      cx, JS::CompileUtf8PathDontInflate(cx, options, script_filename));
   CHECK(script);
 
   tempScript.remove();
   return tryScript(script);
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty) {
   TempFile tempScript;
   static const char script_filename[] = "temp-bug438633_JS_CompileFile_empty";
   tempScript.open(script_filename);
   tempScript.close();
 
   JS::CompileOptions options(cx);
   options.setFileAndLine(script_filename, 1);
 
-  JS::RootedScript script(cx,
-                          JS::CompileUtf8Path(cx, options, script_filename));
+  JS::RootedScript script(
+      cx, JS::CompileUtf8PathDontInflate(cx, options, script_filename));
   CHECK(script);
 
   tempScript.remove();
   return tryScript(script);
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle) {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -978,17 +978,17 @@ static bool InitModuleLoader(JSContext* 
   options.strictOption = true;
 
   JS::SourceText<Utf8Unit> srcBuf;
   if (!srcBuf.init(cx, std::move(src), srcLen)) {
     return false;
   }
 
   RootedValue rv(cx);
-  return JS::Evaluate(cx, options, srcBuf, &rv);
+  return JS::EvaluateDontInflate(cx, options, srcBuf, &rv);
 }
 
 static bool GetModuleImportHook(JSContext* cx,
                                 MutableHandleFunction resultOut) {
   Handle<GlobalObject*> global = cx->global();
   RootedValue hookValue(cx,
                         global->getReservedSlot(GlobalAppSlotModuleLoadHook));
   if (hookValue.isUndefined()) {
@@ -1763,19 +1763,20 @@ static bool LoadScript(JSContext* cx, un
     errno = 0;
 
     CompileOptions opts(cx);
     opts.setIntroductionType("js shell load")
         .setIsRunOnce(true)
         .setNoScriptRval(true);
 
     RootedValue unused(cx);
-    if (!(compileOnly
-              ? JS::CompileUtf8Path(cx, opts, filename.get()) != nullptr
-              : JS::EvaluateUtf8Path(cx, opts, filename.get(), &unused))) {
+    if (!(compileOnly ? JS::CompileUtf8PathDontInflate(
+                            cx, opts, filename.get()) != nullptr
+                      : JS::EvaluateUtf8PathDontInflate(
+                            cx, opts, filename.get(), &unused))) {
       return false;
     }
   }
 
   args.rval().setUndefined();
   return true;
 }
 
@@ -3493,17 +3494,17 @@ static bool DisassFile(JSContext* cx, un
 
   {
     CompileOptions options(cx);
     options.setIntroductionType("js shell disFile")
         .setFileAndLine(filename.get(), 1)
         .setIsRunOnce(true)
         .setNoScriptRval(true);
 
-    script = JS::CompileUtf8Path(cx, options, filename.get());
+    script = JS::CompileUtf8PathDontInflate(cx, options, filename.get());
     if (!script) {
       return false;
     }
   }
 
   Sprinter sprinter(cx);
   if (!sprinter.init()) {
     return false;
@@ -10159,17 +10160,17 @@ static MOZ_MUST_USE bool ProcessArgs(JSC
       opts.setFileAndLine("-e", 1);
 
       JS::SourceText<Utf8Unit> srcBuf;
       if (!srcBuf.init(cx, code, strlen(code), JS::SourceOwnership::Borrowed)) {
         return false;
       }
 
       RootedValue rval(cx);
-      if (!JS::Evaluate(cx, opts, srcBuf, &rval)) {
+      if (!JS::EvaluateDontInflate(cx, opts, srcBuf, &rval)) {
         return false;
       }
 
       codeChunks.popFront();
       if (sc->quitting) {
         break;
       }
 
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -2878,20 +2878,20 @@ XDRResult ScriptSource::codeBinASTData(X
 }
 
 template <typename Unit, XDRMode mode>
 /* static */
 void ScriptSource::codeRetrievableData(ScriptSource* ss) {
   // There's nothing to code for retrievable data.  Just be sure to set
   // retrievable data when decoding.
   if (mode == XDR_ENCODE) {
-    MOZ_ASSERT(ss->data.is<Retrievable<char16_t>>());
+    MOZ_ASSERT(ss->data.is<Retrievable<Unit>>());
   } else {
     MOZ_ASSERT(ss->data.is<Missing>());
-    ss->data = SourceType(Retrievable<char16_t>());
+    ss->data = SourceType(Retrievable<Unit>());
   }
 }
 
 template <XDRMode mode>
 /* static */
 XDRResult ScriptSource::xdrData(XDRState<mode>* const xdr,
                                 ScriptSource* const ss) {
   // Retrievability is kept outside |ScriptSource::data| (and not solely as
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -3106,17 +3106,17 @@ bool JSRuntime::initSelfHosting(JSContex
   FillSelfHostingCompileOptions(options);
 
   JS::SourceText<mozilla::Utf8Unit> srcBuf;
   if (!srcBuf.init(cx, std::move(src), srcLen)) {
     return false;
   }
 
   RootedValue rv(cx);
-  if (!Evaluate(cx, options, srcBuf, &rv)) {
+  if (!EvaluateDontInflate(cx, options, srcBuf, &rv)) {
     return false;
   }
 
   if (!VerifyGlobalNames(cx, shg)) {
     return false;
   }
 
   return true;
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -989,17 +989,17 @@ static bool ProcessArgs(AutoJSAPI& jsapi
         }
 
         JS::CompileOptions opts(cx);
         opts.setFileAndLine("-e", 1);
 
         JS::SourceText<mozilla::Utf8Unit> srcBuf;
         if (srcBuf.init(cx, argv[i], strlen(argv[i]),
                         JS::SourceOwnership::Borrowed)) {
-          JS::Evaluate(cx, opts, srcBuf, &rval);
+          JS::EvaluateDontInflate(cx, opts, srcBuf, &rval);
         }
 
         isInteractive = false;
         break;
       }
       case 'C':
         compileOnly = true;
         isInteractive = false;
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_44_RTM
+ec6843bc0ce7
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -1,21 +0,0 @@
-
-1 Added function:
-
-  'function SECStatus CERT_GetCertificateDer(const CERTCertificate*, SECItem*)'    {CERT_GetCertificateDer@@NSS_3.44}
-
-1 function with some indirect sub-type change:
-
-  [C]'function SECStatus CERT_AddOCSPAcceptableResponses(CERTOCSPRequest*, SECOidTag, ...)' at ocsp.c:2203:1 has some indirect sub-type changes:
-    parameter 2 of type 'typedef SECOidTag' has sub-type changes:
-      underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
-        type size hasn't changed
-        3 enumerator insertions:
-          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_END' value '361'
-          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL' value '362'
-          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_USER' value '363'
-
-        1 enumerator change:
-          '__anonymous_enum__::SEC_OID_TOTAL' from value '361' to '364' at secoidt.h:34:1
-
-
-
--- a/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
@@ -1,17 +0,0 @@
-
-1 function with some indirect sub-type change:
-
-  [C]'function SECStatus NSS_GetAlgorithmPolicy(SECOidTag, PRUint32*)' at secoid.c:2234:1 has some indirect sub-type changes:
-    parameter 1 of type 'typedef SECOidTag' has sub-type changes:
-      underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
-        type size hasn't changed
-        3 enumerator insertions:
-          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_END' value '361'
-          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL' value '362'
-          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_USER' value '363'
-
-        1 enumerator change:
-          '__anonymous_enum__::SEC_OID_TOTAL' from value '361' to '364' at secoidt.h:34:1
-
-
-
--- a/security/nss/automation/abi-check/expected-report-libsmime3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libsmime3.so.txt
@@ -1,47 +0,0 @@
-
-1 function with some indirect sub-type change:
-
-  [C]'function PK11SymKey* NSS_CMSContentInfo_GetBulkKey(NSSCMSContentInfo*)' at cmscinfo.c:426:1 has some indirect sub-type changes:
-    parameter 1 of type 'NSSCMSContentInfo*' has sub-type changes:
-      in pointed to type 'typedef NSSCMSContentInfo' at cmst.h:54:1:
-        underlying type 'struct NSSCMSContentInfoStr' at cmst.h:126:1 changed:
-          type size hasn't changed
-          1 data member changes (2 filtered):
-           type of 'NSSCMSContent NSSCMSContentInfoStr::content' changed:
-             underlying type 'union NSSCMSContentUnion' at cmst.h:113:1 changed:
-               type size hasn't changed
-               1 data member changes (3 filtered):
-                type of 'NSSCMSEncryptedData* NSSCMSContentUnion::encryptedData' changed:
-                  in pointed to type 'typedef NSSCMSEncryptedData' at cmst.h:65:1:
-                    underlying type 'struct NSSCMSEncryptedDataStr' at cmst.h:463:1 changed:
-                      type size hasn't changed
-                      1 data member changes (1 filtered):
-                       type of 'NSSCMSAttribute** NSSCMSEncryptedDataStr::unprotectedAttr' changed:
-                         in pointed to type 'NSSCMSAttribute*':
-                           in pointed to type 'typedef NSSCMSAttribute' at cmst.h:69:1:
-                             underlying type 'struct NSSCMSAttributeStr' at cmst.h:482:1 changed:
-                               type size hasn't changed
-                               1 data member change:
-                                type of 'SECOidData* NSSCMSAttributeStr::typeTag' changed:
-                                  in pointed to type 'typedef SECOidData' at secoidt.h:16:1:
-                                    underlying type 'struct SECOidDataStr' at secoidt.h:518:1 changed:
-                                      type size hasn't changed
-                                      1 data member change:
-                                       type of 'SECOidTag SECOidDataStr::offset' changed:
-                                         underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
-                                           type size hasn't changed
-                                           3 enumerator insertions:
-                                             '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_END' value '361'
-                                             '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL' value '362'
-                                             '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_USER' value '363'
-
-                                           1 enumerator change:
-                                             '__anonymous_enum__::SEC_OID_TOTAL' from value '361' to '364' at secoidt.h:34:1
-
-
-
-
-
-
-
-
--- a/security/nss/automation/abi-check/previous-nss-release
+++ b/security/nss/automation/abi-check/previous-nss-release
@@ -1,1 +1,1 @@
-NSS_3_43_BRANCH
+NSS_3_44_BRANCH
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -98,25 +98,16 @@ queue.filter(task => {
     return false;
   }
 
   // Only old make builds have -Ddisable_libpkix=0 and can run chain tests.
   if (task.tests == "chains" && task.collection != "make") {
     return false;
   }
 
-  if (task.group == "Test") {
-    // Don't run test builds on old make platforms, and not for fips gyp.
-    // Disable on aarch64, see bug 1488331.
-    if (task.collection == "make" || task.collection == "fips"
-        || task.platform == "aarch64") {
-      return false;
-    }
-  }
-
   // Don't run all additional hardware tests on ARM.
   if (task.group == "Cipher" && task.platform == "aarch64" && task.env &&
       (task.env.NSS_DISABLE_PCLMUL == "1" || task.env.NSS_DISABLE_HW_AES == "1"
        || task.env.NSS_DISABLE_AVX == "1")) {
     return false;
   }
 
   return true;
@@ -134,17 +125,18 @@ queue.map(task => {
   if (task.tests == "ssl") {
     if (!task.env) {
       task.env = {};
     }
     task.env.NSS_SSL_TESTS = "crl iopr policy";
   }
 
   // Windows is slow.
-  if (task.platform == "windows2012-64" && task.tests == "chains") {
+  if ((task.platform == "windows2012-32" || task.platform == "windows2012-64") &&
+      task.tests == "chains") {
     task.maxRunTime = 7200;
   }
 
   return task;
 });
 
 /*****************************************************************************/
 
@@ -320,17 +312,17 @@ async function scheduleMac(name, base, a
     platform: "mac"
   });
 
   // Build base definition.
   let build_base = merge(mac_base, {
     command: [
       MAC_CHECKOUT_CMD,
       ["bash", "-c",
-       "nss/automation/taskcluster/scripts/build_gyp.sh", args]
+       "nss/automation/taskcluster/scripts/build_gyp.sh " + args]
     ],
     provisioner: "localprovisioner",
     workerType: "nss-macos-10-12",
     platform: "mac",
     maxRunTime: 7200,
     artifacts: [{
       expires: 24 * 7,
       type: "directory",
@@ -523,18 +515,16 @@ async function scheduleLinux(name, overr
     command: [
       "/bin/bash",
       "-c",
       "bin/checkout.sh && nss/automation/taskcluster/scripts/build.sh",
     ],
     symbol: "modular"
   }));
 
-  await scheduleTestBuilds(name + " Test", merge(base, {group: "Test"}), args);
-
   return queue.submit();
 }
 
 /*****************************************************************************/
 
 function scheduleFuzzingRun(base, name, target, max_len, symbol = null, corpus = null) {
   const MAX_FUZZ_TIME = 300;
 
@@ -758,81 +748,16 @@ async function scheduleFuzzing32() {
   scheduleFuzzingRun(tls_fm_base, "DTLS Client", "dtls-client", 20000, "dtls-client");
   scheduleFuzzingRun(tls_fm_base, "DTLS Server", "dtls-server", 20000, "dtls-server");
 
   return queue.submit();
 }
 
 /*****************************************************************************/
 
-async function scheduleTestBuilds(name, base, args = "") {
-  // Build base definition.
-  let build = merge(base, {
-    command: [
-      "/bin/bash",
-      "-c",
-      "bin/checkout.sh && " +
-      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --test --ct-verif " + args
-    ],
-    artifacts: {
-      public: {
-        expires: 24 * 7,
-        type: "directory",
-        path: "/home/worker/artifacts"
-      }
-    },
-    kind: "build",
-    symbol: "B",
-    name: `${name} build`,
-  });
-
-  // On linux we have a specialized build image for building.
-  if (build.platform === "linux32" || build.platform === "linux64") {
-    build = merge(build, {
-      image: LINUX_BUILDS_IMAGE,
-    });
-  }
-
-  // The task that builds NSPR+NSS.
-  let task_build = queue.scheduleTask(build);
-
-  // Schedule tests.
-  queue.scheduleTask(merge(base, {
-    parent: task_build,
-    name: `${name} mpi tests`,
-    command: [
-      "/bin/bash",
-      "-c",
-      "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
-    ],
-    tests: "mpi",
-    cycle: "standard",
-    symbol: "mpi",
-    kind: "test"
-  }));
-  queue.scheduleTask(merge(base, {
-    parent: task_build,
-    command: [
-      "/bin/bash",
-      "-c",
-      "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
-    ],
-    name: `${name} gtests`,
-    symbol: "Gtest",
-    tests: "gtests",
-    cycle: "standard",
-    kind: "test"
-  }));
-
-  return queue.submit();
-}
-
-
-/*****************************************************************************/
-
 async function scheduleWindows(name, base, build_script) {
   base = merge(base, {
     workerType: "nss-win2012r2",
     env: {
       PATH: "c:\\mozilla-build\\bin;c:\\mozilla-build\\python;" +
 	    "c:\\mozilla-build\\msys\\local\\bin;c:\\mozilla-build\\7zip;" +
 	    "c:\\mozilla-build\\info-zip;c:\\mozilla-build\\python\\Scripts;" +
 	    "c:\\mozilla-build\\yasm;c:\\mozilla-build\\msys\\bin;" +
@@ -946,16 +871,19 @@ function scheduleTests(task_build, task_
     symbol: "Interop",
     tests: "interop",
     cycle: "standard",
     image: LINUX_INTEROP_IMAGE,
   }));
   queue.scheduleTask(merge(no_cert_base, {
     name: "tlsfuzzer tests", symbol: "tlsfuzzer", tests: "tlsfuzzer", cycle: "standard"
   }));
+  queue.scheduleTask(merge(no_cert_base, {
+    name: "MPI tests", symbol: "MPI", tests: "mpi", cycle: "standard"
+  }));
   queue.scheduleTask(merge(cert_base, {
     name: "Chains tests", symbol: "Chains", tests: "chains"
   }));
   queue.scheduleTask(merge(cert_base_long, {
     name: "Cipher tests", symbol: "Default", tests: "cipher", group: "Cipher"
   }));
   queue.scheduleTask(merge(cert_base_long, {
     name: "Cipher tests", symbol: "NoAESNI", tests: "cipher",
--- a/security/nss/build.sh
+++ b/security/nss/build.sh
@@ -89,17 +89,16 @@ while [ $# -gt 0 ]; do
         --ubsan=?*) enable_ubsan "${1#*=}" ;;
         --fuzz) fuzz=1 ;;
         --fuzz=oss) fuzz=1; fuzz_oss=1 ;;
         --fuzz=tls) fuzz=1; fuzz_tls=1 ;;
         --sancov) enable_sancov ;;
         --sancov=?*) enable_sancov "${1#*=}" ;;
         --emit-llvm) gyp_params+=(-Demit_llvm=1 -Dsign_libs=0) ;;
         --no-zdefs) gyp_params+=(-Dno_zdefs=1) ;;
-        --test) gyp_params+=(-Dtest_build=1 -Dstatic_libs=1) ;;
         --static) gyp_params+=(-Dstatic_libs=1) ;;
         --ct-verif) gyp_params+=(-Dct_verif=1) ;;
         --nspr) nspr_clean; rebuild_nspr=1 ;;
         --with-nspr=?*) set_nspr_path "${1#*=}"; no_local_nspr=1 ;;
         --system-nspr) set_nspr_path "/usr/include/nspr/:"; no_local_nspr=1 ;;
         --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;
         --enable-fips) gyp_params+=(-Ddisable_fips=0) ;;
         --enable-libpkix) gyp_params+=(-Ddisable_libpkix=0) ;;
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -1949,17 +1949,17 @@ server_main(
             errExit("SSL_OptionSet SSL_NO_CACHE");
         }
     }
 
     if (zeroRTT) {
         if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) {
             errExit("You tried enabling 0RTT without enabling TLS 1.3!");
         }
-        rv = SSL_SetupAntiReplay(10 * PR_USEC_PER_SEC, 7, 14);
+        rv = SSL_InitAntiReplay(PR_Now(), 10L * PR_USEC_PER_SEC, 7, 14);
         if (rv != SECSuccess) {
             errExit("error configuring anti-replay ");
         }
         rv = SSL_OptionSet(model_sock, SSL_ENABLE_0RTT_DATA, PR_TRUE);
         if (rv != SECSuccess) {
             errExit("error enabling 0RTT ");
         }
     }
--- a/security/nss/coreconf/config.gypi
+++ b/security/nss/coreconf/config.gypi
@@ -101,17 +101,16 @@
     'disable_dbm%': 0,
     'disable_libpkix%': 1,
     'disable_werror%': 0,
     'mozilla_client%': 0,
     'comm_client%': 0,
     'moz_fold_libs%': 0,
     'moz_folded_library_name%': '',
     'sanitizer_flags%': 0,
-    'test_build%': 0,
     'static_libs%': 0,
     'no_zdefs%': 0,
     'fuzz%': 0,
     'fuzz_tls%': 0,
     'fuzz_oss%': 0,
     'sign_libs%': 1,
     'use_pprof%': 0,
     'ct_verif%': 0,
@@ -125,17 +124,16 @@
     'disable_fips%': 1,
     'mozpkix_only%': 0,
   },
   'target_defaults': {
     # Settings specific to targets should go here.
     # This is mostly for linking to libraries.
     'variables': {
       'mapfile%': '',
-      'test_build%': 0,
       'static_libs%': 0,
       'debug_optimization_level%': '0',
       'release_optimization_level%': '2',
     },
     'standalone_static_library': 0,
     'include_dirs': [
       '<(nspr_include_dir)',
       '<(nss_dist_dir)/private/<(module)',
@@ -147,21 +145,16 @@
         ],
       }],
       [ 'disable_fips==1', {
         'defines': [
           'NSS_FIPS_DISABLED',
           'NSS_NO_INIT_SUPPORT',
         ],
       }],
-      [ 'static_libs==1', {
-        'variables': {
-          'standalone_static_library': '1',
-        },
-      }],
       [ 'OS!="android" and OS!="mac" and OS!="ios" and OS!="win"', {
         'libraries': [
           '-lpthread',
         ],
       }],
       [ 'OS=="linux"', {
         'libraries': [
           '-ldl',
@@ -228,17 +221,17 @@
     'target_conditions': [
       # If we want to properly export a static library, and copy it to lib,
       # we need to mark it as a 'standalone_static_library'. Otherwise,
       # the relative paths in the thin archive will break linking.
       [ '_type=="shared_library"', {
         'product_dir': '<(nss_dist_obj_dir)/lib'
       }, '_type=="executable"', {
         'product_dir': '<(nss_dist_obj_dir)/bin'
-      }, '_standalone_static_library==1', {
+      }, 'static_libs==1 or _standalone_static_library==1', {
         'product_dir': '<(nss_dist_obj_dir)/lib'
       }],
       # mapfile handling
       [ 'mapfile!=""', {
         # Work around a gyp bug. Fixed upstream but not in Ubuntu packages:
         # https://chromium.googlesource.com/external/gyp/+/b85ad3e578da830377dbc1843aa4fbc5af17a192%5E%21/
         'sources': [
           '<(DEPTH)/coreconf/empty.c',
@@ -319,16 +312,19 @@
           ],
         },
         'msvs_settings': {
           'VCLinkerTool': {
             'SubSystem': '2',
           },
         },
       }],
+      [ '_type=="static_library" and static_libs==1', {
+        'standalone_static_library': 1,
+      }],
     ],
     'default_configuration': 'Debug',
     'configurations': {
       # Common settings for Debug+Release should go here.
       'Common': {
         'abstract': 1,
         'defines': [
           'USE_UTIL_DIRECTLY',
--- 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/coreconf/fuzz.sh
+++ b/security/nss/coreconf/fuzz.sh
@@ -9,17 +9,17 @@ if [ -z "$CC" ]; then
         echo "Fuzzing requires clang!"
         exit 1
     fi
     export CC=clang
     export CCC=clang++
     export CXX=clang++
 fi
 
-gyp_params+=(-Dtest_build=1 -Dstatic_libs=1 -Dfuzz=1 -Dsign_libs=0)
+gyp_params+=(-Dstatic_libs=1 -Dfuzz=1 -Dsign_libs=0)
 
 # Add debug symbols even for opt builds.
 nspr_params+=(--enable-debug-symbols)
 
 if [ "$fuzz_oss" = 1 ]; then
   gyp_params+=(-Dno_zdefs=1 -Dfuzz_oss=1)
 else
   enable_sanitizer asan
--- a/security/nss/fuzz/fuzz.gyp
+++ b/security/nss/fuzz/fuzz.gyp
@@ -86,17 +86,17 @@
             'libraries': [
               '/usr/lib/x86_64-linux-gnu/libcrypto.a',
             ],
           }, {
             'libraries': [
               '-lcrypto',
             ],
           }],
-          # For test builds we have to set MPI defines.
+          # For static builds we have to set MPI defines.
           [ 'target_arch=="ia32"', {
             'defines': [
               'MP_USE_UINT_DIGIT',
               'MP_ASSEMBLY_MULTIPLY',
               'MP_ASSEMBLY_SQUARE',
               'MP_ASSEMBLY_DIV_2DX1D',
             ],
           }],
--- a/security/nss/fuzz/tls_client_target.cc
+++ b/security/nss/fuzz/tls_client_target.cc
@@ -101,16 +101,17 @@ extern "C" int LLVMFuzzerTestOneInput(co
   static PRDescIdentity id = PR_GetUniqueIdentity("fuzz-client");
   ScopedPRFileDesc fd(DummyIOLayerMethods::CreateFD(id, socket.get()));
   PRFileDesc* ssl_fd = ImportFD(nullptr, fd.get());
   assert(ssl_fd == fd.get());
 
   // Probably not too important for clients.
   SSL_SetURL(ssl_fd, "server");
 
+  FixTime(ssl_fd);
   SetSocketOptions(ssl_fd, config);
   EnableAllCipherSuites(ssl_fd);
   SetupCallbacks(ssl_fd, config.get());
   DoHandshake(ssl_fd, false);
 
   // Release all SIDs.
   SSL_ClearSessionCache();
 
--- a/security/nss/fuzz/tls_common.cc
+++ b/security/nss/fuzz/tls_common.cc
@@ -1,18 +1,27 @@
 /* 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 <assert.h>
 
 #include "ssl.h"
+#include "sslexp.h"
 
 #include "tls_common.h"
 
+static PRTime FixedTime(void*) { return 1234; }
+
+// Fix the time input, to avoid any time-based variation.
+void FixTime(PRFileDesc* fd) {
+  SECStatus rv = SSL_SetTimeFunc(fd, FixedTime, nullptr);
+  assert(rv == SECSuccess);
+}
+
 PRStatus EnableAllProtocolVersions() {
   SSLVersionRange supported;
 
   SECStatus rv = SSL_VersionRangeGetSupported(ssl_variant_stream, &supported);
   assert(rv == SECSuccess);
 
   rv = SSL_VersionRangeSetDefault(ssl_variant_stream, &supported);
   assert(rv == SECSuccess);
--- a/security/nss/fuzz/tls_common.h
+++ b/security/nss/fuzz/tls_common.h
@@ -2,13 +2,14 @@
  * 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 tls_common_h__
 #define tls_common_h__
 
 #include "prinit.h"
 
+void FixTime(PRFileDesc* fd);
 PRStatus EnableAllProtocolVersions();
 void EnableAllCipherSuites(PRFileDesc* fd);
 void DoHandshake(PRFileDesc* fd, bool isServer);
 
 #endif  // tls_common_h__
--- a/security/nss/fuzz/tls_server_target.cc
+++ b/security/nss/fuzz/tls_server_target.cc
@@ -113,16 +113,17 @@ extern "C" int LLVMFuzzerTestOneInput(co
 
   // Create and import dummy socket.
   std::unique_ptr<DummyPrSocket> socket(new DummyPrSocket(data, len));
   static PRDescIdentity id = PR_GetUniqueIdentity("fuzz-server");
   ScopedPRFileDesc fd(DummyIOLayerMethods::CreateFD(id, socket.get()));
   PRFileDesc* ssl_fd = ImportFD(model.get(), fd.get());
   assert(ssl_fd == fd.get());
 
+  FixTime(ssl_fd);
   SetSocketOptions(ssl_fd, config);
   DoHandshake(ssl_fd, true);
 
   return 0;
 }
 
 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
                                           size_t max_size, unsigned int seed) {
--- a/security/nss/gtests/common/gtest.gypi
+++ b/security/nss/gtests/common/gtest.gypi
@@ -16,16 +16,23 @@
         '-Wsign-compare',
       ],
     },
     'conditions': [
       ['OS=="win"', {
         'libraries': [
           '-lws2_32',
         ],
+        'conditions': [
+          ['static_libs==1', {
+            'libraries': [
+              '-ladvapi32',
+            ],
+          }],
+        ],
       }],
       ['OS=="android"', {
         'libraries': [
           '-lstdc++',
         ],
       }],
       [ 'fuzz==1', {
         'defines': [
--- a/security/nss/gtests/common/gtests.cc
+++ b/security/nss/gtests/common/gtests.cc
@@ -1,11 +1,10 @@
 #include "nspr.h"
 #include "nss.h"
-#include "ssl.h"
 
 #include <cstdlib>
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
 int main(int argc, char **argv) {
   ::testing::InitGoogleTest(&argc, argv);
@@ -24,19 +23,16 @@ int main(int argc, char **argv) {
     } else if (!strcmp(argv[i], "-w")) {
       flags &= ~NSS_INIT_READONLY;
     }
   }
 
   if (NSS_Initialize(workdir, "", "", SECMOD_DB, flags) != SECSuccess) {
     return 1;
   }
-  if (NSS_SetDomesticPolicy() != SECSuccess) {
-    return 1;
-  }
   int rv = RUN_ALL_TESTS();
 
   if (NSS_Shutdown() != SECSuccess) {
     return 1;
   }
 
   return rv;
 }
--- a/security/nss/gtests/common/testvectors/chachapoly-vectors.h
+++ b/security/nss/gtests/common/testvectors/chachapoly-vectors.h
@@ -8,32 +8,32 @@
  * Generation is trigged by calling ./mach wycheproof */
 
 #ifndef chachapoly_vectors_h__
 #define chachapoly_vectors_h__
 
 #include <string>
 #include <vector>
 
-typedef struct chacha_testvector_str {
+typedef struct chaChaTestVectorStr {
   uint32_t id;
   std::vector<uint8_t> Data;
   std::vector<uint8_t> AAD;
   std::vector<uint8_t> Key;
   std::vector<uint8_t> IV;
   std::vector<uint8_t> CT;
-  bool invalid_tag;
-  bool invalid_iv;
-} chacha_testvector;
+  bool invalidTag;
+  bool invalidIV;
+} chaChaTestVector;
 
 // ChaCha20/Poly1305 Test Vector 1, RFC 7539
 // <http://tools.ietf.org/html/rfc7539#section-2.8.2>
 // ChaCha20/Poly1305 Test Vector 2, RFC 7539
 // <http://tools.ietf.org/html/rfc7539#appendix-A.5>
-const chacha_testvector kChaCha20Vectors[] = {
+const chaChaTestVector kChaCha20Vectors[] = {
     {0,
      {0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47,
       0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
       0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66,
       0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
       0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79,
       0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
       0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
@@ -111,17 +111,17 @@ const chacha_testvector kChaCha20Vectors
       0x6c, 0x6f, 0x2c, 0x29, 0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
       0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22, 0x39, 0x23, 0x36,
       0xfe, 0xa1, 0x85, 0x1f, 0x38},
      false,
      false}};
 
 // Testvectors from project wycheproof
 // <https://github.com/google/wycheproof>
-const chacha_testvector kChaCha20WycheproofVectors[] = {
+const chaChaTestVector kChaCha20WycheproofVectors[] = {
 
     // Comment: rfc7539
     {0,
      {0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47,
       0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
       0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66,
       0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
       0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79,
@@ -145,16 +145,42 @@ const chacha_testvector kChaCha20Wychepr
       0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
       0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65,
       0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09,
       0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91},
      false,
      false},
 
     // Comment:
+    {1,
+     {},
+     {},
+     {0x80, 0xba, 0x31, 0x92, 0xc8, 0x03, 0xce, 0x96, 0x5e, 0xa3, 0x71,
+      0xd5, 0xff, 0x07, 0x3c, 0xf0, 0xf4, 0x3b, 0x6a, 0x2a, 0xb5, 0x76,
+      0xb2, 0x08, 0x42, 0x6e, 0x11, 0x40, 0x9c, 0x09, 0xb9, 0xb0},
+     {0x4d, 0xa5, 0xbf, 0x8d, 0xfd, 0x58, 0x52, 0xc1, 0xea, 0x12, 0x37, 0x9d},
+     {0x76, 0xac, 0xb3, 0x42, 0xcf, 0x31, 0x66, 0xa5, 0xb6, 0x3c, 0x0c, 0x0e,
+      0xa1, 0x38, 0x3c, 0x8d},
+     false,
+     false},
+
+    // Comment:
+    {2,
+     {},
+     {0xbd, 0x50, 0x67, 0x64, 0xf2, 0xd2, 0xc4, 0x10},
+     {0x7a, 0x4c, 0xd7, 0x59, 0x17, 0x2e, 0x02, 0xeb, 0x20, 0x4d, 0xb2,
+      0xc3, 0xf5, 0xc7, 0x46, 0x22, 0x7d, 0xf5, 0x84, 0xfc, 0x13, 0x45,
+      0x19, 0x63, 0x91, 0xdb, 0xb9, 0x57, 0x7a, 0x25, 0x07, 0x42},
+     {0xa9, 0x2e, 0xf0, 0xac, 0x99, 0x1d, 0xd5, 0x16, 0xa3, 0xc6, 0xf6, 0x89},
+     {0x90, 0x6f, 0xa6, 0x28, 0x4b, 0x52, 0xf8, 0x7b, 0x73, 0x59, 0xcb, 0xaa,
+      0x75, 0x63, 0xc7, 0x09},
+     false,
+     false},
+
+    // Comment:
     {3,
      {0x2a},
      {},
      {0xcc, 0x56, 0xb6, 0x80, 0x55, 0x2e, 0xb7, 0x50, 0x08, 0xf5, 0x48,
       0x4b, 0x4c, 0xb8, 0x03, 0xfa, 0x50, 0x63, 0xeb, 0xd6, 0xea, 0xb9,
       0x1f, 0x6a, 0xb6, 0xae, 0xf4, 0x91, 0x6a, 0x76, 0x62, 0x73},
      {0x99, 0xe2, 0x3e, 0xc4, 0x89, 0x85, 0xbc, 0xcd, 0xee, 0xab, 0x60, 0xf1},
      {0x3a, 0xca, 0xc2, 0x7d, 0xec, 0x09, 0x68, 0x80, 0x1e, 0x9f, 0x6e, 0xde,
@@ -1290,16 +1316,296 @@ const chacha_testvector kChaCha20Wychepr
       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf2, 0x35, 0x42,
       0x97, 0x84, 0x9a, 0x51, 0x1d, 0x53, 0xe5, 0x57, 0x17, 0x72, 0xf7, 0x1f},
      false,
      false},
 
     // Comment: Flipped bit 0 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {61,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa2, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 1 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {62,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa1, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 7 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {63,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0x23, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 8 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {64,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe2, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 31 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {65,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0x79, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 32 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {66,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfa, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 33 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {67,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xf9, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 63 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {68,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x9b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 64 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {69,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5b, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 77 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {70,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xf2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 80 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {71,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x61, 0x7f,
+      0x40, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 96 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {72,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x41, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 97 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {73,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x42, 0xb7, 0xf4, 0x47},
+     true,
+     false},
+
+    // Comment: Flipped bit 120 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {74,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x46},
+     true,
+     false},
+
+    // Comment: Flipped bit 121 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {75,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x45},
+     true,
+     false},
+
+    // Comment: Flipped bit 126 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {76,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0x07},
+     true,
+     false},
+
+    // Comment: Flipped bit 127 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {77,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0xc7},
+     true,
+     false},
+
+    // Comment: Flipped bit 63 and 127 in tag expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {78,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x9b, 0x5a, 0xd2, 0x60, 0x7f,
+      0x40, 0xb7, 0xf4, 0xc7},
+     true,
+     false},
+
+    // Comment: Tag changed to all zero expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {79,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00},
+     true,
+     false},
+
+    // Comment: tag change to all 1 expected
+    // tag:a3e3fdf9fba6861b5ad2607f40b7f447
+    {80,
+     {},
+     {0x61, 0x61, 0x64},
+     {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+      0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+      0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b},
+     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+      0xff, 0xff, 0xff, 0xff},
+     true,
+     false},
+
+    // Comment: Flipped bit 0 in tag expected
     // tag:27da374f17b7f1b23844a5490bfc4001
     {81,
      {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00},
      {0x61, 0x61, 0x64},
      {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
       0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
       0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
--- a/security/nss/gtests/common/testvectors_base/chachapoly-vectors_base.h
+++ b/security/nss/gtests/common/testvectors_base/chachapoly-vectors_base.h
@@ -8,32 +8,32 @@
  * Generation is trigged by calling ./mach wycheproof */
 
 #ifndef chachapoly_vectors_h__
 #define chachapoly_vectors_h__
 
 #include <string>
 #include <vector>
 
-typedef struct chacha_testvector_str {
+typedef struct chaChaTestVectorStr {
   uint32_t id;
   std::vector<uint8_t> Data;
   std::vector<uint8_t> AAD;
   std::vector<uint8_t> Key;
   std::vector<uint8_t> IV;
   std::vector<uint8_t> CT;
-  bool invalid_tag;
-  bool invalid_iv;
-} chacha_testvector;
+  bool invalidTag;
+  bool invalidIV;
+} chaChaTestVector;
 
 // ChaCha20/Poly1305 Test Vector 1, RFC 7539
 // <http://tools.ietf.org/html/rfc7539#section-2.8.2>
 // ChaCha20/Poly1305 Test Vector 2, RFC 7539
 // <http://tools.ietf.org/html/rfc7539#appendix-A.5>
-const chacha_testvector kChaCha20Vectors[] = {
+const chaChaTestVector kChaCha20Vectors[] = {
     {0,
      {0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47,
       0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
       0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66,
       0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
       0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79,
       0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
       0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
--- a/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
+++ b/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
@@ -80,17 +80,17 @@
       '<(DEPTH)/lib/util/',
       '<(DEPTH)/lib/certdb/',
       '<(DEPTH)/lib/cryptohi/',
       '<(DEPTH)/lib/pk11wrap/',
     ],
     'defines': [
       'NSS_USE_STATIC_LIBS',
     ],
-    # For test builds we have to set MPI defines.
+    # For static builds we have to set MPI defines.
     'conditions': [
       [ 'ct_verif==1', {
         'defines': [
           'CT_VERIF',
         ],
       }],
       [ 'target_arch=="ia32"', {
         'defines': [
--- a/security/nss/gtests/freebl_gtest/mpi_unittest.cc
+++ b/security/nss/gtests/freebl_gtest/mpi_unittest.cc
@@ -143,16 +143,51 @@ TEST_F(MPITest, MpiCmpUnalignedTest) {
   ASSERT_TRUE(strncmp(c_tmp, "feffffffffffffff100000000000000", 31));
 
   mp_clear(&a);
   mp_clear(&b);
   mp_clear(&c);
 }
 #endif
 
+// The two follow tests ensure very similar mp_set_* functions are ok.
+TEST_F(MPITest, MpiSetUlong) {
+  mp_int a, b, c;
+  MP_DIGITS(&a) = 0;
+  MP_DIGITS(&b) = 0;
+  MP_DIGITS(&c) = 0;
+  ASSERT_EQ(MP_OKAY, mp_init(&a));
+  ASSERT_EQ(MP_OKAY, mp_init(&b));
+  ASSERT_EQ(MP_OKAY, mp_init(&c));
+  EXPECT_EQ(MP_OKAY, mp_set_ulong(&a, 1));
+  EXPECT_EQ(MP_OKAY, mp_set_ulong(&b, 0));
+  EXPECT_EQ(MP_OKAY, mp_set_ulong(&c, -1));
+
+  mp_clear(&a);
+  mp_clear(&b);
+  mp_clear(&c);
+}
+
+TEST_F(MPITest, MpiSetInt) {
+  mp_int a, b, c;
+  MP_DIGITS(&a) = 0;
+  MP_DIGITS(&b) = 0;
+  MP_DIGITS(&c) = 0;
+  ASSERT_EQ(MP_OKAY, mp_init(&a));
+  ASSERT_EQ(MP_OKAY, mp_init(&b));
+  ASSERT_EQ(MP_OKAY, mp_init(&c));
+  EXPECT_EQ(MP_OKAY, mp_set_int(&a, 1));
+  EXPECT_EQ(MP_OKAY, mp_set_int(&b, 0));
+  EXPECT_EQ(MP_OKAY, mp_set_int(&c, -1));
+
+  mp_clear(&a);
+  mp_clear(&b);
+  mp_clear(&c);
+}
+
 TEST_F(MPITest, MpiFixlenOctetsZero) {
   std::vector<uint8_t> zero = {0};
   TestToFixedOctets(zero, 1);
   TestToFixedOctets(zero, 2);
   TestToFixedOctets(zero, sizeof(mp_digit));
   TestToFixedOctets(zero, sizeof(mp_digit) + 1);
 }
 
--- a/security/nss/gtests/pk11_gtest/manifest.mn
+++ b/security/nss/gtests/pk11_gtest/manifest.mn
@@ -3,16 +3,17 @@
 # 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 = ../..
 DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       pk11_aeskeywrap_unittest.cc \
+      pk11_cbc_unittest.cc \
       pk11_chacha20poly1305_unittest.cc \
       pk11_curve25519_unittest.cc \
       pk11_ecdsa_unittest.cc \
       pk11_encrypt_derive_unittest.cc \
       pk11_export_unittest.cc \
       pk11_import_unittest.cc \
       pk11_pbkdf2_unittest.cc \
       pk11_prf_unittest.cc \
--- a/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
@@ -51,28 +51,36 @@ class Pkcs11AesGcmTest : public ::testin
     SECItem keyItem = {siBuffer, key.data(),
                        static_cast<unsigned int>(key.size())};
 
     // Import key.
     ScopedPK11SymKey symKey(PK11_ImportSymKey(
         slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
     ASSERT_TRUE(!!symKey) << msg;
 
-    // Encrypt.
+    // Encrypt with bogus parameters.
     unsigned int outputLen = 0;
     std::vector<uint8_t> output(plaintext.size() + gcmParams.ulTagBits / 8);
+    gcmParams.ulTagBits = 159082344;
     SECStatus rv =
         PK11_Encrypt(symKey.get(), mech, &params, output.data(), &outputLen,
                      output.size(), plaintext.data(), plaintext.size());
+    EXPECT_EQ(SECFailure, rv);
+    EXPECT_EQ(0U, outputLen);
+    gcmParams.ulTagBits = 128;
+
+    // Encrypt.
+    rv = PK11_Encrypt(symKey.get(), mech, &params, output.data(), &outputLen,
+                      output.size(), plaintext.data(), plaintext.size());
     if (invalid_iv) {
       EXPECT_EQ(rv, SECFailure) << msg;
+      EXPECT_EQ(0U, outputLen);
       return;
-    } else {
-      EXPECT_EQ(rv, SECSuccess) << msg;
     }
+    EXPECT_EQ(rv, SECSuccess) << msg;
 
     ASSERT_EQ(outputLen, output.size()) << msg;
 
     // Check ciphertext and tag.
     if (invalid_ct) {
       EXPECT_NE(result, output) << msg;
     } else {
       EXPECT_EQ(result, output) << msg;
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 <memory>
+#include "nss.h"
+#include "pk11pub.h"
+#include "secerr.h"
+
+#include "nss_scoped_ptrs.h"
+#include "gtest/gtest.h"
+
+namespace nss_test {
+
+static const uint8_t kInput[99] = {1, 2, 3};
+static const uint8_t kKeyData[24] = {'K', 'E', 'Y'};
+
+static SECItem* GetIv() {
+  static const uint8_t kIvData[16] = {'I', 'V'};
+  static const SECItem kIv = {siBuffer, const_cast<uint8_t*>(kIvData),
+                              static_cast<unsigned int>(sizeof(kIvData))};
+  return const_cast<SECItem*>(&kIv);
+}
+
+class Pkcs11CbcPadTest : public ::testing::TestWithParam<CK_MECHANISM_TYPE> {
+ protected:
+  bool is_padded() const {
+    switch (GetParam()) {
+      case CKM_AES_CBC_PAD:
+      case CKM_DES3_CBC_PAD:
+        return true;
+
+      case CKM_AES_CBC:
+      case CKM_DES3_CBC:
+        return false;
+
+      default:
+        ADD_FAILURE() << "Unknown mechanism " << GetParam();
+    }
+    return false;
+  }
+
+  size_t block_size() const {
+    return static_cast<size_t>(PK11_GetBlockSize(GetParam(), nullptr));
+  }
+
+  size_t GetInputLen(CK_ATTRIBUTE_TYPE op) const {
+    if (is_padded() && op == CKA_ENCRYPT) {
+      // Anything goes for encryption when padded.
+      return sizeof(kInput);
+    }
+
+    // Otherwise, use a strict multiple of the block size.
+    size_t block_count = sizeof(kInput) / block_size();
+    EXPECT_LT(1U, block_count) << "need 2 blocks for tests";
+    return block_count * block_size();
+  }
+
+  ScopedPK11SymKey MakeKey(CK_ATTRIBUTE_TYPE op) {
+    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+    EXPECT_NE(nullptr, slot);
+    if (!slot) {
+      return nullptr;
+    }
+
+    unsigned int key_len = 0;
+    switch (GetParam()) {
+      case CKM_AES_CBC_PAD:
+      case CKM_AES_CBC:
+        key_len = 16;  // This doesn't do AES-256 to keep it simple.
+        break;
+
+      case CKM_DES3_CBC_PAD:
+      case CKM_DES3_CBC:
+        key_len = 24;
+        break;
+
+      default:
+        ADD_FAILURE() << "Unknown mechanism " << GetParam();
+        return nullptr;
+    }
+
+    SECItem key_item = {siBuffer, const_cast<uint8_t*>(kKeyData), key_len};
+    PK11SymKey* p = PK11_ImportSymKey(slot.get(), GetParam(), PK11_OriginUnwrap,
+                                      op, &key_item, nullptr);
+    EXPECT_NE(nullptr, p);
+    return ScopedPK11SymKey(p);
+  }
+
+  ScopedPK11Context MakeContext(CK_ATTRIBUTE_TYPE op) {
+    ScopedPK11SymKey k = MakeKey(op);
+    PK11Context* ctx =
+        PK11_CreateContextBySymKey(GetParam(), op, k.get(), GetIv());
+    EXPECT_NE(nullptr, ctx);
+    return ScopedPK11Context(ctx);
+  }
+};
+
+TEST_P(Pkcs11CbcPadTest, EncryptDecrypt) {
+  uint8_t encrypted[sizeof(kInput) + 64];  // Allow for padding and expansion.
+  size_t input_len = GetInputLen(CKA_ENCRYPT);
+
+  ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
+  unsigned int encrypted_len = 0;
+  SECStatus rv =
+      PK11_Encrypt(ek.get(), GetParam(), GetIv(), encrypted, &encrypted_len,
+                   sizeof(encrypted), kInput, input_len);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_LE(input_len, static_cast<size_t>(encrypted_len));
+
+  // Though the decrypted result can't be larger than the input we provided,
+  // NSS needs extra space to put the padding in.
+  uint8_t decrypted[sizeof(kInput) + 64];
+  unsigned int decrypted_len = 0;
+  ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
+  rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted, &decrypted_len,
+                    sizeof(decrypted), encrypted, encrypted_len);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len));
+  EXPECT_EQ(0, memcmp(kInput, decrypted, input_len));
+}
+
+TEST_P(Pkcs11CbcPadTest, ContextEncryptDecrypt) {
+  uint8_t encrypted[sizeof(kInput) + 64];  // Allow for padding and expansion.
+  size_t input_len = GetInputLen(CKA_ENCRYPT);
+
+  ScopedPK11Context ectx = MakeContext(CKA_ENCRYPT);
+  int encrypted_len = 0;
+  SECStatus rv = PK11_CipherOp(ectx.get(), encrypted, &encrypted_len,
+                               sizeof(encrypted), kInput, input_len);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_LE(0, encrypted_len);  // Stupid signed parameters.
+
+  unsigned int final_len = 0;
+  rv = PK11_CipherFinal(ectx.get(), encrypted + encrypted_len, &final_len,
+                        sizeof(encrypted) - encrypted_len);
+  ASSERT_EQ(SECSuccess, rv);
+  encrypted_len += final_len;
+  EXPECT_LE(input_len, static_cast<size_t>(encrypted_len));
+
+  uint8_t decrypted[sizeof(kInput) + 64];
+  int decrypted_len = 0;
+  ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
+  rv = PK11_CipherOp(dctx.get(), decrypted, &decrypted_len, sizeof(decrypted),
+                     encrypted, encrypted_len);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_LE(0, decrypted_len);
+
+  rv = PK11_CipherFinal(dctx.get(), decrypted + decrypted_len, &final_len,
+                        sizeof(decrypted) - decrypted_len);
+  ASSERT_EQ(SECSuccess, rv);
+  decrypted_len += final_len;
+  EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len));
+  EXPECT_EQ(0, memcmp(kInput, decrypted, input_len));
+}
+
+TEST_P(Pkcs11CbcPadTest, ContextEncryptDecryptTwoParts) {
+  uint8_t encrypted[sizeof(kInput) + 64];
+  size_t input_len = GetInputLen(CKA_ENCRYPT);
+
+  ScopedPK11Context ectx = MakeContext(CKA_ENCRYPT);
+  int first_len = 0;
+  SECStatus rv = PK11_CipherOp(ectx.get(), encrypted, &first_len,
+                               sizeof(encrypted), kInput, block_size());
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_LE(0, first_len);
+
+  int second_len = 0;
+  rv = PK11_CipherOp(ectx.get(), encrypted + first_len, &second_len,
+                     sizeof(encrypted) - first_len, kInput + block_size(),
+                     input_len - block_size());
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_LE(0, second_len);
+
+  unsigned int final_len = 0;
+  rv = PK11_CipherFinal(ectx.get(), encrypted + first_len + second_len,
+                        &final_len, sizeof(encrypted) - first_len - second_len);
+  ASSERT_EQ(SECSuccess, rv);
+  unsigned int encrypted_len = first_len + second_len + final_len;
+  ASSERT_LE(input_len, static_cast<size_t>(encrypted_len));
+
+  // Now decrypt this in a similar fashion.
+  uint8_t decrypted[sizeof(kInput) + 64];
+  ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
+  rv = PK11_CipherOp(dctx.get(), decrypted, &first_len, sizeof(decrypted),
+                     encrypted, block_size());
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_LE(0, first_len);
+
+  rv = PK11_CipherOp(dctx.get(), decrypted + first_len, &second_len,
+                     sizeof(decrypted) - first_len, encrypted + block_size(),
+                     encrypted_len - block_size());
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_LE(0, second_len);
+
+  unsigned int decrypted_len = 0;
+  rv = PK11_CipherFinal(dctx.get(), decrypted + first_len + second_len,
+                        &decrypted_len,
+                        sizeof(decrypted) - first_len - second_len);
+  ASSERT_EQ(SECSuccess, rv);
+  decrypted_len += first_len + second_len;
+  EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len));
+  EXPECT_EQ(0, memcmp(kInput, decrypted, input_len));
+}
+
+TEST_P(Pkcs11CbcPadTest, FailDecryptSimple) {
+  ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
+  uint8_t output[sizeof(kInput) + 64];
+  unsigned int output_len = 999;
+  SECStatus rv =
+      PK11_Decrypt(dk.get(), GetParam(), GetIv(), output, &output_len,
+                   sizeof(output), kInput, GetInputLen(CKA_DECRYPT));
+  if (is_padded()) {
+    EXPECT_EQ(SECFailure, rv);
+    EXPECT_EQ(999U, output_len);
+  } else {
+    // Unpadded decryption can't really fail.
+    EXPECT_EQ(SECSuccess, rv);
+  }
+}
+
+TEST_P(Pkcs11CbcPadTest, FailEncryptSimple) {
+  ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
+  uint8_t output[3];  // Too small for anything.
+  unsigned int output_len = 333;
+
+  SECStatus rv =
+      PK11_Encrypt(ek.get(), GetParam(), GetIv(), output, &output_len,
+                   sizeof(output), kInput, GetInputLen(CKA_ENCRYPT));
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(333U, output_len);
+}
+
+TEST_P(Pkcs11CbcPadTest, ContextFailDecryptSimple) {
+  ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
+  uint8_t output[sizeof(kInput) + 64];
+  int output_len = 77;
+
+  SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output),
+                               kInput, GetInputLen(CKA_DECRYPT));
+  EXPECT_EQ(SECSuccess, rv);
+  EXPECT_LE(0, output_len) << "this is not an AEAD, so content leaks";
+
+  unsigned int final_len = 88;
+  rv = PK11_CipherFinal(dctx.get(), output, &final_len, sizeof(output));
+  if (is_padded()) {
+    EXPECT_EQ(SECFailure, rv);
+    ASSERT_EQ(88U, final_len) << "final_len should be untouched";
+  } else {
+    // Unpadded decryption can't really fail.
+    EXPECT_EQ(SECSuccess, rv);
+  }
+}
+
+TEST_P(Pkcs11CbcPadTest, ContextFailDecryptInvalidBlockSize) {
+  ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
+  uint8_t output[sizeof(kInput) + 64];
+  int output_len = 888;
+
+  SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output),
+                               kInput, GetInputLen(CKA_DECRYPT) - 1);
+  EXPECT_EQ(SECFailure, rv);
+  // Because PK11_CipherOp is partial, it can return data on failure.
+  // This means that it needs to reset its output length to 0 when it starts.
+  EXPECT_EQ(0, output_len) << "output_len is reset";
+}
+
+INSTANTIATE_TEST_CASE_P(EncryptDecrypt, Pkcs11CbcPadTest,
+                        ::testing::Values(CKM_AES_CBC_PAD, CKM_AES_CBC,
+                                          CKM_DES3_CBC_PAD, CKM_DES3_CBC));
+
+}  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
@@ -21,17 +21,17 @@ namespace nss_test {
 static const CK_MECHANISM_TYPE kMech = CKM_NSS_CHACHA20_POLY1305;
 static const CK_MECHANISM_TYPE kMechXor = CKM_NSS_CHACHA20_CTR;
 // Some test data for simple tests.
 static const uint8_t kKeyData[32] = {'k'};
 static const uint8_t kCtrNonce[16] = {'c', 0, 0, 0, 'n'};
 static const uint8_t kData[16] = {'d'};
 
 class Pkcs11ChaCha20Poly1305Test
-    : public ::testing::TestWithParam<chacha_testvector> {
+    : public ::testing::TestWithParam<chaChaTestVector> {
  public:
   void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv,
                       const bool invalid_tag, const uint8_t* data,
                       size_t data_len, const uint8_t* aad, size_t aad_len,
                       const uint8_t* iv, size_t iv_len,
                       const uint8_t* ct = nullptr, size_t ct_len = 0) {
     // Prepare AEAD params.
     CK_NSS_AEAD_PARAMS aead_params;
@@ -39,227 +39,261 @@ class Pkcs11ChaCha20Poly1305Test
     aead_params.ulNonceLen = iv_len;
     aead_params.pAAD = toUcharPtr(aad);
     aead_params.ulAADLen = aad_len;
     aead_params.ulTagLen = 16;
 
     SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params),
                       sizeof(aead_params)};
 
+    // Encrypt with bad parameters.
+    unsigned int encrypted_len = 0;
+    std::vector<uint8_t> encrypted(data_len + aead_params.ulTagLen);
+    aead_params.ulTagLen = 158072;
+    SECStatus rv =
+        PK11_Encrypt(key.get(), kMech, &params, encrypted.data(),
+                     &encrypted_len, encrypted.size(), data, data_len);
+    EXPECT_EQ(SECFailure, rv);
+    EXPECT_EQ(0U, encrypted_len);
+    aead_params.ulTagLen = 16;
+
     // Encrypt.
-    unsigned int outputLen = 0;
-    std::vector<uint8_t> output(data_len + aead_params.ulTagLen);
-    SECStatus rv = PK11_Encrypt(key.get(), kMech, &params, output.data(),
-                                &outputLen, output.size(), data, data_len);
+    rv = PK11_Encrypt(key.get(), kMech, &params, encrypted.data(),
+                      &encrypted_len, encrypted.size(), data, data_len);
 
     // Return if encryption failure was expected due to invalid IV.
     // Without valid ciphertext, all further tests can be skipped.
     if (invalid_iv) {
       EXPECT_EQ(rv, SECFailure);
+      EXPECT_EQ(0U, encrypted_len)
+          << "encrypted_len is unmodified after failure";
       return;
-    } else {
-      EXPECT_EQ(rv, SECSuccess);
     }
 
+    EXPECT_EQ(rv, SECSuccess);
+    EXPECT_EQ(encrypted.size(), static_cast<size_t>(encrypted_len));
+
     // Check ciphertext and tag.
     if (ct) {
-      ASSERT_EQ(ct_len, outputLen);
-      EXPECT_TRUE(!memcmp(ct, output.data(), outputLen) != invalid_tag);
+      ASSERT_EQ(ct_len, encrypted_len);
+      EXPECT_TRUE(!memcmp(ct, encrypted.data(), encrypted.size()) !=
+                  invalid_tag);
     }
 
-    // Decrypt.
-    unsigned int decryptedLen = 0;
-    std::vector<uint8_t> decrypted(data_len);
-    rv =
-        PK11_Decrypt(key.get(), kMech, &params, decrypted.data(), &decryptedLen,
-                     decrypted.size(), output.data(), outputLen);
+    // Get the *estimated* plaintext length. This value should
+    // never be zero as it could lead to a NULL outPtr being
+    // passed to a subsequent decryption call (for AEAD we
+    // must authenticate even when the pt is zero-length).
+    unsigned int decrypt_bytes_needed = 0;
+    rv = PK11_Decrypt(key.get(), kMech, &params, nullptr, &decrypt_bytes_needed,
+                      0, encrypted.data(), encrypted_len);
+    EXPECT_EQ(rv, SECSuccess);
+    EXPECT_GT(decrypt_bytes_needed, data_len);
+
+    // Now decrypt it
+    std::vector<uint8_t> decrypted(decrypt_bytes_needed);
+    unsigned int decrypted_len = 0;
+    rv = PK11_Decrypt(key.get(), kMech, &params, decrypted.data(),
+                      &decrypted_len, decrypted.size(), encrypted.data(),
+                      encrypted.size());
     EXPECT_EQ(rv, SECSuccess);
 
     // Check the plaintext.
-    ASSERT_EQ(data_len, decryptedLen);
-    EXPECT_TRUE(!memcmp(data, decrypted.data(), decryptedLen));
+    ASSERT_EQ(data_len, decrypted_len);
+    EXPECT_TRUE(!memcmp(data, decrypted.data(), decrypted_len));
 
     // Decrypt with bogus data.
     // Skip if there's no data to modify.
-    if (outputLen != 0) {
-      std::vector<uint8_t> bogusCiphertext(output);
-      bogusCiphertext[0] ^= 0xff;
+    if (encrypted_len > 0) {
+      decrypted_len = 0;
+      std::vector<uint8_t> bogus_ciphertext(encrypted);
+      bogus_ciphertext[0] ^= 0xff;
       rv = PK11_Decrypt(key.get(), kMech, &params, decrypted.data(),
-                        &decryptedLen, decrypted.size(), bogusCiphertext.data(),
-                        outputLen);
-      EXPECT_NE(rv, SECSuccess);
+                        &decrypted_len, decrypted.size(),
+                        bogus_ciphertext.data(), encrypted_len);
+      EXPECT_EQ(rv, SECFailure);
+      EXPECT_EQ(0U, decrypted_len);
     }
 
     // Decrypt with bogus tag.
     // Skip if there's no tag to modify.
-    if (outputLen != 0) {
-      std::vector<uint8_t> bogusTag(output);
-      bogusTag[outputLen - 1] ^= 0xff;
+    if (encrypted_len > 0) {
+      decrypted_len = 0;
+      std::vector<uint8_t> bogus_tag(encrypted);
+      bogus_tag[encrypted_len - 1] ^= 0xff;
       rv = PK11_Decrypt(key.get(), kMech, &params, decrypted.data(),
-                        &decryptedLen, decrypted.size(), bogusTag.data(),
-                        outputLen);
-      EXPECT_NE(rv, SECSuccess);
+                        &decrypted_len, decrypted.size(), bogus_tag.data(),
+                        encrypted_len);
+      EXPECT_EQ(rv, SECFailure);
+      EXPECT_EQ(0U, decrypted_len);
     }
 
     // Decrypt with bogus IV.
     // iv_len == 0 is invalid and should be caught earlier.
     // Still skip, if there's no IV to modify.
     if (iv_len != 0) {
-      SECItem bogusParams(params);
+      decrypted_len = 0;
+      SECItem bogus_params(params);
       CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
-      bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
+      bogus_params.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
 
       std::vector<uint8_t> bogusIV(iv, iv + iv_len);
       bogusAeadParams.pNonce = toUcharPtr(bogusIV.data());
       bogusIV[0] ^= 0xff;
 
-      rv = PK11_Decrypt(key.get(), kMech, &bogusParams, decrypted.data(),
-                        &decryptedLen, data_len, output.data(), outputLen);
-      EXPECT_NE(rv, SECSuccess);
+      rv = PK11_Decrypt(key.get(), kMech, &bogus_params, decrypted.data(),
+                        &decrypted_len, data_len, encrypted.data(),
+                        encrypted.size());
+      EXPECT_EQ(rv, SECFailure);
+      EXPECT_EQ(0U, decrypted_len);
     }
 
     // Decrypt with bogus additional data.
     // Skip when AAD was empty and can't be modified.
     // Alternatively we could generate random aad.
     if (aad_len != 0) {
-      SECItem bogusParams(params);
-      CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
-      bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
+      decrypted_len = 0;
+      SECItem bogus_params(params);
+      CK_NSS_AEAD_PARAMS bogus_aead_params(aead_params);
+      bogus_params.data = reinterpret_cast<unsigned char*>(&bogus_aead_params);
 
-      std::vector<uint8_t> bogusAAD(aad, aad + aad_len);
-      bogusAeadParams.pAAD = toUcharPtr(bogusAAD.data());
-      bogusAAD[0] ^= 0xff;
+      std::vector<uint8_t> bogus_aad(aad, aad + aad_len);
+      bogus_aead_params.pAAD = toUcharPtr(bogus_aad.data());
+      bogus_aad[0] ^= 0xff;
 
-      rv = PK11_Decrypt(key.get(), kMech, &bogusParams, decrypted.data(),
-                        &decryptedLen, data_len, output.data(), outputLen);
-      EXPECT_NE(rv, SECSuccess);
+      rv = PK11_Decrypt(key.get(), kMech, &bogus_params, decrypted.data(),
+                        &decrypted_len, data_len, encrypted.data(),
+                        encrypted.size());
+      EXPECT_EQ(rv, SECFailure);
+      EXPECT_EQ(0U, decrypted_len);
     }
   }
 
-  void EncryptDecrypt(const chacha_testvector testvector) {
+  void EncryptDecrypt(const chaChaTestVector testvector) {
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-    SECItem key_item = {siBuffer, toUcharPtr(testvector.Key.data()),
-                        static_cast<unsigned int>(testvector.Key.size())};
+    SECItem keyItem = {siBuffer, toUcharPtr(testvector.Key.data()),
+                       static_cast<unsigned int>(testvector.Key.size())};
 
     // Import key.
     ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap,
-                                           CKA_ENCRYPT, &key_item, nullptr));
+                                           CKA_ENCRYPT, &keyItem, nullptr));
     EXPECT_TRUE(!!key);
 
     // Check.
-    EncryptDecrypt(key, testvector.invalid_iv, testvector.invalid_tag,
+    EncryptDecrypt(key, testvector.invalidIV, testvector.invalidTag,
                    testvector.Data.data(), testvector.Data.size(),
                    testvector.AAD.data(), testvector.AAD.size(),
                    testvector.IV.data(), testvector.IV.size(),
                    testvector.CT.data(), testvector.CT.size());
   }
 
  protected:
 };
 
 TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) {
   // Generate a random key.
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
   EXPECT_TRUE(!!key);
 
   // Generate random data.
-  std::vector<uint8_t> data(512);
+  std::vector<uint8_t> input(512);
   SECStatus rv =
-      PK11_GenerateRandomOnSlot(slot.get(), data.data(), data.size());
+      PK11_GenerateRandomOnSlot(slot.get(), input.data(), input.size());
   EXPECT_EQ(rv, SECSuccess);
 
   // Generate random AAD.
   std::vector<uint8_t> aad(16);
   rv = PK11_GenerateRandomOnSlot(slot.get(), aad.data(), aad.size());
   EXPECT_EQ(rv, SECSuccess);
 
   // Generate random IV.
   std::vector<uint8_t> iv(12);
   rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size());
   EXPECT_EQ(rv, SECSuccess);
 
   // Check.
-  EncryptDecrypt(key, false, false, data.data(), data.size(), aad.data(),
+  EncryptDecrypt(key, false, false, input.data(), input.size(), aad.data(),
                  aad.size(), iv.data(), iv.size());
 }
 
 TEST_F(Pkcs11ChaCha20Poly1305Test, Xor) {
   static const uint8_t kExpected[sizeof(kData)] = {
       0xd8, 0x15, 0xd3, 0xb3, 0xe9, 0x34, 0x3b, 0x7a,
       0x24, 0xf6, 0x5f, 0xd7, 0x95, 0x3d, 0xd3, 0x51};
 
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   SECItem keyItem = {siBuffer, toUcharPtr(kKeyData),
                      static_cast<unsigned int>(sizeof(kKeyData))};
   ScopedPK11SymKey key(PK11_ImportSymKey(
       slot.get(), kMechXor, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
   EXPECT_TRUE(!!key);
 
-  SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
-                            static_cast<unsigned int>(sizeof(kCtrNonce))};
-  uint8_t output[sizeof(kData)];
-  unsigned int output_len = 88;  // This should be overwritten.
+  SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
+                          static_cast<unsigned int>(sizeof(kCtrNonce))};
+  uint8_t encrypted[sizeof(kData)];
+  unsigned int encrypted_len = 88;  // This should be overwritten.
   SECStatus rv =
-      PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
-                   sizeof(output), kData, sizeof(kData));
+      PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
+                   &encrypted_len, sizeof(encrypted), kData, sizeof(kData));
   ASSERT_EQ(SECSuccess, rv);
-  ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(output_len));
-  EXPECT_EQ(0, memcmp(kExpected, output, sizeof(kExpected)));
+  ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len));
+  EXPECT_EQ(0, memcmp(kExpected, encrypted, sizeof(kExpected)));
 
   // Decrypting has the same effect.
-  rv = PK11_Decrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
-                    sizeof(output), kData, sizeof(kData));
+  rv = PK11_Decrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
+                    &encrypted_len, sizeof(encrypted), kData, sizeof(kData));
   ASSERT_EQ(SECSuccess, rv);
-  ASSERT_EQ(sizeof(kData), static_cast<size_t>(output_len));
-  EXPECT_EQ(0, memcmp(kExpected, output, sizeof(kExpected)));
+  ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len));
+  EXPECT_EQ(0, memcmp(kExpected, encrypted, sizeof(kExpected)));
 
   // Operating in reverse too.
-  rv = PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
-                    sizeof(output), kExpected, sizeof(kExpected));
+  rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
+                    &encrypted_len, sizeof(encrypted), kExpected,
+                    sizeof(kExpected));
   ASSERT_EQ(SECSuccess, rv);
-  ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(output_len));
-  EXPECT_EQ(0, memcmp(kData, output, sizeof(kData)));
+  ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len));
+  EXPECT_EQ(0, memcmp(kData, encrypted, sizeof(kData)));
 }
 
 // This test just ensures that a key can be generated for use with the XOR
 // function.  The result is random and therefore cannot be checked.
 TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) {
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
   EXPECT_TRUE(!!key);
 
-  SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
-                            static_cast<unsigned int>(sizeof(kCtrNonce))};
-  uint8_t output[sizeof(kData)];
-  unsigned int output_len = 88;  // This should be overwritten.
+  SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
+                          static_cast<unsigned int>(sizeof(kCtrNonce))};
+  uint8_t encrypted[sizeof(kData)];
+  unsigned int encrypted_len = 88;  // This should be overwritten.
   SECStatus rv =
-      PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
-                   sizeof(output), kData, sizeof(kData));
+      PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
+                   &encrypted_len, sizeof(encrypted), kData, sizeof(kData));
   ASSERT_EQ(SECSuccess, rv);
-  ASSERT_EQ(sizeof(kData), static_cast<size_t>(output_len));
+  ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len));
 }
 
 TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) {
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
   EXPECT_TRUE(!!key);
 
-  SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
-                            static_cast<unsigned int>(sizeof(kCtrNonce)) - 1};
-  uint8_t output[sizeof(kData)];
-  unsigned int output_len = 88;
+  SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
+                          static_cast<unsigned int>(sizeof(kCtrNonce)) - 1};
+  uint8_t encrypted[sizeof(kData)];
+  unsigned int encrypted_len = 88;
   SECStatus rv =
-      PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
-                   sizeof(output), kData, sizeof(kData));
+      PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
+                   &encrypted_len, sizeof(encrypted), kData, sizeof(kData));
   EXPECT_EQ(SECFailure, rv);
 
-  ctr_nonce_item.data = nullptr;
-  rv = PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
-                    sizeof(output), kData, sizeof(kData));
+  ctrNonceItem.data = nullptr;
+  rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
+                    &encrypted_len, sizeof(encrypted), kData, sizeof(kData));
   EXPECT_EQ(SECFailure, rv);
   EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
 }
 
 TEST_P(Pkcs11ChaCha20Poly1305Test, TestVectors) { EncryptDecrypt(GetParam()); }
 
 INSTANTIATE_TEST_CASE_P(NSSTestVector, Pkcs11ChaCha20Poly1305Test,
                         ::testing::ValuesIn(kChaCha20Vectors));
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -8,16 +8,17 @@
   ],
   'targets': [
     {
       'target_name': 'pk11_gtest',
       'type': 'executable',
       'sources': [
         'pk11_aeskeywrap_unittest.cc',
         'pk11_aes_gcm_unittest.cc',
+        'pk11_cbc_unittest.cc',
         'pk11_chacha20poly1305_unittest.cc',
         'pk11_cipherop_unittest.cc',
         'pk11_curve25519_unittest.cc',
         'pk11_ecdsa_unittest.cc',
         'pk11_encrypt_derive_unittest.cc',
         'pk11_import_unittest.cc',
         'pk11_pbkdf2_unittest.cc',
         'pk11_prf_unittest.cc',
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -104,19 +104,20 @@ void SSLInt_PrintCipherSpecs(const char 
   for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs);
        cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) {
     ssl3CipherSpec *spec = (ssl3CipherSpec *)cur_p;
     fprintf(stderr, "  %s spec epoch=%d (%s) refct=%d\n", SPEC_DIR(spec),
             spec->epoch, spec->phase, spec->refCt);
   }
 }
 
-/* Force a timer expiry by backdating when all active timers were started. We
- * could set the remaining time to 0 but then backoff would not work properly if
- * we decide to test it. */
+/* DTLS timers are separate from the time that the rest of the stack uses.
+ * Force a timer expiry by backdating when all active timers were started.
+ * We could set the remaining time to 0 but then backoff would not work properly
+ * if we decide to test it. */
 SECStatus SSLInt_ShiftDtlsTimers(PRFileDesc *fd, PRIntervalTime shift) {
   size_t i;
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return SECFailure;
   }
 
   for (i = 0; i < PR_ARRAY_SIZE(ss->ssl3.hs.timers); ++i) {
@@ -292,20 +293,16 @@ SECStatus SSLInt_AdvanceWriteSeqByAWindo
 
 SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
   const sslNamedGroupDef *groupDef = ssl_LookupNamedGroup(group);
   if (!groupDef) return ssl_kea_null;
 
   return groupDef->keaType;
 }
 
-void SSLInt_SetTicketLifetime(uint32_t lifetime) {
-  ssl_ticket_lifetime = lifetime;
-}
-
 SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
   sslSocket *ss;
 
   ss = ssl_FindSocket(fd);
   if (!ss) {
     return SECFailure;
   }
 
@@ -319,20 +316,16 @@ SECStatus SSLInt_SetSocketMaxEarlyDataSi
   ssl_GetSpecWriteLock(ss);
   ss->ssl3.crSpec->earlyDataRemaining = size;
   ss->ssl3.cwSpec->earlyDataRemaining = size;
   ssl_ReleaseSpecWriteLock(ss);
 
   return SECSuccess;
 }
 
-void SSLInt_RolloverAntiReplay(void) {
-  tls13_AntiReplayRollover(ssl_TimeUsec());
-}
-
 SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return SECFailure;
   }
 
   ssl_GetSSL3HandshakeLock(ss);
   *pending = ss->ssl3.hs.msg_body.len > 0;
--- a/security/nss/gtests/ssl_gtest/libssl_internals.h
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.h
@@ -35,13 +35,11 @@ PRBool SSLInt_DamageEarlyTrafficSecret(P
 SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len);
 PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType);
 PRBool SSLInt_SendAlert(PRFileDesc *fd, uint8_t level, uint8_t type);
 SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to);
 SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
 SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
 SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group);
 SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
-void SSLInt_SetTicketLifetime(uint32_t lifetime);
 SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
-void SSLInt_RolloverAntiReplay(void);
 
 #endif  // ndef libssl_internals_h_
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -41,17 +41,17 @@ TEST_P(TlsConnectTls13, ZeroRttServerRej
   ExpectResumption(RESUME_TICKET);
   ZeroRttSendReceive(true, false);
   Handshake();
   CheckConnected();
   SendReceive();
 }
 
 TEST_P(TlsConnectTls13, ZeroRttApparentReplayAfterRestart) {
-  // The test fixtures call SSL_SetupAntiReplay() in SetUp().  This results in
+  // The test fixtures call SSL_InitAntiReplay() in SetUp().  This results in
   // 0-RTT being rejected until at least one window passes.  SetupFor0Rtt()
   // forces a rollover of the anti-replay filters, which clears this state.
   // Here, we do the setup manually here without that forced rollover.
 
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   server_->Set0RttEnabled(true);  // So we signal that we allow 0-RTT.
   Connect();
@@ -101,17 +101,17 @@ class TlsZeroRttReplayTest : public TlsC
     ZeroRttSendReceive(true, true);
     Handshake();
     EXPECT_LT(0U, first_packet->packet().len());
     ExpectEarlyDataAccepted(true);
     CheckConnected();
     SendReceive();
 
     if (rollover) {
-      SSLInt_RolloverAntiReplay();
+      RolloverAntiReplay();
     }
 
     // Now replay that packet against the server.
     Reset();
     server_->StartConnect();
     server_->Set0RttEnabled(true);
 
     // Capture the early_data extension, which should not appear.
@@ -179,62 +179,62 @@ TEST_P(TlsConnectTls13, ZeroRttServerOnl
 
   // Now make sure that things complete.
   Handshake();
   CheckConnected();
   SendReceive();
   CheckKeys();
 }
 
-// A small sleep after sending the ClientHello means that the ticket age that
-// arrives at the server is too low.  With a small tolerance for variation in
-// ticket age (which is determined by the |window| parameter that is passed to
-// SSL_SetupAntiReplay()), the server then rejects early data.
+// Advancing time after sending the ClientHello means that the ticket age that
+// arrives at the server is too low.  The server then rejects early data if this
+// delay exceeds half the anti-replay window.
 TEST_P(TlsConnectTls13, ZeroRttRejectOldTicket) {
+  static const PRTime kWindow = 10 * PR_USEC_PER_SEC;
+  EXPECT_EQ(SECSuccess, SSL_InitAntiReplay(now(), kWindow, 1, 3));
   SetupForZeroRtt();
+
+  Reset();
+  StartConnect();
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
-  EXPECT_EQ(SECSuccess, SSL_SetupAntiReplay(1, 1, 3));
-  SSLInt_RolloverAntiReplay();  // Make sure to flush replay state.
-  SSLInt_RolloverAntiReplay();
   ExpectResumption(RESUME_TICKET);
-  ZeroRttSendReceive(true, false, []() {
-    PR_Sleep(PR_MillisecondsToInterval(10));
+  ZeroRttSendReceive(true, false, [this]() {
+    AdvanceTime(1 + kWindow / 2);
     return true;
   });
   Handshake();
   ExpectEarlyDataAccepted(false);
   CheckConnected();
   SendReceive();
 }
 
 // In this test, we falsely inflate the estimate of the RTT by delaying the
 // ServerHello on the first handshake.  This results in the server estimating a
 // higher value of the ticket age than the client ultimately provides.  Add a
 // small tolerance for variation in ticket age and the ticket will appear to
 // arrive prematurely, causing the server to reject early data.
 TEST_P(TlsConnectTls13, ZeroRttRejectPrematureTicket) {
+  static const PRTime kWindow = 10 * PR_USEC_PER_SEC;
+  EXPECT_EQ(SECSuccess, SSL_InitAntiReplay(now(), kWindow, 1, 3));
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   server_->Set0RttEnabled(true);
   StartConnect();
   client_->Handshake();  // ClientHello
   server_->Handshake();  // ServerHello
-  PR_Sleep(PR_MillisecondsToInterval(10));
+  AdvanceTime(1 + kWindow / 2);
   Handshake();  // Remainder of handshake
   CheckConnected();
   SendReceive();
   CheckKeys();
 
   Reset();
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
-  EXPECT_EQ(SECSuccess, SSL_SetupAntiReplay(1, 1, 3));
-  SSLInt_RolloverAntiReplay();  // Make sure to flush replay state.
-  SSLInt_RolloverAntiReplay();
   ExpectResumption(RESUME_TICKET);
   ExpectEarlyDataAccepted(false);
   StartConnect();
   ZeroRttSendReceive(true, false);
   Handshake();
   CheckConnected();
   SendReceive();
 }
@@ -865,14 +865,67 @@ TEST_F(TlsConnectDatagram13, ZeroRttShor
   EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
   EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data)));
 
   Handshake();  // Complete the handshake.
   ExpectEarlyDataAccepted(true);
   CheckConnected();
 }
 
+// There are few ways in which TLS uses the clock and most of those operate on
+// timescales that would be ridiculous to wait for in a test.  This is the one
+// test we have that uses the real clock.  It tests that time passes by checking
+// that a small sleep results in rejection of early data. 0-RTT has a
+// configurable timer, which makes it ideal for this.
+TEST_F(TlsConnectStreamTls13, TimePassesByDefault) {
+  // Set a tiny anti-replay window.  This has to be at least 2 milliseconds to
+  // have any chance of being relevant as that is the smallest window that we
+  // can detect.  Anything smaller rounds to zero.
+  static const unsigned int kTinyWindowMs = 5;
+  EXPECT_EQ(SECSuccess, SSL_InitAntiReplay(
+                            PR_Now(), kTinyWindowMs * PR_USEC_PER_MSEC, 1, 5));
+
+  // Calling EnsureTlsSetup() replaces the time function on client and server,
+  // which we don't want, so initialize each directly.
+  client_->EnsureTlsSetup();
+  server_->EnsureTlsSetup();
+  client_->StartConnect();  // Also avoid StartConnect().
+  server_->StartConnect();
+
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->Set0RttEnabled(true);
+  Handshake();
+  CheckConnected();
+  SendReceive();  // Absorb a session ticket.
+  CheckKeys();
+
+  // Clear the first window.
+  PR_Sleep(PR_MillisecondsToInterval(kTinyWindowMs));
+
+  Reset();
+  client_->EnsureTlsSetup();
+  server_->EnsureTlsSetup();
+  client_->StartConnect();
+  server_->StartConnect();
+
+  // Early data is rejected by the server only if time passes for it as well.
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true, false, []() {
+    // Sleep long enough that we minimize the risk of our RTT estimation being
+    // duped by stutters in test execution.  This is very long to allow for
+    // flaky and low-end hardware, especially what our CI runs on.
+    PR_Sleep(PR_MillisecondsToInterval(1000));
+    return true;
+  });
+  Handshake();
+  ExpectEarlyDataAccepted(false);
+  CheckConnected();
+}
+
 #ifndef NSS_DISABLE_TLS_1_3
 INSTANTIATE_TEST_CASE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest,
                         TlsConnectTestBase::kTlsVariantsAll);
 #endif
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -17,17 +17,17 @@ namespace nss_test {
 #else
 #define FUZZ_F(c, f) TEST_F(c, DISABLED_Fuzz_##f)
 #define FUZZ_P(c, f) TEST_P(c, DISABLED_Fuzz_##f)
 #endif
 
 const uint8_t kShortEmptyFinished[8] = {0};
 const uint8_t kLongEmptyFinished[128] = {0};
 
-class TlsFuzzTest : public ::testing::Test {};
+class TlsFuzzTest : public TlsConnectGeneric {};
 
 // Record the application data stream.
 class TlsApplicationDataRecorder : public TlsRecordFilter {
  public:
   TlsApplicationDataRecorder(const std::shared_ptr<TlsAgent>& a)
       : TlsRecordFilter(a), buffer_() {}
 
   virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
@@ -41,26 +41,19 @@ class TlsApplicationDataRecorder : publi
   }
 
   const DataBuffer& buffer() const { return buffer_; }
 
  private:
   DataBuffer buffer_;
 };
 
-// Ensure that ssl_Time() returns a constant value.
-FUZZ_F(TlsFuzzTest, SSL_Time_Constant) {
-  PRUint32 now = ssl_TimeSec();
-  PR_Sleep(PR_SecondsToInterval(2));
-  EXPECT_EQ(ssl_TimeSec(), now);
-}
-
 // Check that due to the deterministic PRNG we derive
 // the same master secret in two consecutive TLS sessions.
-FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
+FUZZ_P(TlsFuzzTest, DeterministicExporter) {
   const char kLabel[] = "label";
   std::vector<unsigned char> out1(32), out2(32);
 
   // Make sure we have RSA blinding params.
   Connect();
 
   Reset();
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
@@ -90,17 +83,17 @@ FUZZ_P(TlsConnectGeneric, DeterministicE
   EXPECT_EQ(SECSuccess, rv);
 
   // The two exported keys should be the same.
   EXPECT_EQ(out1, out2);
 }
 
 // Check that due to the deterministic RNG two consecutive
 // TLS sessions will have the exact same transcript.
-FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
+FUZZ_P(TlsFuzzTest, DeterministicTranscript) {
   // Make sure we have RSA blinding params.
   Connect();
 
   // Connect a few times and compare the transcripts byte-by-byte.
   DataBuffer last;
   for (size_t i = 0; i < 5; i++) {
     Reset();
     ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
@@ -125,19 +118,17 @@ FUZZ_P(TlsConnectGeneric, DeterministicT
     last = buffer;
   }
 }
 
 // Check that we can establish and use a connection
 // with all supported TLS versions, STREAM and DGRAM.
 // Check that records are NOT encrypted.
 // Check that records don't have a MAC.
-FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
-  EnsureTlsSetup();
-
+FUZZ_P(TlsFuzzTest, ConnectSendReceive_NullCipher) {
   // Set up app data filters.
   auto client_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(client_);
   auto server_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(server_);
 
   Connect();
 
   // Construct the plaintext.
   DataBuffer buf;
@@ -152,91 +143,113 @@ FUZZ_P(TlsConnectGeneric, ConnectSendRec
   Receive(buf.len());
 
   // Check for plaintext on the wire.
   EXPECT_EQ(buf, client_recorder->buffer());
   EXPECT_EQ(buf, server_recorder->buffer());
 }
 
 // Check that an invalid Finished message doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
+FUZZ_P(TlsFuzzTest, BogusClientFinished) {
   EnsureTlsSetup();
 
   MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
       client_, kTlsHandshakeFinished,
       DataBuffer(kShortEmptyFinished, sizeof(kShortEmptyFinished)));
   Connect();
   SendReceive();
 }
 
 // Check that an invalid Finished message doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
+FUZZ_P(TlsFuzzTest, BogusServerFinished) {
   EnsureTlsSetup();
 
   MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
       server_, kTlsHandshakeFinished,
       DataBuffer(kLongEmptyFinished, sizeof(kLongEmptyFinished)));
   Connect();
   SendReceive();
 }
 
 // Check that an invalid server auth signature doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
+FUZZ_P(TlsFuzzTest, BogusServerAuthSignature) {
   EnsureTlsSetup();
   uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
                          ? kTlsHandshakeCertificateVerify
                          : kTlsHandshakeServerKeyExchange;
   MakeTlsFilter<TlsLastByteDamager>(server_, msg_type);
   Connect();
   SendReceive();
 }
 
 // Check that an invalid client auth signature doesn't abort the connection.
-FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
+FUZZ_P(TlsFuzzTest, BogusClientAuthSignature) {
   EnsureTlsSetup();
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   MakeTlsFilter<TlsLastByteDamager>(client_, kTlsHandshakeCertificateVerify);
   Connect();
 }
 
 // Check that session ticket resumption works.
-FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
+FUZZ_P(TlsFuzzTest, SessionTicketResumption) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
   SendReceive();
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ExpectResumption(RESUME_TICKET);
   Connect();
   SendReceive();
 }
 
 // Check that session tickets are not encrypted.
-FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
+FUZZ_P(TlsFuzzTest, UnencryptedSessionTickets) {
   ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
 
   auto filter = MakeTlsFilter<TlsHandshakeRecorder>(
       server_, kTlsHandshakeNewSessionTicket);
   Connect();
 
   std::cerr << "ticket" << filter->buffer() << std::endl;
-  size_t offset = 4; /* lifetime */
+  size_t offset = 4;  // Skip lifetime.
+
   if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
-    offset += 4; /* ticket_age_add */
+    offset += 4;  // Skip ticket_age_add.
     uint32_t nonce_len = 0;
     EXPECT_TRUE(filter->buffer().Read(offset, 1, &nonce_len));
     offset += 1 + nonce_len;
   }
-  offset += 2 + /* ticket length */
-            2;  /* TLS_EX_SESS_TICKET_VERSION */
+
+  offset += 2;  // Skip the ticket length.
+
+  // This bit parses the contents of the ticket, which would ordinarily be
+  // encrypted.  Start by checking that we have the right version.  This needs
+  // to be updated every time that TLS_EX_SESS_TICKET_VERSION is changed.  But
+  // we don't use the #define.  That way, any time that code is updated, this
+  // test will fail unless it is manually checked.
+  uint32_t ticket_version;
+  EXPECT_TRUE(filter->buffer().Read(offset, 2, &ticket_version));
+  EXPECT_EQ(0x010aU, ticket_version);
+  offset += 2;
+
   // Check the protocol version number.
   uint32_t tls_version = 0;
   EXPECT_TRUE(filter->buffer().Read(offset, sizeof(version_), &tls_version));
   EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));
+  offset += sizeof(version_);
 
   // Check the cipher suite.
   uint32_t suite = 0;
-  EXPECT_TRUE(filter->buffer().Read(offset + sizeof(version_), 2, &suite));
+  EXPECT_TRUE(filter->buffer().Read(offset, 2, &suite));
   client_->CheckCipherSuite(static_cast<uint16_t>(suite));
 }
+
+INSTANTIATE_TEST_CASE_P(
+    FuzzStream, TlsFuzzTest,
+    ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+                       TlsConnectTestBase::kTlsVAll));
+INSTANTIATE_TEST_CASE_P(
+    FuzzDatagram, TlsFuzzTest,
+    ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+                       TlsConnectTestBase::kTlsV11Plus));
 }
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -320,24 +320,27 @@ TEST_P(TlsConnectGeneric, ConnectResumeC
   Reset();
   ClearServerCache();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ExpectResumption(RESUME_NONE);
   Connect();
   SendReceive();
 }
 
+// Tickets last two days maximum; this is a time longer than that.
+static const PRTime kLongerThanTicketLifetime =
+    3LL * 24 * 60 * 60 * PR_USEC_PER_SEC;
+
 TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
-  SSLInt_SetTicketLifetime(1);  // one second
   // This causes a ticket resumption.
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
   SendReceive();
 
-  WAIT_(false, 1000);
+  AdvanceTime(kLongerThanTicketLifetime);
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ExpectResumption(RESUME_NONE);
 
   // TLS 1.3 uses the pre-shared key extension instead.
   SSLExtensionType xtn = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
                              ? ssl_tls13_pre_shared_key_xtn
@@ -349,17 +352,16 @@ TEST_P(TlsConnectGenericResumption, Conn
     EXPECT_FALSE(capture->captured());
   } else {
     EXPECT_TRUE(capture->captured());
     EXPECT_EQ(0U, capture->extension().len());
   }
 }
 
 TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
-  SSLInt_SetTicketLifetime(1);  // one second
   // This causes a ticket resumption.
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
   SendReceive();
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ExpectResumption(RESUME_NONE);
@@ -368,17 +370,17 @@ TEST_P(TlsConnectGeneric, ConnectWithExp
                              ? ssl_tls13_pre_shared_key_xtn
                              : ssl_session_ticket_xtn;
   auto capture = MakeTlsFilter<TlsExtensionCapture>(client_, xtn);
   StartConnect();
   client_->Handshake();
   EXPECT_TRUE(capture->captured());
   EXPECT_LT(0U, capture->extension().len());
 
-  WAIT_(false, 1000);  // Let the ticket expire on the server.
+  AdvanceTime(kLongerThanTicketLifetime);
 
   Handshake();
   CheckConnected();
 }
 
 TEST_P(TlsConnectGeneric, ConnectResumeCorruptTicket) {
   // This causes a ticket resumption.
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@@ -1104,33 +1106,33 @@ TEST_P(TlsConnectGenericResumption, ReCo
   ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
   ExpectResumption(RESUME_TICKET, 2);
   Connect();
   // Only the client knows this.
   CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
                       ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
 }
 
-void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
+void CheckGetInfoResult(PRTime now, uint32_t alpnSize, uint32_t earlyDataSize,
                         ScopedCERTCertificate& cert,
                         ScopedSSLResumptionTokenInfo& token) {
   ASSERT_TRUE(cert);
   ASSERT_TRUE(token->peerCert);
 
   // Check that the server cert is the correct one.
   ASSERT_EQ(cert->derCert.len, token->peerCert->derCert.len);
   EXPECT_EQ(0, memcmp(cert->derCert.data, token->peerCert->derCert.data,
                       cert->derCert.len));
 
   ASSERT_EQ(alpnSize, token->alpnSelectionLen);
   EXPECT_EQ(0, memcmp("a", token->alpnSelection, token->alpnSelectionLen));
 
   ASSERT_EQ(earlyDataSize, token->maxEarlyDataSize);
 
-  ASSERT_LT(ssl_TimeUsec(), token->expirationTime);
+  ASSERT_LT(now, token->expirationTime);
 }
 
 // The client should generate a new, randomized session_id
 // when resuming using an external token.
 TEST_P(TlsConnectGenericResumptionToken, CheckSessionId) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
   auto original_sid = MakeTlsFilter<CaptureSessionId>(client_);
   Connect();
@@ -1170,24 +1172,74 @@ TEST_P(TlsConnectGenericResumptionToken,
 
   // Get resumption token infos
   SSLResumptionTokenInfo tokenInfo = {0};
   ScopedSSLResumptionTokenInfo token(&tokenInfo);
   client_->GetTokenInfo(token);
   ScopedCERTCertificate cert(
       PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
 
-  CheckGetInfoResult(0, 0, cert, token);
+  CheckGetInfoResult(now(), 0, 0, cert, token);
 
   Handshake();
   CheckConnected();
 
   SendReceive();
 }
 
+TEST_P(TlsConnectGenericResumptionToken, RefuseExpiredTicketClient) {
+  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+  Connect();
+  SendReceive();
+
+  // Move the clock to the expiration time of the ticket.
+  SSLResumptionTokenInfo tokenInfo = {0};
+  ScopedSSLResumptionTokenInfo token(&tokenInfo);
+  client_->GetTokenInfo(token);
+  AdvanceTime(token->expirationTime - now());
+
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+  ExpectResumption(RESUME_TICKET);
+
+  StartConnect();
+  ASSERT_EQ(SECFailure,
+            SSL_SetResumptionToken(client_->ssl_fd(),
+                                   client_->GetResumptionToken().data(),
+                                   client_->GetResumptionToken().size()));
+  EXPECT_EQ(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, PORT_GetError());
+}
+
+TEST_P(TlsConnectGenericResumptionToken, RefuseExpiredTicketServer) {
+  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+  Connect();
+  SendReceive();
+
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+  ExpectResumption(RESUME_NONE);
+
+  // Start the handshake and send the ClientHello.
+  StartConnect();
+  ASSERT_EQ(SECSuccess,
+            SSL_SetResumptionToken(client_->ssl_fd(),
+                                   client_->GetResumptionToken().data(),
+                                   client_->GetResumptionToken().size()));
+  client_->Handshake();
+
+  // Move the clock to the expiration time of the ticket.
+  SSLResumptionTokenInfo tokenInfo = {0};
+  ScopedSSLResumptionTokenInfo token(&tokenInfo);
+  client_->GetTokenInfo(token);
+  AdvanceTime(token->expirationTime - now());
+
+  Handshake();
+  CheckConnected();
+}
+
 TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
   EnableAlpn();
   ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
   Connect();
   CheckAlpn("a");
   SendReceive();
 
   Reset();
@@ -1200,28 +1252,28 @@ TEST_P(TlsConnectGenericResumptionToken,
 
   // Get resumption token infos
   SSLResumptionTokenInfo tokenInfo = {0};
   ScopedSSLResumptionTokenInfo token(&tokenInfo);
   client_->GetTokenInfo(token);
   ScopedCERTCertificate cert(
       PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
 
-  CheckGetInfoResult(1, 0, cert, token);
+  CheckGetInfoResult(now(), 1, 0, cert, token);
 
   Handshake();
   CheckConnected();
   CheckAlpn("a");
 
   SendReceive();
 }
 
 TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
   EnableAlpn();
-  SSLInt_RolloverAntiReplay();
+  RolloverAntiReplay();
   ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
   server_->Set0RttEnabled(true);
   Connect();
   CheckAlpn("a");
   SendReceive();
 
   Reset();
   EnableAlpn();
@@ -1235,17 +1287,17 @@ TEST_P(TlsConnectTls13ResumptionToken, C
 
   // Get resumption token infos
   SSLResumptionTokenInfo tokenInfo = {0};
   ScopedSSLResumptionTokenInfo token(&tokenInfo);
   client_->GetTokenInfo(token);
   ScopedCERTCertificate cert(
       PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
 
-  CheckGetInfoResult(1, 1024, cert, token);
+  CheckGetInfoResult(now(), 1, 1024, cert, token);
 
   ZeroRttSendReceive(true, true);
   Handshake();
   ExpectEarlyDataAccepted(true);
   CheckConnected();
   CheckAlpn("a");
 
   SendReceive();
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -101,16 +101,20 @@ std::string VersionString(uint16_t versi
       return "1.3";
     default:
       std::cerr << "Invalid version: " << version << std::endl;
       EXPECT_TRUE(false);
       return "";
   }
 }
 
+// The default anti-replay window for tests.  Tests that rely on a different
+// value call SSL_InitAntiReplay directly.
+static PRTime kAntiReplayWindow = 100 * PR_USEC_PER_SEC;
+
 TlsConnectTestBase::TlsConnectTestBase(SSLProtocolVariant variant,
                                        uint16_t version)
     : variant_(variant),
       client_(new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, variant_)),
       server_(new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, variant_)),
       client_model_(nullptr),
       server_model_(nullptr),
       version_(version),
@@ -198,21 +202,25 @@ void TlsConnectTestBase::RestoreAlgorith
     auto algorithm = std::get<0>(*it);
     auto policy = std::get<1>(*it);
     SECStatus rv = NSS_SetAlgorithmPolicy(
         algorithm, policy, NSS_USE_POLICY_IN_SSL | NSS_USE_ALG_IN_SSL_KX);
     ASSERT_EQ(SECSuccess, rv);
   }
 }
 
+PRTime TlsConnectTestBase::TimeFunc(void* arg) {
+  return *reinterpret_cast<PRTime*>(arg);
+}
+
 void TlsConnectTestBase::SetUp() {
   SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
   SSLInt_ClearSelfEncryptKey();
-  SSLInt_SetTicketLifetime(30);
-  SSL_SetupAntiReplay(1 * PR_USEC_PER_SEC, 1, 3);
+  now_ = PR_Now();
+  SSL_InitAntiReplay(now_, kAntiReplayWindow, 1, 3);
   ClearStats();
   SaveAlgorithmPolicy();
   Init();
 }
 
 void TlsConnectTestBase::TearDown() {
   client_ = nullptr;
   server_ = nullptr;
@@ -277,46 +285,49 @@ void TlsConnectTestBase::ExpectResumptio
   EXPECT_EQ(expected_resumptions_ == 0, expected == RESUME_NONE);
 }
 
 void TlsConnectTestBase::EnsureTlsSetup() {
   EXPECT_TRUE(server_->EnsureTlsSetup(server_model_ ? server_model_->ssl_fd()
                                                     : nullptr));
   EXPECT_TRUE(client_->EnsureTlsSetup(client_model_ ? client_model_->ssl_fd()
                                                     : nullptr));
+  EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(client_->ssl_fd(),
+                                        TlsConnectTestBase::TimeFunc, &now_));
+  EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(server_->ssl_fd(),
+                                        TlsConnectTestBase::TimeFunc, &now_));
 }
 
 void TlsConnectTestBase::Handshake() {
-  EnsureTlsSetup();
   client_->SetServerKeyBits(server_->server_key_bits());
   client_->Handshake();
   server_->Handshake();
 
   ASSERT_TRUE_WAIT((client_->state() != TlsAgent::STATE_CONNECTING) &&
                        (server_->state() != TlsAgent::STATE_CONNECTING),
                    5000);
 }
 
 void TlsConnectTestBase::EnableExtendedMasterSecret() {
   client_->EnableExtendedMasterSecret();
   server_->EnableExtendedMasterSecret();
   ExpectExtendedMasterSecret(true);
 }
 
 void TlsConnectTestBase::Connect() {
-  server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
-  client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
+  StartConnect();
   client_->MaybeSetResumptionToken();
   Handshake();
   CheckConnected();
 }
 
 void TlsConnectTestBase::StartConnect() {
-  server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
-  client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
+  EnsureTlsSetup();
+  server_->StartConnect();
+  client_->StartConnect();
 }
 
 void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite) {
   EnsureTlsSetup();
   client_->EnableSingleCipher(cipher_suite);
 
   Connect();
   SendReceive();
@@ -674,18 +685,19 @@ void TlsConnectTestBase::SendReceive(siz
   ASSERT_GT(total, server_->received_bytes());
   client_->SendData(total - server_->received_bytes());
   server_->SendData(total - client_->received_bytes());
   Receive(total);  // Receive() is cumulative
 }
 
 // Do a first connection so we can do 0-RTT on the second one.
 void TlsConnectTestBase::SetupForZeroRtt() {
+  // Force rollover of the anti-replay window.
   // If we don't do this, then all 0-RTT attempts will be rejected.
-  SSLInt_RolloverAntiReplay();
+  RolloverAntiReplay();
 
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   server_->Set0RttEnabled(true);  // So we signal that we allow 0-RTT.
   Connect();
   SendReceive();  // Need to read so that we absorb the session ticket.
   CheckKeys();
 
@@ -787,22 +799,30 @@ void TlsConnectTestBase::ShiftDtlsTimers
     time_shift = time;
   }
   rv = DTLS_GetHandshakeTimeout(server_->ssl_fd(), &time);
   if (rv == SECSuccess &&
       (time < time_shift || time_shift == PR_INTERVAL_NO_TIMEOUT)) {
     time_shift = time;
   }
 
-  if (time_shift == PR_INTERVAL_NO_TIMEOUT) {
-    return;
+  if (time_shift != PR_INTERVAL_NO_TIMEOUT) {
+    AdvanceTime(PR_IntervalToMicroseconds(time_shift));
+    EXPECT_EQ(SECSuccess,
+              SSLInt_ShiftDtlsTimers(client_->ssl_fd(), time_shift));
+    EXPECT_EQ(SECSuccess,
+              SSLInt_ShiftDtlsTimers(server_->ssl_fd(), time_shift));
   }
+}
 
-  EXPECT_EQ(SECSuccess, SSLInt_ShiftDtlsTimers(client_->ssl_fd(), time_shift));
-  EXPECT_EQ(SECSuccess, SSLInt_ShiftDtlsTimers(server_->ssl_fd(), time_shift));
+void TlsConnectTestBase::AdvanceTime(PRTime time_shift) { now_ += time_shift; }
+
+// Advance time by a full anti-replay window.
+void TlsConnectTestBase::RolloverAntiReplay() {
+  AdvanceTime(kAntiReplayWindow);
 }
 
 TlsConnectGeneric::TlsConnectGeneric()
     : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
 TlsConnectPre12::TlsConnectPre12()
     : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -43,16 +43,18 @@ class TlsConnectTestBase : public ::test
   static ::testing::internal::ParamGenerator<uint16_t> kTlsVAll;
 
   TlsConnectTestBase(SSLProtocolVariant variant, uint16_t version);
   virtual ~TlsConnectTestBase();
 
   virtual void SetUp();
   virtual void TearDown();
 
+  PRTime now() const { return now_; }
+
   // Initialize client and server.
   void Init();
   // Clear the statistics.
   void ClearStats();
   // Clear the server session cache.
   void ClearServerCache();
   // Make sure TLS is configured for a connection.
   virtual void EnsureTlsSetup();
@@ -126,16 +128,18 @@ class TlsConnectTestBase : public ::test
   void Receive(size_t amount);
   void ExpectExtendedMasterSecret(bool expected);
   void ExpectEarlyDataAccepted(bool expected);
   void DisableECDHEServerKeyReuse();
   void SkipVersionChecks();
 
   // Move the DTLS timers for both endpoints to pop the next timer.
   void ShiftDtlsTimers();
+  void AdvanceTime(PRTime time_shift);
+  void RolloverAntiReplay();
 
   void SaveAlgorithmPolicy();
   void RestoreAlgorithmPolicy();
 
  protected:
   SSLProtocolVariant variant_;
   std::shared_ptr<TlsAgent> client_;
   std::shared_ptr<TlsAgent> server_;
@@ -159,20 +163,22 @@ class TlsConnectTestBase : public ::test
                                               SEC_OID_ANSIX9_DSA_SIGNATURE,
                                               SEC_OID_CURVE25519};
   std::vector<std::tuple<SECOidTag, uint32_t>> saved_policies_;
 
  private:
   void CheckResumption(SessionResumptionMode expected);
   void CheckExtendedMasterSecret();
   void CheckEarlyDataAccepted();
+  static PRTime TimeFunc(void* arg);
 
   bool expect_extended_master_secret_;
   bool expect_early_data_accepted_;
   bool skip_version_checks_;
+  PRTime now_;
 
   // Track groups and make sure that there are no duplicates.
   class DuplicateGroupChecker {
    public:
     void AddAndCheckGroup(SSLNamedGroup group) {
       EXPECT_EQ(groups_.end(), groups_.find(group))
           << "Group " << group << " should not be duplicated";
       groups_.insert(group);
--- a/security/nss/help.txt
+++ b/security/nss/help.txt
@@ -1,14 +1,14 @@
 Usage: build.sh [-h] [-c|-cc] [-v] [-j <n>] [--gyp|-g] [--opt|-o]
                 [-t <x64|x86|...>|--target=<x64|x86|...>]
                 [--clang|--gcc|--msvc] [--scan-build[=dir]] [--disable-tests]
                 [--pprof] [--asan] [--msan] [--ubsan[=bool,shift,...]
                 [--fuzz[=tls|oss]] [--sancov[=edge|bb|func|...]]
-                [--emit-llvm] [--no-zdefs] [--test] [--ct-verif]
+                [--emit-llvm] [--no-zdefs] [--static] [--ct-verif]
                 [--nspr|--with-nspr=<include>:<lib>|--system-nspr]
                 [--system-sqlite] [--enable-fips] [--enable-libpkix]
                 [--mozpkix-only] [-D<gyp-option>]
 
 This script builds NSS with gyp and ninja.
 
 NSS build tool options:
 
@@ -26,25 +26,24 @@ NSS build tool options:
     --scan-build     run the build with scan-build
                      --scan-build=<dir> sets the output path for scan-build
     --disable-tests  don't build tests and corresponding cmdline utils
     --pprof          build with gperftool support
     --asan           enable address sanitizer
     --msan           enable memory sanitizer
     --ubsan          enable undefined behavior sanitizer
                      --ubsan=bool,shift,... sets specific UB sanitizers
-    --fuzz           build fuzzing targets (this always enables test builds)
+    --fuzz           build fuzzing targets (this always enables static builds)
                      --fuzz=tls to enable TLS fuzzing mode
                      --fuzz=oss to build for OSS-Fuzz
     --sancov         do sanitize coverage builds
                      --sancov=func sets coverage to function level for example
     --emit-llvm      emit LLVM bitcode while building
                      (requires the gold linker, use clang-3.8 for SAW)
     --no-zdefs       don't set -Wl,-z,defs
-    --test           ignore map files and export everything we have
     --static         create static libraries and use static linking
     --ct-verif       build with valgrind for ct-verif
     --nspr           force a rebuild of NSPR
     --with-nspr      use the NSPR build at the given locations
                      --with-nspr=<include>:<lib> sets include and lib paths
     --system-nspr    attempt to use system nspr
                      shorthand for --with-nspr=/usr/include/nspr:
     --system-sqlite  use system sqlite
--- a/security/nss/lib/freebl/chacha20poly1305.c
+++ b/security/nss/lib/freebl/chacha20poly1305.c
@@ -205,33 +205,33 @@ ChaCha20Poly1305_Seal(const ChaCha20Poly
         PORT_SetError(SEC_ERROR_INPUT_LEN);
         return SECFailure;
     }
     // ChaCha has a 64 octet block, with a 32-bit block counter.
     if (sizeof(inputLen) > 4 && inputLen >= (1ULL << (6 + 32))) {
         PORT_SetError(SEC_ERROR_INPUT_LEN);
         return SECFailure;
     }
-    *outputLen = inputLen + ctx->tagLen;
-    if (maxOutputLen < *outputLen) {
+    if (maxOutputLen < inputLen + ctx->tagLen) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         return SECFailure;
     }
 
     PORT_Memset(block, 0, sizeof(block));
     // Generate a block of keystream. The first 32 bytes will be the poly1305
     // key. The remainder of the block is discarded.
     ChaCha20Xor(block, (uint8_t *)block, sizeof(block), (uint8_t *)ctx->key,
                 (uint8_t *)nonce, 0);
     ChaCha20Xor(output, (uint8_t *)input, inputLen, (uint8_t *)ctx->key,
                 (uint8_t *)nonce, 1);
 
     Poly1305Do(tag, ad, adLen, output, inputLen, block);
     PORT_Memcpy(output + inputLen, tag, ctx->tagLen);
 
+    *outputLen = inputLen + ctx->tagLen;
     return SECSuccess;
 #endif
 }
 
 SECStatus
 ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output,
                       unsigned int *outputLen, unsigned int maxOutputLen,
                       const unsigned char *input, unsigned int inputLen,
@@ -249,18 +249,17 @@ ChaCha20Poly1305_Open(const ChaCha20Poly
         PORT_SetError(SEC_ERROR_INPUT_LEN);
         return SECFailure;
     }
     if (inputLen < ctx->tagLen) {
         PORT_SetError(SEC_ERROR_INPUT_LEN);
         return SECFailure;
     }
     ciphertextLen = inputLen - ctx->tagLen;
-    *outputLen = ciphertextLen;
-    if (maxOutputLen < *outputLen) {
+    if (maxOutputLen < ciphertextLen) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         return SECFailure;
     }
 
     PORT_Memset(block, 0, sizeof(block));
     // Generate a block of keystream. The first 32 bytes will be the poly1305
     // key. The remainder of the block is discarded.
     ChaCha20Xor(block, (uint8_t *)block, sizeof(block), (uint8_t *)ctx->key,
@@ -269,11 +268,12 @@ ChaCha20Poly1305_Open(const ChaCha20Poly
     if (NSS_SecureMemcmp(tag, &input[ciphertextLen], ctx->tagLen) != 0) {
         PORT_SetError(SEC_ERROR_BAD_DATA);
         return SECFailure;
     }
 
     ChaCha20Xor(output, (uint8_t *)input, ciphertextLen, (uint8_t *)ctx->key,
                 (uint8_t *)nonce, 1);
 
+    *outputLen = ciphertextLen;
     return SECSuccess;
 #endif
 }
--- a/security/nss/lib/freebl/freebl.gyp
+++ b/security/nss/lib/freebl/freebl.gyp
@@ -121,19 +121,19 @@
       'type': 'static_library',
       'sources': [
         'loader.c'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports'
       ]
     },
-    # For test builds, build a static freebl library so we can statically
-    # link it into the test build binary. This way we don't have to
-    # dlopen() the shared lib but can directly call freebl functions.
+    # Build a static freebl library so we can statically link it into
+    # the binary. This way we don't have to dlopen() the shared lib
+    # but can directly call freebl functions.
     {
       'target_name': 'freebl_static',
       'type': 'static_library',
       'includes': [
         'freebl_base.gypi',
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
@@ -149,17 +149,17 @@
           'defines!': [
             'FREEBL_NO_DEPEND',
             'FREEBL_LOWHASH',
             'USE_HW_AES',
             'INTEL_GCM',
           ],
           'conditions': [
             [ 'target_arch=="x64"', {
-              # The AES assembler code doesn't work in static test builds.
+              # The AES assembler code doesn't work in static builds.
               # The linker complains about non-relocatable code, and I
               # currently don't know how to fix this properly.
               'sources!': [
                 'intel-aes.s',
                 'intel-gcm.s',
               ],
             }],
           ],
@@ -177,29 +177,30 @@
         'hw-acc-crypto',
       ],
       'conditions': [
         [ 'target_arch=="ia32" or target_arch=="x64"', {
           'dependencies': [
             'gcm-aes-x86_c_lib',
           ]
         }],
-        [ 'OS!="linux" and OS!="android"', {
+        [ 'OS!="linux"', {
           'conditions': [
             [ 'moz_fold_libs==0', {
               'dependencies': [
                 '<(DEPTH)/lib/util/util.gyp:nssutil3',
               ],
             }, {
               'libraries': [
                 '<(moz_folded_library_name)',
               ],
             }],
           ],
-        }, 'target_arch=="x64"', {
+        }],
+        [ '(OS=="linux" or OS=="android") and target_arch=="x64"', {
           'dependencies': [
             'intel-gcm-wrap_c_lib',
           ],
         }],
         [ 'OS=="win" and cc_is_clang==1', {
           'dependencies': [
             'intel-gcm-wrap_c_lib',
           ],
--- a/security/nss/lib/freebl/freebl_base.gypi
+++ b/security/nss/lib/freebl/freebl_base.gypi
@@ -94,17 +94,17 @@
           'sources': [
             'mpi/mpi_arm.c',
           ],
         }],
       ],
     }],
     [ 'OS=="win"', {
       'libraries': [
-        'advapi32.lib',
+        '-ladvapi32',
       ],
       'conditions': [
         [ 'cc_use_gnu_ld!=1 and target_arch=="x64"', {
           'sources': [
             'arcfour-amd64-masm.asm',
             'mpi/mpi_amd64.c',
             'mpi/mpi_amd64_masm.asm',
             'mpi/mp_comba_amd64_masm.asm',
--- a/security/nss/lib/freebl/mpi/mpi.c
+++ b/security/nss/lib/freebl/mpi/mpi.c
@@ -336,43 +336,29 @@ mp_set(mp_int *mp, mp_digit d)
 
 /* }}} */
 
 /* {{{ mp_set_int(mp, z) */
 
 mp_err
 mp_set_int(mp_int *mp, long z)
 {
-    int ix;
     unsigned long v = labs(z);
     mp_err res;
 
-    ARGCHK(mp != NULL, MP_BADARG);
-
-    mp_zero(mp);
-    if (z == 0)
-        return MP_OKAY; /* shortcut for zero */
-
-    if (sizeof v <= sizeof(mp_digit)) {
-        DIGIT(mp, 0) = v;
-    } else {
-        for (ix = sizeof(long) - 1; ix >= 0; ix--) {
-            if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
-                return res;
-
-            res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
-            if (res != MP_OKAY)
-                return res;
-        }
+    /* https://bugzilla.mozilla.org/show_bug.cgi?id=1509432 */
+    if ((res = mp_set_ulong(mp, v)) != MP_OKAY) { /* avoids duplicated code */
+        return res;
     }
-    if (z < 0)
+
+    if (z < 0) {
         SIGN(mp) = NEG;
+    }
 
     return MP_OKAY;
-
 } /* end mp_set_int() */
 
 /* }}} */
 
 /* {{{ mp_set_ulong(mp, z) */
 
 mp_err
 mp_set_ulong(mp_int *mp, unsigned long z)
--- a/security/nss/lib/freebl/pqg.c
+++ b/security/nss/lib/freebl/pqg.c
@@ -1010,16 +1010,18 @@ makePfromQandSeed(
     CHECK_MPI_OK(mp_init(&c));
     CHECK_MPI_OK(mp_init(&twoQ));
     CHECK_MPI_OK(mp_init(&tmp));
     CHECK_MPI_OK(mp_init(&V_n));
 
     hashlen = HASH_ResultLen(hashtype);
     outlen = hashlen * PR_BITS_PER_BYTE;
 
+    PORT_Assert(outlen > 0);
+
     /* L - 1 = n*outlen + b */
     n = (L - 1) / outlen;
     b = (L - 1) % outlen;
 
     /* ******************************************************************
     ** Step 11.1 (Step 7 in 186-1)
     **  "for j = 0 ... n let
     **           V_j = SHA[(SEED + offset + j) mod 2**seedlen]."
@@ -1763,16 +1765,17 @@ PQG_VerifyParams(const PQGParams *params
     } else if (vfy->counter == -1) {
         /* If counter is set to -1, we are really only verifying G, skip
          * the remainder of the checks for P */
         CHECKPARAM(type != FIPS186_1_TYPE); /* we only do this for DSA2 */
     } else {
         /* 10. P generated from (L, counter, g, SEED, Q) matches P
          * in PQGParams. */
         outlen = HASH_ResultLen(hashtype) * PR_BITS_PER_BYTE;
+        PORT_Assert(outlen > 0);
         n = (L - 1) / outlen;
         offset = vfy->counter * (n + 1) + ((type == FIPS186_1_TYPE) ? 2 : 1);
         CHECK_SEC_OK(makePfromQandSeed(hashtype, L, N, offset, g, &vfy->seed,
                                        &Q, &P_));
         CHECKPARAM(mp_cmp(&P, &P_) == 0);
     }
 
     /* now check G, skip if don't have a g */
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION "3.44" _NSS_CUSTOMIZED
+#define NSS_VERSION "3.45" _NSS_CUSTOMIZED " Beta"
 #define NSS_VMAJOR 3
-#define NSS_VMINOR 44
+#define NSS_VMINOR 45
 #define NSS_VPATCH 0
 #define NSS_VBUILD 0
-#define NSS_BETA PR_FALSE
+#define NSS_BETA PR_TRUE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/pk11wrap/pk11cxt.c
+++ b/security/nss/lib/pk11wrap/pk11cxt.c
@@ -1003,17 +1003,17 @@ PK11_DigestFinal(PK11Context *context, u
             crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, data, &len);
             break;
         default:
             crv = CKR_OPERATION_NOT_INITIALIZED;
             break;
     }
     PK11_ExitContextMonitor(context);
 
-    *outLen = (unsigned int)len;
     context->init = PR_FALSE; /* allow Begin to start up again */
 
     if (crv != CKR_OK) {
         PORT_SetError(PK11_MapError(crv));
         return SECFailure;
     }
+    *outLen = (unsigned int)len;
     return SECSuccess;
 }
--- a/security/nss/lib/pk11wrap/pk11obj.c
+++ b/security/nss/lib/pk11wrap/pk11obj.c
@@ -928,21 +928,21 @@ PK11_Decrypt(PK11SymKey *symKey,
         return SECFailure;
     }
 
     crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
                                        out, &len);
     if (haslock)
         PK11_ExitSlotMonitor(slot);
     pk11_CloseSession(slot, session, owner);
-    *outLen = len;
     if (crv != CKR_OK) {
         PORT_SetError(PK11_MapError(crv));
         return SECFailure;
     }
+    *outLen = len;
     return SECSuccess;
 }
 
 SECStatus
 PK11_Encrypt(PK11SymKey *symKey,
              CK_MECHANISM_TYPE mechanism, SECItem *param,
              unsigned char *out, unsigned int *outLen,
              unsigned int maxLen,
@@ -974,21 +974,21 @@ PK11_Encrypt(PK11SymKey *symKey,
         PORT_SetError(PK11_MapError(crv));
         return SECFailure;
     }
     crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data,
                                        dataLen, out, &len);
     if (haslock)
         PK11_ExitSlotMonitor(slot);
     pk11_CloseSession(slot, session, owner);
-    *outLen = len;
     if (crv != CKR_OK) {
         PORT_SetError(PK11_MapError(crv));
         return SECFailure;
     }
+    *outLen = len;
     return SECSuccess;
 }
 
 static SECStatus
 pk11_PrivDecryptRaw(SECKEYPrivateKey *key,
                     unsigned char *data, unsigned *outLen, unsigned int maxLen,
                     const unsigned char *enc, unsigned encLen,
                     CK_MECHANISM_PTR mech)
@@ -1660,31 +1660,31 @@ pk11_CreateGenericObjectHelper(PK11SlotI
     obj->next = NULL;
     obj->prev = NULL;
     return obj;
 }
 
 /* This is the classic interface. Applications would call this function to
  * create new object that would not be destroyed later. This lead to resource
  * leaks (and thus memory leaks in the PKCS #11 module).  To solve this we have
- * a new interface that automatically marks objects created on the fly to be 
- * destroyed later. 
+ * a new interface that automatically marks objects created on the fly to be
+ * destroyed later.
  * The old interface is preserved because applications like Mozilla purposefully
- * leak the reference to be found later with PK11_FindGenericObjects. New 
+ * leak the reference to be found later with PK11_FindGenericObjects. New
  * applications should use the new interface PK11_CreateManagedGenericObject */
 PK11GenericObject *
 PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate,
                          int count, PRBool token)
 {
     return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
                                           PR_FALSE);
 }
 
-/* Use this interface. It will automatically destroy any temporary objects 
- * (token = PR_FALSE) when the PK11GenericObject is freed. Permanent objects still 
+/* Use this interface. It will automatically destroy any temporary objects
+ * (token = PR_FALSE) when the PK11GenericObject is freed. Permanent objects still
  * need to be destroyed by hand with PK11_DestroyTokenObject.
  */
 PK11GenericObject *
 PK11_CreateManagedGenericObject(PK11SlotInfo *slot,
                                 const CK_ATTRIBUTE *pTemplate, int count, PRBool token)
 {
     return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
                                           !token);
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -1434,30 +1434,30 @@ PK11_InitSlot(SECMODModule *mod, CK_SLOT
     SECStatus rv;
     CK_SLOT_INFO slotInfo;
 
     slot->functionList = mod->functionList;
     slot->isInternal = mod->internal;
     slot->slotID = slotID;
     slot->isThreadSafe = mod->isThreadSafe;
     slot->hasRSAInfo = PR_FALSE;
+    slot->module = mod; /* NOTE: we don't make a reference here because
+                         * modules have references to their slots. This
+                         * works because modules keep implicit references
+                         * from their slots, and won't unload and disappear
+                         * until all their slots have been freed */
 
     if (PK11_GETTAB(slot)->C_GetSlotInfo(slotID, &slotInfo) != CKR_OK) {
         slot->disabled = PR_TRUE;
         slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
         return;
     }
 
     /* test to make sure claimed mechanism work */
     slot->needTest = mod->internal ? PR_FALSE : PR_TRUE;
-    slot->module = mod; /* NOTE: we don't make a reference here because
-                         * modules have references to their slots. This
-                         * works because modules keep implicit references
-                         * from their slots, and won't unload and disappear
-                         * until all their slots have been freed */
     (void)PK11_MakeString(NULL, slot->slot_name,
                           (char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
     slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT);
 #define ACTIVE_CARD "ActivCard SA"
     slot->isActiveCard = (PRBool)(PORT_Strncmp((char *)slotInfo.manufacturerID,
                                                ACTIVE_CARD, sizeof(ACTIVE_CARD) - 1) == 0);
     if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == 0) {
         slot->isPerm = PR_TRUE;
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -1374,18 +1374,21 @@ NSC_EncryptUpdate(CK_SESSION_HANDLE hSes
             *pulEncryptedPartLen = padoutlen;
             return CKR_OK;
         }
     }
 
     /* do it: NOTE: this assumes buf size in is >= buf size out! */
     rv = (*context->update)(context->cipherInfo, pEncryptedPart,
                             &outlen, maxout, pPart, ulPartLen);
+    if (rv != SECSuccess) {
+        return sftk_MapCryptError(PORT_GetError());
+    }
     *pulEncryptedPartLen = (CK_ULONG)(outlen + padoutlen);
-    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+    return CKR_OK;
 }
 
 /* NSC_EncryptFinal finishes a multiple-part encryption operation. */
 CK_RV
 NSC_EncryptFinal(CK_SESSION_HANDLE hSession,
                  CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
 {
     SFTKSession *session;
@@ -1455,36 +1458,39 @@ NSC_Encrypt(CK_SESSION_HANDLE hSession, 
     CHECK_FORK();
 
     /* make sure we're legal */
     crv = sftk_GetContext(hSession, &context, SFTK_ENCRYPT, PR_FALSE, &session);
     if (crv != CKR_OK)
         return crv;
 
     if (!pEncryptedData) {
-        *pulEncryptedDataLen = context->rsa ? context->maxLen : ulDataLen + 2 * context->blockSize;
-        goto finish;
+        outlen = context->rsa ? context->maxLen : ulDataLen + 2 * context->blockSize;
+        goto done;
     }
 
     if (context->doPad) {
         if (context->multi) {
+            CK_ULONG updateLen = maxoutlen;
             CK_ULONG finalLen;
             /* padding is fairly complicated, have the update and final
              * code deal with it */
             sftk_FreeSession(session);
             crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData,
-                                    pulEncryptedDataLen);
-            if (crv != CKR_OK)
-                *pulEncryptedDataLen = 0;
-            maxoutlen -= *pulEncryptedDataLen;
-            pEncryptedData += *pulEncryptedDataLen;
+                                    &updateLen);
+            if (crv != CKR_OK) {
+                updateLen = 0;
+            }
+            maxoutlen -= updateLen;
+            pEncryptedData += updateLen;
             finalLen = maxoutlen;
             crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
-            if (crv2 == CKR_OK)
-                *pulEncryptedDataLen += finalLen;
+            if (crv == CKR_OK && crv2 == CKR_OK) {
+                *pulEncryptedDataLen = updateLen + finalLen;
+            }
             return crv == CKR_OK ? crv2 : crv;
         }
         /* doPad without multi means that padding must be done on the first
         ** and only update.  There will be no final.
         */
         PORT_Assert(context->blockSize > 1);
         if (context->blockSize > 1) {
             CK_ULONG remainder = ulDataLen % context->blockSize;
@@ -1500,24 +1506,25 @@ NSC_Encrypt(CK_SESSION_HANDLE hSession, 
             }
         }
     }
 
     /* do it: NOTE: this assumes buf size is big enough. */
     rv = (*context->update)(context->cipherInfo, pEncryptedData,
                             &outlen, maxoutlen, pText.data, pText.len);
     crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
-    *pulEncryptedDataLen = (CK_ULONG)outlen;
     if (pText.data != pData)
         PORT_ZFree(pText.data, pText.len);
 fail:
     sftk_TerminateOp(session, SFTK_ENCRYPT, context);
-finish:
+done:
     sftk_FreeSession(session);
-
+    if (crv == CKR_OK) {
+        *pulEncryptedDataLen = (CK_ULONG)outlen;
+    }
     return crv;
 }
 
 /*
  ************** Crypto Functions:     Decrypt ************************
  */
 
 /* NSC_DecryptInit initializes a decryption operation. */
@@ -1596,18 +1603,21 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSes
                     context->blockSize);
         context->padDataLength = context->blockSize;
         ulEncryptedPartLen -= context->padDataLength;
     }
 
     /* do it: NOTE: this assumes buf size in is >= buf size out! */
     rv = (*context->update)(context->cipherInfo, pPart, &outlen,
                             maxout, pEncryptedPart, ulEncryptedPartLen);
+    if (rv != SECSuccess) {
+        return sftk_MapDecryptError(PORT_GetError());
+    }
     *pulPartLen = (CK_ULONG)(outlen + padoutlen);
-    return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
+    return CKR_OK;
 }
 
 /* NSC_DecryptFinal finishes a multiple-part decryption operation. */
 CK_RV
 NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
                  CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
 {
     SFTKSession *session;
@@ -1688,35 +1698,37 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
     CHECK_FORK();
 
     /* make sure we're legal */
     crv = sftk_GetContext(hSession, &context, SFTK_DECRYPT, PR_FALSE, &session);
     if (crv != CKR_OK)
         return crv;
 
     if (!pData) {
-        *pulDataLen = ulEncryptedDataLen + context->blockSize;
-        goto finish;
+        outlen = ulEncryptedDataLen + context->blockSize;
+        goto done;
     }
 
     if (context->doPad && context->multi) {
+        CK_ULONG updateLen = maxoutlen;
         CK_ULONG finalLen;
         /* padding is fairly complicated, have the update and final
          * code deal with it */
         sftk_FreeSession(session);
         crv = NSC_DecryptUpdate(hSession, pEncryptedData, ulEncryptedDataLen,
-                                pData, pulDataLen);
-        if (crv != CKR_OK)
-            *pulDataLen = 0;
-        maxoutlen -= *pulDataLen;
-        pData += *pulDataLen;
+                                pData, &updateLen);
+        if (crv == CKR_OK) {
+            maxoutlen -= updateLen;
+            pData += updateLen;
+        }
         finalLen = maxoutlen;
         crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
-        if (crv2 == CKR_OK)
-            *pulDataLen += finalLen;
+        if (crv == CKR_OK && crv2 == CKR_OK) {
+            *pulDataLen = updateLen + finalLen;
+        }
         return crv == CKR_OK ? crv2 : crv;
     }
 
     rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen,
                             pEncryptedData, ulEncryptedDataLen);
     /* XXX need to do MUCH better error mapping than this. */
     crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
     if (rv == SECSuccess && context->doPad) {
@@ -1731,20 +1743,22 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
             }
             if (badPadding) {
                 crv = CKR_ENCRYPTED_DATA_INVALID;
             } else {
                 outlen -= padding;
             }
         }
     }
-    *pulDataLen = (CK_ULONG)outlen;
     sftk_TerminateOp(session, SFTK_DECRYPT, context);
-finish:
+done:
     sftk_FreeSession(session);
+    if (crv == CKR_OK) {
+        *pulDataLen = (CK_ULONG)outlen;
+    }
     return crv;
 }
 
 /*
  ************** Crypto Functions:     Digest (HASH)  ************************
  */
 
 /* NSC_DigestInit initializes a message-digesting operation. */
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION "3.44" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION "3.45" SOFTOKEN_ECC_STRING " Beta"
 #define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 44
+#define SOFTOKEN_VMINOR 45
 #define SOFTOKEN_VPATCH 0
 #define SOFTOKEN_VBUILD 0
-#define SOFTOKEN_BETA PR_FALSE
+#define SOFTOKEN_BETA PR_TRUE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/ssl/authcert.c
+++ b/security/nss/lib/ssl/authcert.c
@@ -15,33 +15,37 @@
 #include "secder.h"
 #include "keyhi.h"
 #include "nss.h"
 #include "ssl.h"
 #include "pk11func.h" /* for PK11_ function calls */
 #include "sslimpl.h"
 
 /*
- * This callback used by SSL to pull client sertificate upon
+ * This callback used by SSL to pull client certificate upon
  * server request
  */
 SECStatus
 NSS_GetClientAuthData(void *arg,
-                      PRFileDesc *socket,
+                      PRFileDesc *fd,
                       struct CERTDistNamesStr *caNames,
                       struct CERTCertificateStr **pRetCert,
                       struct SECKEYPrivateKeyStr **pRetKey)
 {
     CERTCertificate *cert = NULL;
     SECKEYPrivateKey *privkey = NULL;
     char *chosenNickName = (char *)arg; /* CONST */
-    void *proto_win = NULL;
     SECStatus rv = SECFailure;
 
-    proto_win = SSL_RevealPinArg(socket);
+    sslSocket *ss = ssl_FindSocket(fd);
+    if (!ss) {
+        return SECFailure;
+    }
+    void *proto_win = SSL_RevealPinArg(fd);
+    PRTime now = ssl_Time(ss);
 
     if (chosenNickName) {
         cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
                                         chosenNickName, certUsageSSLClient,
                                         PR_FALSE, proto_win);
         if (cert) {
             privkey = PK11_FindKeyByAnyCert(cert, proto_win);
             if (privkey) {
@@ -59,17 +63,17 @@ NSS_GetClientAuthData(void *arg,
         if (names != NULL) {
             for (i = 0; i < names->numnicknames; i++) {
                 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
                                                 names->nicknames[i], certUsageSSLClient,
                                                 PR_FALSE, proto_win);
                 if (!cert)
                     continue;
                 /* Only check unexpired certs */
-                if (CERT_CheckCertValidTimes(cert, ssl_TimeUsec(), PR_TRUE) !=
+                if (CERT_CheckCertValidTimes(cert, now, PR_TRUE) !=
                     secCertTimeValid) {
                     CERT_DestroyCertificate(cert);
                     continue;
                 }
                 rv = NSS_CmpCertChainWCANames(cert, caNames);
                 if (rv == SECSuccess) {
                     privkey =
                         PK11_FindKeyByAnyCert(cert, proto_win);
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -4836,17 +4836,18 @@ ssl3_SendClientHello(sslSocket *ss, sslC
          * as the original one. */
         sid = ssl_ReferenceSID(ss->sec.ci.sid);
     } else if (!ss->opt.noCache) {
         /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
          * handles expired entries and other details.
          * XXX If we've been called from ssl_BeginClientHandshake, then
          * this lookup is duplicative and wasteful.
          */
-        sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+        sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
+                            ss->sec.ci.port, ss->peerID, ss->url);
     } else {
         sid = NULL;
     }
 
     /* We can't resume based on a different token. If the sid exists,
      * make sure the token that holds the master secret still exists ...
      * If we previously did client-auth, make sure that the token that holds
      * the private key still exists, is logged in, hasn't been removed, etc.
@@ -8573,18 +8574,18 @@ ssl3_HandleClientHello(sslSocket *ss, PR
          ss->xtnData.emptySessionTicket)) {
         if (sidBytes.len > 0 && !ss->opt.noCache) {
             SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",
                         SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],
                         ss->sec.ci.peer.pr_s6_addr32[1],
                         ss->sec.ci.peer.pr_s6_addr32[2],
                         ss->sec.ci.peer.pr_s6_addr32[3]));
             if (ssl_sid_lookup) {
-                sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sidBytes.data,
-                                        sidBytes.len, ss->dbHandle);
+                sid = (*ssl_sid_lookup)(ssl_Time(ss), &ss->sec.ci.peer,
+                                        sidBytes.data, sidBytes.len, ss->dbHandle);
             } else {
                 errCode = SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED;
                 goto loser;
             }
         }
     } else if (ss->statelessResume) {
         /* Fill in the client's session ID if doing a stateless resume.
          * (When doing stateless resumes, server echos client's SessionID.)
@@ -10271,17 +10272,17 @@ ssl3_HandleNewSessionTicket(sslSocket *s
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET);
         return SECFailure;
     }
 
     /* RFC5077 Section 3.3: "The client MUST NOT treat the ticket as valid
      * until it has verified the server's Finished message." See the comment in
      * ssl3_FinishHandshake for more details.
      */
-    ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_TimeUsec();
+    ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time(ss);
     if (length < 4) {
         (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
         return SECFailure;
     }
 
     rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 4, &b, &length);
     if (rv != SECSuccess) {
@@ -11579,18 +11580,18 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
     sid->keaType = ss->sec.keaType;
     sid->keaKeyBits = ss->sec.keaKeyBits;
     if (ss->sec.keaGroup) {
         sid->keaGroup = ss->sec.keaGroup->name;
     } else {
         sid->keaGroup = ssl_grp_none;
     }
     sid->sigScheme = ss->sec.signatureScheme;
-    sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
-    sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
+    sid->lastAccessTime = sid->creationTime = ssl_Time(ss);
+    sid->expirationTime = sid->creationTime + (ssl_ticket_lifetime * PR_USEC_PER_SEC);
     sid->localCert = CERT_DupCertificate(ss->sec.localCert);
     if (ss->sec.isServer) {
         sid->namedCurve = ss->sec.serverCert->namedCurve;
     }
 
     if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
         ss->xtnData.nextProto.data) {
         SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -241,17 +241,17 @@ ssl3_ClientSendSessionTicketXtn(const ss
      * caller will call this function twice, and we need the inputs to be
      * consistent between the two calls. Note that currently the caller
      * will only be holding the lock when we are the client and when we're
      * attempting to resume an existing session.
      */
     session_ticket = &sid->u.ssl3.locked.sessionTicket;
     if (session_ticket->ticket.data &&
         (xtnData->ticketTimestampVerified ||
-         ssl_TicketTimeValid(session_ticket))) {
+         ssl_TicketTimeValid(ss, session_ticket))) {
 
         xtnData->ticketTimestampVerified = PR_FALSE;
 
         rv = sslBuffer_Append(buf, session_ticket->ticket.data,
                               session_ticket->ticket.len);
         if (rv != SECSuccess) {
             return SECFailure;
         }
@@ -603,17 +603,16 @@ ssl3_ClientHandleStatusRequestXtn(const 
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
     return SECSuccess;
 }
 
-PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
 #define TLS_EX_SESS_TICKET_VERSION (0x010a)
 
 /*
  * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
  */
 SECStatus
 ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
                          const PRUint8 *appToken, unsigned int appTokenLen,
@@ -737,17 +736,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 
             goto loser;
     } else {
         rv = sslBuffer_AppendNumber(&plaintext, 0, 1);
         if (rv != SECSuccess)
             goto loser;
     }
 
     /* timestamp */
-    now = ssl_TimeUsec();
+    now = ssl_Time(ss);
     PORT_Assert(sizeof(now) == 8);
     rv = sslBuffer_AppendNumber(&plaintext, now, 8);
     if (rv != SECSuccess)
         goto loser;
 
     /* HostName (length and value) */
     rv = sslBuffer_AppendVariable(&plaintext, srvName->data, srvName->len, 2);
     if (rv != SECSuccess)
@@ -792,17 +791,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 
      *
      * We calculate the client's estimate of this as:
      *    ticket_create + ticket_age_baseline + obfuscated_age
      *    = ticket_create + 1rtt + ticket_age_client
      *
      * This is compared to the expected time, which should differ only as a
      * result of clock errors or errors in the RTT estimate.
      */
-    ticketAgeBaseline = (ssl_TimeUsec() - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
+    ticketAgeBaseline = (ssl_Time(ss) - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
     ticketAgeBaseline -= ticket->ticket_age_add;
     rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4);
     if (rv != SECSuccess)
         goto loser;
 
     /* Application token */
     rv = sslBuffer_AppendVariable(&plaintext, appToken, appTokenLen, 2);
     if (rv != SECSuccess)
@@ -1237,18 +1236,18 @@ ssl3_ProcessSessionTicketCommon(sslSocke
         SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.",
                  SSL_GETPID(), ss->fd));
         ssl3stats = SSL_GetStatistics();
         SSL_AtomicIncrementLong(&ssl3stats->hch_sid_ticket_parse_failures);
         goto loser; /* code already set */
     }
 
     /* Use the ticket if it is valid and unexpired. */
-    if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC >
-        ssl_TimeUsec()) {
+    PRTime end = parsedTicket.timestamp + (ssl_ticket_lifetime * PR_USEC_PER_SEC);
+    if (end > ssl_Time(ss)) {
 
         rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid);
         if (rv != SECSuccess) {
             goto loser; /* code already set */
         }
         if (appToken && parsedTicket.applicationToken.len) {
             rv = SECITEM_CopyItem(NULL, appToken,
                                   &parsedTicket.applicationToken);
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -150,50 +150,40 @@ ssl_BeginClientHandshake(sslSocket *ss)
     SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
 
     /* If there's an sid set from an external cache, use it. */
     if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
         sid = ss->sec.ci.sid;
         SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
     } else if (!ss->opt.noCache) {
         /* Try to find server in our session-id cache */
-        sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
-                            ss->url);
+        sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
+                            ss->sec.ci.port, ss->peerID, ss->url);
     }
 
     if (sid) {
         if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) {
             PORT_Assert(!ss->sec.localCert);
             ss->sec.localCert = CERT_DupCertificate(sid->localCert);
         } else {
             ssl_UncacheSessionID(ss);
             ssl_FreeSID(sid);
             sid = NULL;
         }
     }
     if (!sid) {
-        sid = PORT_ZNew(sslSessionID);
+        sid = ssl3_NewSessionID(ss, PR_FALSE);
         if (!sid) {
             goto loser;
         }
-        sid->references = 1;
-        sid->cached = never_cached;
-        sid->addr = ss->sec.ci.peer;
-        sid->port = ss->sec.ci.port;
-        if (ss->peerID != NULL) {
-            sid->peerID = PORT_Strdup(ss->peerID);
-        }
-        if (ss->url != NULL) {
-            sid->urlSvrName = PORT_Strdup(ss->url);
-        }
+        /* This session is a dummy, which we don't want to resume. */
+        sid->u.ssl3.keys.resumable = PR_FALSE;
     }
     ss->sec.ci.sid = sid;
 
-    PORT_Assert(sid != NULL);
-
     ss->gs.state = GS_INIT;
     ss->handshake = ssl_GatherRecord1stHandshake;
 
     /* ssl3_SendClientHello will override this if it succeeds. */
     ss->version = SSL_LIBRARY_VERSION_3_0;
 
     ssl_GetSSL3HandshakeLock(ss);
     ssl_GetXmitBufLock(ss);
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -154,17 +154,17 @@ typedef SECStatus(PR_CALLBACK *SSLExtens
     SSL_EXPERIMENTAL_API("SSL_InstallExtensionHooks",                       \
                          (PRFileDesc * _fd, PRUint16 _extension,            \
                           SSLExtensionWriter _writer, void *_writerArg,     \
                           SSLExtensionHandler _handler, void *_handlerArg), \
                          (fd, extension, writer, writerArg,                 \
                           handler, handlerArg))
 
 /*
- * Setup the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
+ * Initialize the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
  *
  * To use 0-RTT on a server, you must call this function.  Failing to call this
  * function will result in all 0-RTT being rejected.  Connections will complete,
  * but early data will be rejected.
  *
  * NSS uses a Bloom filter to track the ClientHello messages that it receives
  * (specifically, it uses the PSK binder).  This function initializes a pair of
  * Bloom filters.  The two filters are alternated over time, with new
@@ -176,21 +176,21 @@ typedef SECStatus(PR_CALLBACK *SSLExtens
  * The false-positive probability of Bloom filters means that some valid
  * handshakes will be marked as potential replays.  Early data will be rejected
  * for a false positive.  To minimize this and to allow a trade-off of space
  * against accuracy, the size of the Bloom filter can be set by this function.
  *
  * The first tuning parameter to consider is |window|, which determines the
  * window over which ClientHello messages will be tracked.  This also causes
  * early data to be rejected if a ClientHello contains a ticket age parameter
- * that is outside of this window (see Section 4.2.10.4 of
- * draft-ietf-tls-tls13-20 for details).  Set |window| to account for any
- * potential sources of clock error.  |window| is the entire width of the
- * window, which is symmetrical.  Therefore to allow 5 seconds of clock error in
- * both directions, set the value to 10 seconds (i.e., 10 * PR_USEC_PER_SEC).
+ * that is outside of this window (see Section 8.3 of RFC 8446 for details).
+ * Set |window| to account for any potential sources of clock error.  |window|
+ * is the entire width of the window, which is symmetrical.  Therefore to allow
+ * 5 seconds of clock error in both directions, set the value to 10 seconds
+ * (i.e., 10 * PR_USEC_PER_SEC).
  *
  * After calling this function, early data will be rejected until |window|
  * elapses.  This prevents replay across crashes and restarts.  Only call this
  * function once to avoid inadvertently disabling 0-RTT (use PR_CallOnce() to
  * avoid this problem).
  *
  * The primary tuning parameter is |bits| which determines the amount of memory
  * allocated to each Bloom filter.  NSS will allocate two Bloom filters, each
@@ -214,20 +214,21 @@ typedef SECStatus(PR_CALLBACK *SSLExtens
  * specification for the details of the generic problems with this technique.
  *
  * In addition to the generic anti-replay weaknesses, the state that the server
  * maintains is in local memory only.  Servers that operate in a cluster, even
  * those that use shared memory for tickets, will not share anti-replay state.
  * Early data can be replayed at least once with every server instance that will
  * accept tickets that are encrypted with the same key.
  */
-#define SSL_SetupAntiReplay(window, k, bits)                                    \
-    SSL_EXPERIMENTAL_API("SSL_SetupAntiReplay",                                 \
-                         (PRTime _window, unsigned int _k, unsigned int _bits), \
-                         (window, k, bits))
+#define SSL_InitAntiReplay(now, window, k, bits)                \
+    SSL_EXPERIMENTAL_API("SSL_InitAntiReplay",                  \
+                         (PRTime _now, PRTime _window,          \
+                          unsigned int _k, unsigned int _bits), \
+                         (now, window, k, bits))
 
 /*
  * This function allows a server application to generate a session ticket that
  * will embed the provided token.
  *
  * This function will cause a NewSessionTicket message to be sent by a server.
  * This happens even if SSL_ENABLE_SESSION_TICKETS is disabled.  This allows a
  * server to suppress the usually automatic generation of a session ticket at
@@ -718,14 +719,26 @@ typedef struct SSLAeadContextStr SSLAead
                           const PRUint8 *_hsHash, unsigned int _hsHashLen, \
                           const char *_label, unsigned int _labelLen,      \
                           CK_MECHANISM_TYPE _mech, unsigned int _keySize,  \
                           PK11SymKey **_keyp),                             \
                          (version, cipherSuite, prk,                       \
                           hsHash, hsHashLen, label, labelLen,              \
                           mech, keySize, keyp))
 
+/* SSL_SetTimeFunc overrides the default time function (PR_Now()) and provides
+ * an alternative source of time for the socket. This is used in testing, and in
+ * applications that need better control over how the clock is accessed. Set the
+ * function to NULL to use PR_Now().*/
+typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg);
+
+#define SSL_SetTimeFunc(fd, f, arg)                                      \
+    SSL_EXPERIMENTAL_API("SSL_SetTimeFunc",                              \
+                         (PRFileDesc * _fd, SSLTimeFunc _f, void *_arg), \
+                         (fd, f, arg))
+
 /* Deprecated experimental APIs */
 #define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
+#define SSL_SetupAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
 
 SEC_END_PROTOS
 
 #endif /* __sslexp_h_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -178,20 +178,21 @@ struct ssl3CertNodeStr {
     struct ssl3CertNodeStr *next;
     CERTCertificate *cert;
 };
 
 typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
 
 void ssl_CacheSessionID(sslSocket *ss);
 void ssl_UncacheSessionID(sslSocket *ss);
-void ssl_ServerCacheSessionID(sslSessionID *sid);
+void ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime);
 void ssl_ServerUncacheSessionID(sslSessionID *sid);
 
-typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
+typedef sslSessionID *(*sslSessionIDLookupFunc)(PRTime ssl_now,
+                                                const PRIPv6Addr *addr,
                                                 unsigned char *sid,
                                                 unsigned int sidLen,
                                                 CERTCertDBHandle *dbHandle);
 
 /* Socket ops */
 struct sslSocketOpsStr {
     int (*connect)(sslSocket *, const PRNetAddr *);
     PRFileDesc *(*accept)(sslSocket *, PRNetAddr *);
@@ -941,16 +942,20 @@ struct sslSocketStr {
     /* Pointer to operations vector for this socket */
     const sslSocketOps *ops;
 
     /* SSL socket options */
     sslOptions opt;
     /* Enabled version range */
     SSLVersionRange vrange;
 
+    /* A function that returns the current time. */
+    SSLTimeFunc now;
+    void *nowArg;
+
     /* State flags */
     unsigned long clientAuthRequested;
     unsigned long delayDisabled;     /* Nagle delay disabled */
     unsigned long firstHsDone;       /* first handshake is complete. */
     unsigned long enoughFirstHsDone; /* enough of the first handshake is
                                       * done for callbacks to be able to
                                       * retrieve channel security
                                       * parameters from the SSL socket. */
@@ -1099,18 +1104,17 @@ struct sslSelfEncryptKeysStr {
 };
 typedef struct sslSelfEncryptKeysStr sslSelfEncryptKeys;
 
 extern char ssl_debug;
 extern char ssl_trace;
 extern FILE *ssl_trace_iob;
 extern FILE *ssl_keylog_iob;
 extern PZLock *ssl_keylog_lock;
-extern PRUint32 ssl3_sid_timeout;
-extern PRUint32 ssl_ticket_lifetime;
+static const PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; // 2 days.
 
 extern const char *const ssl3_cipherName[];
 
 extern sslSessionIDLookupFunc ssl_sid_lookup;
 
 extern const sslNamedGroupDef ssl_named_groups[];
 
 /************************************************************************/
@@ -1190,18 +1194,19 @@ extern SECStatus ssl_SaveWriteData(sslSo
 extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
 extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
 extern SECStatus ssl_Do1stHandshake(sslSocket *ss);
 
 extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
                                              PRBool derive);
 extern void ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial);
 extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
-extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
-                                   const char *peerID, const char *urlSvrName);
+extern sslSessionID *ssl_LookupSID(PRTime now, const PRIPv6Addr *addr,
+                                   PRUint16 port, const char *peerID,
+                                   const char *urlSvrName);
 extern void ssl_FreeSID(sslSessionID *sid);
 extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
 extern sslSessionID *ssl_ReferenceSID(sslSessionID *sid);
 
 extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
                                     int len, int flags);
 
 extern PRBool ssl_FdIsBlocking(PRFileDesc *fd);
@@ -1601,18 +1606,18 @@ extern unsigned int ssl3_config_match_in
 /* Return PR_TRUE if suite is usable.  This if the suite is permitted by policy,
  * enabled, has a certificate (as needed), has a viable key agreement method, is
  * usable with the negotiated TLS version, and is otherwise usable. */
 PRBool ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
                          const SSLVersionRange *vrange, const sslSocket *ss);
 
 /* calls for accessing wrapping keys across processes. */
 extern SECStatus
-ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex,
-                   SSLWrappedSymWrappingKey *wswk);
+ssl_GetWrappingKey(unsigned int symWrapMechIndex,
+                   unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk);
 
 /* The caller passes in the new value it wants
  * to set.  This code tests the wrapped sym key entry in the file on disk.
  * If it is uninitialized, this function writes the caller's value into
  * the disk entry, and returns false.
  * Otherwise, it overwrites the caller's wswk with the value obtained from
  * the disk, and returns PR_TRUE.
  * This is all done while holding the locks/semaphores necessary to make
@@ -1714,23 +1719,18 @@ SECStatus ssl_InsertRecordHeader(const s
 /********************** misc calls *********************/
 
 #ifdef DEBUG
 extern void ssl3_CheckCipherSuiteOrderConsistency();
 #endif
 
 extern int ssl_MapLowLevelError(int hiLevelError);
 
-extern PRUint32 ssl_TimeSec(void);
-#ifdef UNSAFE_FUZZER_MODE
-#define ssl_TimeUsec() ((PRTime)12345678)
-#else
-#define ssl_TimeUsec() (PR_Now())
-#endif
-extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket);
+PRTime ssl_Time(const sslSocket *ss);
+PRBool ssl_TicketTimeValid(const sslSocket *ss, const NewSessionTicket *ticket);
 
 extern void SSL_AtomicIncrementLong(long *x);
 
 SECStatus ssl3_ApplyNSSPolicy(void);
 
 extern SECStatus
 ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec,
                             const char *label, unsigned int labelLen,
@@ -1758,17 +1758,17 @@ PRBool ssl_IsResumptionTokenUsable(sslSo
 /* unwrap helper function to handle the case where the wrapKey doesn't wind
  *  * up in the correct token for the master secret */
 PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
                              CK_MECHANISM_TYPE wrapType, SECItem *param,
                              SECItem *wrappedKey,
                              CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
                              int keySize, CK_FLAGS keyFlags, void *pinArg);
 
-/* Remove when stable. */
+/* Experimental APIs. Remove when stable. */
 
 SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
                                             SSLResumptionTokenCallback cb,
                                             void *ctx);
 SECStatus SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
                                     unsigned int len);
 
 SECStatus SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
@@ -1810,16 +1810,18 @@ SECStatus SSLExp_HkdfExpandLabel(PRUint1
                                  PK11SymKey **key);
 SECStatus
 SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
                                const PRUint8 *hsHash, unsigned int hsHashLen,
                                const char *label, unsigned int labelLen,
                                CK_MECHANISM_TYPE mech, unsigned int keySize,
                                PK11SymKey **keyp);
 
+SECStatus SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg);
+
 SEC_END_PROTOS
 
 #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
 #define SSL_GETPID getpid
 #elif defined(WIN32)
 extern int __cdecl _getpid(void);
 #define SSL_GETPID _getpid
 #else
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -15,18 +15,16 @@
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "nssilock.h"
 #include "sslencode.h"
 #if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
 #include <time.h>
 #endif
 
-PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
-
 static sslSessionID *cache = NULL;
 static PZLock *cacheLock = NULL;
 
 /* sids can be in one of 5 states:
  *
  * never_cached,        created, but not yet put into cache.
  * in_client_cache,     in the client cache's linked list.
  * in_server_cache,     entry came from the server's cache file.
@@ -254,40 +252,38 @@ ssl_ReferenceSID(sslSessionID *sid)
 
 /*
 **  Lookup sid entry in cache by Address, port, and peerID string.
 **  If found, Increment reference count, and return pointer to caller.
 **  If it has timed out or ref count is zero, remove from list and free it.
 */
 
 sslSessionID *
-ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
+ssl_LookupSID(PRTime now, const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
               const char *urlSvrName)
 {
     sslSessionID **sidp;
     sslSessionID *sid;
-    PRUint32 now;
 
     if (!urlSvrName)
         return NULL;
-    now = ssl_TimeSec();
     LOCK_CACHE;
     sidp = &cache;
     while ((sid = *sidp) != 0) {
         PORT_Assert(sid->cached == in_client_cache);
         PORT_Assert(sid->references >= 1);
 
-        SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
+        SSL_TRC(8, ("SSL: lookup: sid=0x%x", sid));
 
         if (sid->expirationTime < now) {
             /*
             ** This session-id timed out.
             ** Don't even care who it belongs to, blow it out of our cache.
             */
-            SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
+            SSL_TRC(7, ("SSL: lookup, throwing sid out, age=%d refs=%d",
                         now - sid->creationTime, sid->references));
 
             *sidp = sid->next;                                      /* delink it from the list. */
             sid->cached = invalid_cache;                            /* mark not on list. */
             ssl_FreeLockedSID(sid);                                 /* drop ref count, free. */
         } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
                    (sid->port == port) &&                           /* server port matches */
                    /* proxy (peerID) matches */
@@ -311,17 +307,17 @@ ssl_LookupSID(const PRIPv6Addr *addr, PR
     return sid;
 }
 
 /*
 ** Add an sid to the cache or return a previously cached entry to the cache.
 ** Although this is static, it is called via ss->sec.cache().
 */
 static void
-CacheSID(sslSessionID *sid)
+CacheSID(sslSessionID *sid, PRTime creationTime)
 {
     PORT_Assert(sid);
     PORT_Assert(sid->cached == never_cached);
 
     SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
                 "time=%x cached=%d",
                 sid, sid->cached, sid->addr.pr_s6_addr32[0],
                 sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
@@ -348,21 +344,26 @@ CacheSID(sslSessionID *sid)
     }
     PRINT_BUF(8, (0, "sessionID:",
                   sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
 
     sid->u.ssl3.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL);
     if (!sid->u.ssl3.lock) {
         return;
     }
-    PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
-    if (!sid->creationTime)
-        sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
-    if (!sid->expirationTime)
-        sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
+    PORT_Assert(sid->creationTime != 0);
+    if (!sid->creationTime) {
+        sid->lastAccessTime = sid->creationTime = creationTime;
+    }
+    PORT_Assert(sid->expirationTime != 0);
+    if (!sid->expirationTime) {
+        sid->expirationTime = sid->creationTime + (PR_MIN(ssl_ticket_lifetime,
+                                                          sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint) *
+                                                   PR_USEC_PER_SEC);
+    }
 
     /*
      * Put sid into the cache.  Bump reference count to indicate that
      * cache is holding a reference. Uncache will reduce the cache
      * reference.
      */
     LOCK_CACHE;
     sid->references++;
@@ -721,23 +722,23 @@ ssl_IsResumptionTokenUsable(sslSocket *s
     PORT_Assert(sid);
 
     // Check that the ticket didn't expire.
     PRTime endTime = 0;
     NewSessionTicket *ticket = &sid->u.ssl3.locked.sessionTicket;
     if (ticket->ticket_lifetime_hint != 0) {
         endTime = ticket->received_timestamp +
                   (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
-        if (endTime < ssl_TimeUsec()) {
+        if (endTime <= ssl_Time(ss)) {
             return PR_FALSE;
         }
     }
 
     // Check that the session entry didn't expire.
-    if (sid->expirationTime < ssl_TimeUsec()) {
+    if (sid->expirationTime < ssl_Time(ss)) {
         return PR_FALSE;
     }
 
     // Check that the server name (SNI) matches the one set for this session.
     // Don't use the token if there's no server name.
     if (sid->urlSvrName == NULL || PORT_Strcmp(ss->url, sid->urlSvrName) != 0) {
         return PR_FALSE;
     }
@@ -1082,20 +1083,22 @@ ssl_CacheExternalToken(sslSocket *ss)
     }
 
     /* Don't export token if the session used client authentication. */
     if (sid->u.ssl3.clAuthValid) {
         return;
     }
 
     if (!sid->creationTime) {
-        sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+        sid->lastAccessTime = sid->creationTime = ssl_Time(ss);
     }
     if (!sid->expirationTime) {
-        sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
+        sid->expirationTime = sid->creationTime + (PR_MIN(ssl_ticket_lifetime,
+                                                          sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint) *
+                                                   PR_USEC_PER_SEC);
     }
 
     sslBuffer encodedToken = SSL_BUFFER_EMPTY;
 
     if (ssl_EncodeResumptionToken(sid, &encodedToken) != SECSuccess) {
         SSL_TRC(3, ("SSL [%d]: encoding resumption token failed", ss->fd));
         return;
     }
@@ -1124,21 +1127,21 @@ ssl_CacheSessionID(sslSocket *ss)
 
     if (!ss->sec.isServer && ss->resumptionTokenCallback) {
         ssl_CacheExternalToken(ss);
         return;
     }
 
     PORT_Assert(!ss->resumptionTokenCallback);
     if (sec->isServer) {
-        ssl_ServerCacheSessionID(sec->ci.sid);
+        ssl_ServerCacheSessionID(sec->ci.sid, ssl_Time(ss));
         return;
     }
 
-    CacheSID(sec->ci.sid);
+    CacheSID(sec->ci.sid, ssl_Time(ss));
 }
 
 void
 ssl_UncacheSessionID(sslSocket *ss)
 {
     if (ss->opt.noCache) {
         return;
     }
@@ -1160,52 +1163,28 @@ void
 SSL_ClearSessionCache(void)
 {
     LOCK_CACHE;
     while (cache != NULL)
         UncacheSID(cache);
     UNLOCK_CACHE;
 }
 
-/* returns an unsigned int containing the number of seconds in PR_Now() */
-PRUint32
-ssl_TimeSec(void)
-{
-#ifdef UNSAFE_FUZZER_MODE
-    return 1234;
-#endif
-
-    PRUint32 myTime;
-#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
-    myTime = time(NULL); /* accurate until the year 2038. */
-#else
-    /* portable, but possibly slower */
-    PRTime now;
-    PRInt64 ll;
-
-    now = PR_Now();
-    LL_I2L(ll, 1000000L);
-    LL_DIV(now, now, ll);
-    LL_L2UI(myTime, now);
-#endif
-    return myTime;
-}
-
 PRBool
-ssl_TicketTimeValid(const NewSessionTicket *ticket)
+ssl_TicketTimeValid(const sslSocket *ss, const NewSessionTicket *ticket)
 {
     PRTime endTime;
 
     if (ticket->ticket_lifetime_hint == 0) {
         return PR_TRUE;
     }
 
     endTime = ticket->received_timestamp +
               (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
-    return endTime > ssl_TimeUsec();
+    return endTime > ssl_Time(ss);
 }
 
 void
 ssl3_SetSIDSessionTicket(sslSessionID *sid,
                          /*in/out*/ NewSessionTicket *newSessionTicket)
 {
     PORT_Assert(sid);
     PORT_Assert(newSessionTicket);
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -271,40 +271,50 @@ typedef struct inheritanceStr inheritanc
 #if defined(XP_UNIX) || defined(XP_BEOS)
 
 #define DEFAULT_CACHE_DIRECTORY "/tmp"
 
 #endif /* XP_UNIX || XP_BEOS */
 
 /************************************************************************/
 
+/* This is used to set locking times for the cache.  It is not used to set the
+ * PRTime attributes of sessions, which are driven by ss->now(). */
+static PRUint32
+ssl_CacheNow()
+{
+    return PR_Now() / PR_USEC_PER_SEC;
+}
+
 static PRUint32
 LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
 {
     SECStatus rv = sslMutex_Lock(&lock->mutex);
     if (rv != SECSuccess)
         return 0;
-    if (!now)
-        now = ssl_TimeSec();
+    if (!now) {
+        now = ssl_CacheNow();
+    }
+
     lock->timeStamp = now;
     lock->pid = myPid;
     return now;
 }
 
 static SECStatus
 UnlockSidCacheLock(sidCacheLock *lock)
 {
     SECStatus rv;
 
     lock->pid = 0;
     rv = sslMutex_Unlock(&lock->mutex);
     return rv;
 }
 
-/* returns the value of ssl_TimeSec on success, zero on failure. */
+/* Returns non-zero |now| or ssl_CacheNow() on success, zero on failure. */
 static PRUint32
 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
 {
     PRUint32 lockNum = set % cache->numSIDCacheLocks;
     sidCacheLock *lock = cache->sidCacheLocks + lockNum;
 
     return LockSidCacheLock(lock, now);
 }
@@ -625,19 +635,22 @@ FindSID(cacheDesc *cache, PRUint32 setNu
     return NULL;
 }
 
 /************************************************************************/
 
 /* This is the primary function for finding entries in the server's sid cache.
  * Although it is static, this function is called via the global function
  * pointer ssl_sid_lookup.
+ *
+ * sslNow is the time that the calling socket understands, which might be
+ * different than what the cache uses to maintain its locks.
  */
 static sslSessionID *
-ServerSessionIDLookup(const PRIPv6Addr *addr,
+ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
                       unsigned char *sessionID,
                       unsigned int sessionIDLength,
                       CERTCertDBHandle *dbHandle)
 {
     sslSessionID *sid = 0;
     sidCacheEntry *psce;
     certCacheEntry *pcce = 0;
     srvNameCacheEntry *psnce = 0;
@@ -707,17 +720,17 @@ ServerSessionIDLookup(const PRIPv6Addr *
                 ** Don't invalidate the SID cache entry, but don't find it.
                 */
                 PORT_Assert(!("Didn't get name Cache Lock!"));
                 psce = 0;
                 psnce = 0;
             }
         }
         if (psce) {
-            psce->lastAccessTime = now;
+            psce->lastAccessTime = sslNow;
             sce = *psce; /* grab a copy while holding the lock */
         }
     }
     UnlockSet(cache, set);
     if (psce) {
         /* sce conains a copy of the cache entry.
         ** Convert shared memory format to local format
         */
@@ -725,17 +738,17 @@ ServerSessionIDLookup(const PRIPv6Addr *
     }
     return sid;
 }
 
 /*
 ** Place a sid into the cache, if it isn't already there.
 */
 void
-ssl_ServerCacheSessionID(sslSessionID *sid)
+ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime)
 {
     PORT_Assert(sid);
 
     sidCacheEntry sce;
     PRUint32 now = 0;
     cacheDesc *cache = &globalCache;
 
     if (sid->u.ssl3.sessionIDLength == 0) {
@@ -743,17 +756,17 @@ ssl_ServerCacheSessionID(sslSessionID *s
     }
 
     if (sid->cached == never_cached || sid->cached == invalid_cache) {
         PRUint32 set;
         SECItem *name;
 
         PORT_Assert(sid->creationTime != 0);
         if (!sid->creationTime)
-            sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+            sid->lastAccessTime = sid->creationTime = creationTime;
         /* override caller's expiration time, which uses client timeout
          * duration, not server timeout duration.
          */
         sid->expirationTime =
             sid->creationTime + cache->ssl3Timeout * PR_USEC_PER_SEC;
         SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
                     "cipherSuite=%d",
                     myPid, sid->cached,
@@ -1084,17 +1097,17 @@ InitCache(cacheDesc *cache, int maxCache
     cache->keyCacheData = (SSLWrappedSymWrappingKey *)(cache->cacheMem + (ptrdiff_t)cache->keyCacheData);
     cache->ticketKeyNameSuffix = (PRUint8 *)(cache->cacheMem + (ptrdiff_t)cache->ticketKeyNameSuffix);
     cache->ticketEncKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->ticketEncKey);
     cache->ticketMacKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->ticketMacKey);
     cache->ticketKeysValid = (PRUint32 *)(cache->cacheMem + (ptrdiff_t)cache->ticketKeysValid);
     cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData);
 
     /* initialize the locks */
-    init_time = ssl_TimeSec();
+    init_time = ssl_CacheNow();
     pLock = cache->sidCacheLocks;
     for (locks_to_initialize = cache->numSIDCacheLocks + 3;
          locks_initialized < locks_to_initialize;
          ++locks_initialized, ++pLock) {
 
         SECStatus err = sslMutex_Init(&pLock->mutex, shared);
         if (err) {
             cache->numSIDCacheLocksInitialized = locks_initialized;
@@ -1513,17 +1526,17 @@ LockPoller(void *arg)
     PRUint32 expiration = cache->mutexTimeout;
 
     timeout = PR_SecondsToInterval(expiration);
     while (!sharedCache->stopPolling) {
         PR_Sleep(timeout);
         if (sharedCache->stopPolling)
             break;
 
-        now = ssl_TimeSec();
+        now = ssl_CacheNow();
         then = now - expiration;
         for (pLock = cache->sidCacheLocks, locks_polled = 0;
              locks_to_poll > locks_polled && !sharedCache->stopPolling;
              ++locks_polled, ++pLock) {
             pid_t pid;
 
             if (pLock->timeStamp < then &&
                 pLock->timeStamp != 0 &&
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -272,16 +272,18 @@ ssl_DupSocket(sslSocket *os)
 
     ss->opt = os->opt;
     ss->opt.useSocks = PR_FALSE;
     rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &os->opt.nextProtoNego);
     if (rv != SECSuccess) {
         goto loser;
     }
     ss->vrange = os->vrange;
+    ss->now = os->now;
+    ss->nowArg = os->nowArg;
 
     ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
     ss->url = !os->url ? NULL : PORT_Strdup(os->url);
 
     ss->ops = os->ops;
     ss->rTimeout = os->rTimeout;
     ss->wTimeout = os->wTimeout;
     ss->cTimeout = os->cTimeout;
@@ -2210,16 +2212,18 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile
     PORT_Assert(ss);
     if (ss == NULL) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return NULL;
     }
 
     ss->opt = sm->opt;
     ss->vrange = sm->vrange;
+    ss->now = sm->now;
+    ss->nowArg = sm->nowArg;
     PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites);
     PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, sm->ssl3.dtlsSRTPCiphers,
                 sizeof(PRUint16) * sm->ssl3.dtlsSRTPCipherCount);
     ss->ssl3.dtlsSRTPCipherCount = sm->ssl3.dtlsSRTPCipherCount;
     PORT_Memcpy(ss->ssl3.signatureSchemes, sm->ssl3.signatureSchemes,
                 sizeof(ss->ssl3.signatureSchemes[0]) *
                     sm->ssl3.signatureSchemeCount);
     ss->ssl3.signatureSchemeCount = sm->ssl3.signatureSchemeCount;
@@ -3897,32 +3901,41 @@ void
 ssl_FreeEphemeralKeyPairs(sslSocket *ss)
 {
     while (!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)) {
         PRCList *cursor = PR_LIST_TAIL(&ss->ephemeralKeyPairs);
         ssl_FreeEphemeralKeyPair((sslEphemeralKeyPair *)cursor);
     }
 }
 
+PRTime
+ssl_Time(const sslSocket *ss)
+{
+    if (!ss->now) {
+        return PR_Now();
+    }
+    return ss->now(ss->nowArg);
+}
+
 /*
 ** Create a newsocket structure for a file descriptor.
 */
 static sslSocket *
 ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
 {
     SECStatus rv;
     sslSocket *ss;
     int i;
     ssl_SetDefaultsFromEnvironment();
 
     if (ssl_force_locks)
         makeLocks = PR_TRUE;
 
     /* Make a new socket and get it ready */
-    ss = (sslSocket *)PORT_ZAlloc(sizeof(sslSocket));
+    ss = PORT_ZNew(sslSocket);
     if (!ss) {
         return NULL;
     }
     ss->opt = ssl_defaults;
     if (protocolVariant == ssl_variant_datagram) {
         ss->opt.enableRenegotiation = SSL_RENEGOTIATE_NEVER;
     }
     ss->opt.useSocks = PR_FALSE;
@@ -4046,32 +4059,33 @@ struct {
     EXP(DestroyAead),
     EXP(DestroyResumptionTokenInfo),
     EXP(EnableESNI),
     EXP(EncodeESNIKeys),
     EXP(GetCurrentEpoch),
     EXP(GetExtensionSupport),
     EXP(GetResumptionTokenInfo),
     EXP(HelloRetryRequestCallback),
+    EXP(InitAntiReplay),
     EXP(InstallExtensionHooks),
     EXP(HkdfExtract),
     EXP(HkdfExpandLabel),
     EXP(HkdfExpandLabelWithMech),
     EXP(KeyUpdate),
     EXP(MakeAead),
     EXP(RecordLayerData),
     EXP(RecordLayerWriteCallback),
     EXP(SecretCallback),
     EXP(SendCertificateRequest),
     EXP(SendSessionTicket),
     EXP(SetESNIKeyPair),
     EXP(SetMaxEarlyDataSize),
     EXP(SetResumptionTokenCallback),
     EXP(SetResumptionToken),
-    EXP(SetupAntiReplay),
+    EXP(SetTimeFunc),
 #endif
     { "", NULL }
 };
 #undef EXP
 #undef PUB
 
 void *
 SSL_GetExperimentalAPI(const char *name)
@@ -4097,16 +4111,31 @@ ssl_ClearPRCList(PRCList *list, void (*f
         PR_REMOVE_LINK(cursor);
         if (f) {
             f(cursor);
         }
         PORT_Free(cursor);
     }
 }
 
+SECStatus
+SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg)
+{
+    sslSocket *ss = ssl_FindSocket(fd);
+
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTimeFunc",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+    ss->now = f;
+    ss->nowArg = arg;
+    return SECSuccess;
+}
+
 /* Experimental APIs for session cache handling. */
 
 SECStatus
 SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
                                   SSLResumptionTokenCallback cb,
                                   void *ctx)
 {
     sslSocket *ss = ssl_FindSocket(fd);
@@ -4180,17 +4209,17 @@ SSLExp_SetResumptionToken(PRFileDesc *fd
     rv = PK11_GenerateRandom(sid->u.ssl3.sessionID, SSL3_SESSIONID_BYTES);
     if (rv != SECSuccess) {
         goto loser; // Code set by PK11_GenerateRandom.
     }
     sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
     /* Use the sid->cached as marker that this is from an external cache and
      * we don't have to look up anything in the NSS internal cache. */
     sid->cached = in_external_cache;
-    sid->lastAccessTime = ssl_TimeSec();
+    sid->lastAccessTime = ssl_Time(ss);
 
     ss->sec.ci.sid = sid;
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_Release1stHandshakeLock(ss);
     return SECSuccess;
 
 loser:
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -474,17 +474,17 @@ tls13_SetupClientHello(sslSocket *ss, ss
         sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     /* The caller must be holding sid->u.ssl3.lock for reading. */
     session_ticket = &sid->u.ssl3.locked.sessionTicket;
     PORT_Assert(session_ticket && session_ticket->ticket.data);
 
-    if (ssl_TicketTimeValid(session_ticket)) {
+    if (ssl_TicketTimeValid(ss, session_ticket)) {
         ss->statelessResume = PR_TRUE;
     }
 
     if (ss->statelessResume) {
         PORT_Assert(ss->sec.ci.sid);
         rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
@@ -2719,17 +2719,17 @@ tls13_SendServerHelloSequence(sslSocket 
         }
         if (tls13_ShouldRequestClientAuth(ss)) {
             TLS13_SET_HS_STATE(ss, wait_client_cert);
         } else {
             TLS13_SET_HS_STATE(ss, wait_finished);
         }
     }
 
-    ss->ssl3.hs.serverHelloTime = ssl_TimeUsec();
+    ss->ssl3.hs.serverHelloTime = ssl_Time(ss);
     return SECSuccess;
 }
 
 SECStatus
 tls13_HandleServerHelloPart2(sslSocket *ss)
 {
     SECStatus rv;
     sslSessionID *sid = ss->sec.ci.sid;
@@ -4976,17 +4976,17 @@ tls13_HandleNewSessionTicket(sslSocket *
         return SECFailure;
     }
     if (!tls13_IsPostHandshake(ss) || ss->sec.isServer) {
         FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
                     unexpected_message);
         return SECFailure;
     }
 
-    ticket.received_timestamp = ssl_TimeUsec();
+    ticket.received_timestamp = ssl_Time(ss);
     rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
                                      &length);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
                     decode_error);
         return SECFailure;
     }
     ticket.ticket.type = siBuffer;
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -112,18 +112,18 @@ PRUint16 tls13_EncodeDraftVersion(SSL3Pr
 SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss);
 SECStatus tls13_NegotiateVersion(sslSocket *ss,
                                  const TLSExtension *supported_versions);
 PRBool tls13_ShouldRequestClientAuth(sslSocket *ss);
 
 PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid);
 void tls13_AntiReplayRollover(PRTime now);
 
-SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k,
-                                 unsigned int bits);
+SECStatus SSLExp_InitAntiReplay(PRTime now, PRTime window, unsigned int k,
+                                unsigned int bits);
 
 SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
                                            SSLHelloRetryRequestCallback cb,
                                            void *arg);
 SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
                               PRBool buffer);
 SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
 PRBool tls13_MaybeTls13(sslSocket *ss);
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -443,17 +443,17 @@ tls13_ClientSendPreSharedKeyXtn(const ss
     if (rv != SECSuccess)
         goto loser;
     rv = sslBuffer_AppendVariable(buf, session_ticket->ticket.data,
                                   session_ticket->ticket.len, 2);
     if (rv != SECSuccess)
         goto loser;
 
     /* Obfuscated age. */
-    age = ssl_TimeUsec() - session_ticket->received_timestamp;
+    age = ssl_Time(ss) - session_ticket->received_timestamp;
     age /= PR_USEC_PER_MSEC;
     age += session_ticket->ticket_age_add;
     rv = sslBuffer_AppendNumber(buf, age, 4);
     if (rv != SECSuccess)
         goto loser;
 
     /* Write out the binder list length. */
     binderLen = tls13_GetHashSize(ss);
--- a/security/nss/lib/ssl/tls13replay.c
+++ b/security/nss/lib/ssl/tls13replay.c
@@ -104,17 +104,17 @@ loser:
  * multiple threads if the server is multi-threaded.  A monitor is used to
  * ensure that only one thread can access the structures that change over time,
  * but no such guarantee is provided for configuration data.
  *
  * Functions that read from static configuration data depend on there being a
  * memory barrier between the setup and use of this function.
  */
 SECStatus
-SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits)
+SSLExp_InitAntiReplay(PRTime now, PRTime window, unsigned int k, unsigned int bits)
 {
     SECStatus rv;
 
     if (k == 0 || bits == 0) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
     if ((k * (bits + 7) / 8) > SSL_MAX_BLOOM_FILTER_SIZE) {
@@ -148,61 +148,47 @@ SSLExp_SetupAntiReplay(PRTime window, un
     if (rv != SECSuccess) {
         goto loser; /* Code already set. */
     }
     /* When starting out, ensure that 0-RTT is not accepted until the window is
      * updated.  A ClientHello might have been accepted prior to a restart. */
     sslBloom_Fill(&ssl_anti_replay.filters[1]);
 
     ssl_anti_replay.current = 0;
-    ssl_anti_replay.nextUpdate = ssl_TimeUsec() + window;
+    ssl_anti_replay.nextUpdate = now + window;
     ssl_anti_replay.window = window;
     return SECSuccess;
 
 loser:
     (void)tls13_AntiReplayReset(NULL, NULL);
     return SECFailure;
 }
 
-/* This is exposed to tests.  Though it could, this doesn't take the lock on the
- * basis that those tests use thread confinement. */
-void
-tls13_AntiReplayRollover(PRTime now)
+static void
+tls13_AntiReplayUpdate(PRTime now)
 {
-    ssl_anti_replay.current ^= 1;
-    ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window;
-    sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current);
-}
-
-static void
-tls13_AntiReplayUpdate()
-{
-    PRTime now;
-
     PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ssl_anti_replay.lock);
-
-    now = ssl_TimeUsec();
-    if (now < ssl_anti_replay.nextUpdate) {
-        return;
+    if (now >= ssl_anti_replay.nextUpdate) {
+        ssl_anti_replay.current ^= 1;
+        ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window;
+        sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current);
     }
-
-    tls13_AntiReplayRollover(now);
 }
 
 PRBool
 tls13_InWindow(const sslSocket *ss, const sslSessionID *sid)
 {
     PRInt32 timeDelta;
 
     /* Calculate the difference between the client's view of the age of the
      * ticket (in |ss->xtnData.ticketAge|) and the server's view, which we now
      * calculate.  The result should be close to zero.  timeDelta is signed to
      * make the comparisons below easier. */
     timeDelta = ss->xtnData.ticketAge -
-                ((ssl_TimeUsec() - sid->creationTime) / PR_USEC_PER_MSEC);
+                ((ssl_Time(ss) - sid->creationTime) / PR_USEC_PER_MSEC);
 
     /* Only allow the time delta to be at most half of our window.  This is
      * symmetrical, though it doesn't need to be; this assumes that clock errors
      * on server and client will tend to cancel each other out.
      *
      * There are two anti-replay filters that roll over each window.  In the
      * worst case, immediately after a rollover of the filters, we only have a
      * single window worth of recorded 0-RTT attempts.  Thus, the period in
@@ -216,17 +202,17 @@ tls13_InWindow(const sslSocket *ss, cons
      * occur immediately afterwards.  Window 1 is still checked for new 0-RTT
      * attempts for the remainder of window 2.  Therefore, attempts to replay
      * are detected because the value is recorded in window 1.  When rollover
      * occurs again, window 1 is erased and window 3 instated.  If we allowed an
      * attempt to be late by more than half a window, then this check would not
      * prevent the same 0-RTT attempt from being accepted during window 1 and
      * later window 3.
      */
-    return PR_ABS(timeDelta) < (ssl_anti_replay.window / 2);
+    return PR_ABS(timeDelta) < (ssl_anti_replay.window / (PR_USEC_PER_MSEC * 2));
 }
 
 /* Checks for a duplicate in the two filters we have.  Performs maintenance on
  * the filters as a side-effect. This only detects a probable replay, it's
  * possible that this will return true when the 0-RTT attempt is not genuinely a
  * replay.  In that case, we reject 0-RTT unnecessarily, but that's OK because
  * no client expects 0-RTT to work every time. */
 PRBool
@@ -257,20 +243,19 @@ tls13_IsReplay(const sslSocket *ss, cons
                                   ss->xtnData.pskBinder.len,
                                   label, strlen(label),
                                   buf, size);
     if (rv != SECSuccess) {
         return PR_TRUE;
     }
 
     PZ_EnterMonitor(ssl_anti_replay.lock);
-    tls13_AntiReplayUpdate();
+    tls13_AntiReplayUpdate(ssl_Time(ss));
 
     index = ssl_anti_replay.current;
     replay = sslBloom_Add(&ssl_anti_replay.filters[index], buf);
     if (!replay) {
-        replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1],
-                                buf);
+        replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1], buf);
     }
 
     PZ_ExitMonitor(ssl_anti_replay.lock);
     return replay;
 }
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,22 +14,22 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION "3.44"
+#define NSSUTIL_VERSION "3.45 Beta"
 #define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 44
+#define NSSUTIL_VMINOR 45
 #define NSSUTIL_VPATCH 0
 #define NSSUTIL_VBUILD 0
-#define NSSUTIL_BETA PR_FALSE
+#define NSSUTIL_BETA PR_TRUE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.
  */
 extern const char *NSSUTIL_GetVersion(void);
 
--- a/security/nss/nss.gyp
+++ b/security/nss/nss.gyp
@@ -187,16 +187,17 @@
             'cmd/tests/tests.gyp:dertimetest',
             'cmd/tests/tests.gyp:encodeinttest',
             'cmd/tests/tests.gyp:nonspr10',
             'cmd/tests/tests.gyp:remtest',
             'cmd/tests/tests.gyp:secmodtest',
             'cmd/tstclnt/tstclnt.gyp:tstclnt',
             'cmd/vfychain/vfychain.gyp:vfychain',
             'cmd/vfyserv/vfyserv.gyp:vfyserv',
+            'cmd/mpitests/mpitests.gyp:mpi_tests',
             'gtests/certhigh_gtest/certhigh_gtest.gyp:certhigh_gtest',
             'gtests/cryptohi_gtest/cryptohi_gtest.gyp:cryptohi_gtest',
             'gtests/der_gtest/der_gtest.gyp:der_gtest',
             'gtests/certdb_gtest/certdb_gtest.gyp:certdb_gtest',
             'gtests/freebl_gtest/freebl_gtest.gyp:prng_gtest',
             'gtests/freebl_gtest/freebl_gtest.gyp:blake2b_gtest',
             'gtests/freebl_gtest/freebl_gtest.gyp:freebl_gtest',
             'gtests/mozpkix_gtest/mozpkix_gtest.gyp:mozpkix_gtest',
@@ -218,22 +219,16 @@
                 'gtests/sysinit_gtest/sysinit_gtest.gyp:sysinit_gtest',
               ],
             }],
             [ 'disable_libpkix==0', {
               'dependencies': [
                 'cmd/pkix-errcodes/pkix-errcodes.gyp:pkix-errcodes',
               ],
             }],
-            [ 'test_build==1', {
-              'dependencies': [
-                'cmd/mpitests/mpitests.gyp:mpi_tests',
-                'gtests/freebl_gtest/freebl_gtest.gyp:freebl_gtest',
-              ],
-            }],
             [ 'disable_fips==0', {
               'dependencies': [
                 'cmd/fipstest/fipstest.gyp:fipstest',
               ],
             }],
           ],
         },
       ],