Bug 1577822 - land NSS cf0df88aa807 UPGRADE_NSS_RELEASE, r=kjacobs
authorJ.C. Jones <jc@mozilla.com>
Fri, 06 Sep 2019 00:25:25 +0000
changeset 491954 df53ccb59e064ef84f06938e4250c73f81b1b8e1
parent 491953 3bfc0e27d0389a069380540e49b0c4c5b6ecdc3e
child 491955 ee9061d6a2a028c73a35a95d870d9d9d91d7686c
push id94631
push userjjones@mozilla.com
push dateFri, 06 Sep 2019 00:26:56 +0000
treeherderautoland@df53ccb59e06 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskjacobs
bugs1577822, 1570501, 657379, 1560329, 1576664, 1577038
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1577822 - land NSS cf0df88aa807 UPGRADE_NSS_RELEASE, r=kjacobs 2019-08-30 Alexander Scheel <ascheel@redhat.com> * automation/taskcluster/scripts/build_softoken.sh, cmd/lib/pk11table.c, gtests/pk11_gtest/pk11_aes_cmac_unittest.cc, gtests/pk11_gtest/pk11_gtest.gyp, lib/pk11wrap/debug_module.c, lib/pk11wrap/pk11mech.c, lib/softoken/pkcs11.c, lib/softoken/pkcs11c.c, lib/util/pkcs11t.h: Bug 1570501 - Expose AES-CMAC in PKCS #11 API, r=mt [cf0df88aa807] [tip] * cpputil/freebl_scoped_ptrs.h, gtests/freebl_gtest/cmac_unittests.cc, gtests/freebl_gtest/freebl_gtest.gyp, lib/freebl/blapi.h, lib/freebl/cmac.c, lib/freebl/cmac.h, lib/freebl/exports.gyp, lib/freebl/freebl_base.gypi, lib/freebl/ldvector.c, lib/freebl/loader.c, lib/freebl/loader.h, lib/freebl/manifest.mn: Bug 1570501 - Add AES-CMAC implementation to freebl, r=mt [a42c6882ba1b] 2019-09-05 David Cooper <dcooper16@gmail.com> * lib/smime/cmssiginfo.c: Bug 657379 - NSS uses the wrong OID for signatureAlgorithm field of signerInfo in CMS for DSA and ECDSA. r=rrelyea [7a83b248de30] 2019-09-05 Daiki Ueno <dueno@redhat.com> * lib/freebl/drbg.c: Backed out changeset 934c8d0e7aba It turned out to cause some new errors in LSan; backing out for now. [34a254dd1357] * lib/freebl/drbg.c: Bug 1560329, drbg: perform continuous test on entropy source, r=rrelyea Summary: FIPS 140-2 section 4.9.2 requires a conditional self test to check that consecutive entropy blocks from the system are different. As neither getentropy() nor /dev/urandom provides that check on the output, this adds the self test at caller side. Reviewers: rrelyea Reviewed By: rrelyea Bug #: 1560329 [934c8d0e7aba] 2019-08-30 Kevin Jacobs <kjacobs@mozilla.com> * coreconf/WIN32.mk: Bug 1576664 - Remove -mms-bitfields from win32 makefile r=jcj [bf4de7985f3d] 2019-08-29 Dana Keeler <dkeeler@mozilla.com> * automation/abi-check/expected-report-libnss3.so.txt, gtests/pk11_gtest/pk11_find_certs_unittest.cc, lib/nss/nss.def, lib/pk11wrap/pk11cert.c, lib/pk11wrap/pk11pub.h: bug 1577038 - add PK11_GetCertsFromPrivateKey r=jcj,kjacobs PK11_GetCertFromPrivateKey only returns one certificate with a public key that matches the given private key. This change introduces PK11_GetCertsFromPrivateKey, which returns a list of all certificates with public keys that match the given private key. [9befa8d296c0] 2019-08-30 J.C. Jones <jjones@mozilla.com> * automation/abi-check/previous-nss-release, lib/nss/nss.h, lib/softoken/softkver.h, lib/util/nssutil.h: Set version numbers to 3.47 beta [685cea0a7b48] * lib/nss/nss.h, lib/softoken/softkver.h, lib/util/nssutil.h: Set version numbers to 3.46 final [decbf7bd40fd] [NSS_3_46_RTM] Differential Revision: https://phabricator.services.mozilla.com/D44927
security/nss/TAG-INFO
security/nss/automation/abi-check/expected-report-libnss3.so.txt
security/nss/automation/abi-check/previous-nss-release
security/nss/automation/taskcluster/scripts/build_softoken.sh
security/nss/cmd/lib/pk11table.c
security/nss/coreconf/WIN32.mk
security/nss/coreconf/coreconf.dep
security/nss/cpputil/freebl_scoped_ptrs.h
security/nss/gtests/freebl_gtest/cmac_unittests.cc
security/nss/gtests/freebl_gtest/freebl_gtest.gyp
security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
security/nss/gtests/pk11_gtest/pk11_gtest.gyp
security/nss/lib/freebl/blapi.h
security/nss/lib/freebl/cmac.c
security/nss/lib/freebl/cmac.h
security/nss/lib/freebl/exports.gyp
security/nss/lib/freebl/freebl_base.gypi
security/nss/lib/freebl/ldvector.c
security/nss/lib/freebl/loader.c
security/nss/lib/freebl/loader.h
security/nss/lib/freebl/manifest.mn
security/nss/lib/nss/nss.def
security/nss/lib/nss/nss.h
security/nss/lib/pk11wrap/debug_module.c
security/nss/lib/pk11wrap/pk11cert.c
security/nss/lib/pk11wrap/pk11mech.c
security/nss/lib/pk11wrap/pk11pub.h
security/nss/lib/smime/cmssiginfo.c
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/softkver.h
security/nss/lib/util/nssutil.h
security/nss/lib/util/pkcs11t.h
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_46_RTM
+cf0df88aa807
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -0,0 +1,4 @@
+1 Added function:
+
+  'function CERTCertList* PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey*)'    {PK11_GetCertsMatchingPrivateKey@@NSS_3.47}
+
--- a/security/nss/automation/abi-check/previous-nss-release
+++ b/security/nss/automation/abi-check/previous-nss-release
@@ -1,1 +1,1 @@
-NSS_3_45_BRANCH
+NSS_3_46_BRANCH
--- a/security/nss/automation/taskcluster/scripts/build_softoken.sh
+++ b/security/nss/automation/taskcluster/scripts/build_softoken.sh
@@ -15,16 +15,17 @@ platform=`make -s -C nss platform`
 export LIBRARY_PATH="$PWD/dist-nspr/$platform/lib:$PWD/dist-util/$platform/lib"
 export LD_LIBRARY_PATH="$LIBRARY_PATH:$LD_LIBRARY_PATH"
 export INCLUDES="-I$PWD/dist-nspr/$platform/include -I$PWD/dist-util/public/nss"
 export NSS_BUILD_SOFTOKEN_ONLY=1
 
 rm -rf dist
 make -C nss-softoken nss_build_all
 
-mv dist/private/nss/blapi.h dist/public/nss
-mv dist/private/nss/alghmac.h dist/public/nss
+for i in blapi alghmac cmac; do
+    mv "dist/private/nss/${i}.h" dist/public/nss
+done
 
 # Package.
 test -d artifacts || mkdir artifacts
 rm -rf dist-softoken
 mv dist dist-softoken
 tar cvfjh artifacts/dist-softoken.tar.bz2 dist-softoken
--- a/security/nss/cmd/lib/pk11table.c
+++ b/security/nss/cmd/lib/pk11table.c
@@ -328,16 +328,18 @@ const Constant _consts[] = {
     mkEntry(CKM_SHA256_HMAC_GENERAL, Mechanism),
     mkEntry(CKM_SHA256_HMAC, Mechanism),
     mkEntry(CKM_SHA384, Mechanism),
     mkEntry(CKM_SHA384_HMAC_GENERAL, Mechanism),
     mkEntry(CKM_SHA384_HMAC, Mechanism),
     mkEntry(CKM_SHA512, Mechanism),
     mkEntry(CKM_SHA512_HMAC_GENERAL, Mechanism),
     mkEntry(CKM_SHA512_HMAC, Mechanism),
+    mkEntry(CKM_AES_CMAC, Mechanism),
+    mkEntry(CKM_AES_CMAC_GENERAL, Mechanism),
     mkEntry(CKM_CAST_KEY_GEN, Mechanism),
     mkEntry(CKM_CAST_ECB, Mechanism),
     mkEntry(CKM_CAST_CBC, Mechanism),
     mkEntry(CKM_CAST_MAC, Mechanism),
     mkEntry(CKM_CAST_MAC_GENERAL, Mechanism),
     mkEntry(CKM_CAST_CBC_PAD, Mechanism),
     mkEntry(CKM_CAST3_KEY_GEN, Mechanism),
     mkEntry(CKM_CAST3_ECB, Mechanism),
--- a/security/nss/coreconf/WIN32.mk
+++ b/security/nss/coreconf/WIN32.mk
@@ -99,17 +99,17 @@ XP_DEFINE   += -DXP_PC
 ifdef NS_USE_GCC
 LIB_SUFFIX   = a
 else
 LIB_SUFFIX   = lib
 endif
 DLL_SUFFIX   = dll
 
 ifdef NS_USE_GCC
-    OS_CFLAGS += -mwindows -mms-bitfields
+    OS_CFLAGS += -mwindows
     _GEN_IMPORT_LIB=-Wl,--out-implib,$(IMPORT_LIBRARY)
     DLLFLAGS  += -mwindows -o $@ -shared -Wl,--export-all-symbols $(if $(IMPORT_LIBRARY),$(_GEN_IMPORT_LIB))
     ifdef BUILD_OPT
 	ifeq (11,$(ALLOW_OPT_CODE_SIZE)$(OPT_CODE_SIZE))
 		OPTIMIZER += -Os
 	else
 		OPTIMIZER += -O2
 	endif
--- 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."
+
new file mode 100644
--- /dev/null
+++ b/security/nss/cpputil/freebl_scoped_ptrs.h
@@ -0,0 +1,33 @@
+/* -*- 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/. */
+
+#ifndef freebl_scoped_ptrs_h__
+#define freebl_scoped_ptrs_h__
+
+#include <memory>
+#include "blapi.h"
+
+struct ScopedDelete {
+  void operator()(CMACContext* ctx) { CMAC_Destroy(ctx, PR_TRUE); }
+};
+
+template <class T>
+struct ScopedMaybeDelete {
+  void operator()(T* ptr) {
+    if (ptr) {
+      ScopedDelete del;
+      del(ptr);
+    }
+  }
+};
+
+#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
+
+SCOPED(CMACContext);
+
+#undef SCOPED
+
+#endif  // freebl_scoped_ptrs_h__
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/freebl_gtest/cmac_unittests.cc
@@ -0,0 +1,187 @@
+// 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 "gtest/gtest.h"
+
+#include <stdint.h>
+#include <memory>
+
+#include "blapi.h"
+#include "secitem.h"
+#include "freebl_scoped_ptrs.h"
+
+class CmacAesTest : public ::testing::Test {
+ protected:
+  bool Compare(const uint8_t *actual, const uint8_t *expected,
+               unsigned int length) {
+    return strncmp((const char *)actual, (const char *)expected, length) == 0;
+  }
+};
+
+TEST_F(CmacAesTest, CreateInvalidSize) {
+  uint8_t key[1] = {0x00};
+  ScopedCMACContext ctx(CMAC_Create(CMAC_AES, key, sizeof(key)));
+  ASSERT_EQ(ctx, nullptr);
+}
+
+TEST_F(CmacAesTest, CreateRightSize) {
+  uint8_t *key = PORT_NewArray(uint8_t, AES_128_KEY_LENGTH);
+  ScopedCMACContext ctx(CMAC_Create(CMAC_AES, key, AES_128_KEY_LENGTH));
+
+  ASSERT_NE(ctx, nullptr);
+  PORT_Free(key);
+}
+
+// The following tests were taken from NIST's Cryptographic Standards and
+// Guidelines page for AES-CMAC Examples with Intermediate Values. These same
+// test vectors for AES-128 can be found in RFC 4493, Section 4.
+
+static const uint8_t kNistKeys[][AES_256_KEY_LENGTH] = {
+    {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15,
+     0x88, 0x09, 0xCF, 0x4F, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    {0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, 0xC8, 0x10, 0xF3,
+     0x2B, 0x80, 0x90, 0x79, 0xE5, 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C,
+     0x6B, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    {0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 0x2B, 0x73, 0xAE,
+     0xF0, 0x85, 0x7D, 0x77, 0x81, 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61,
+     0x08, 0xD7, 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4}};
+static const size_t kNistKeyLengthsCount = PR_ARRAY_SIZE(kNistKeys);
+static const unsigned int kNistKeyLengths[kNistKeyLengthsCount] = {
+    AES_128_KEY_LENGTH, AES_192_KEY_LENGTH, AES_256_KEY_LENGTH};
+
+static const uint8_t kNistPlaintext[64] = {
+    0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E,
+    0x11, 0x73, 0x93, 0x17, 0x2A, 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03,
+    0xAC, 0x9C, 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, 0x30,
+    0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, 0xE5, 0xFB, 0xC1, 0x19,
+    0x1A, 0x0A, 0x52, 0xEF, 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B,
+    0x17, 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10};
+static const unsigned int kNistPlaintextLengths[] = {0, 16, 20, 64};
+static const size_t kNistPlaintextLengthsCount =
+    PR_ARRAY_SIZE(kNistPlaintextLengths);
+
+// This table contains the result of a CMAC over kNistPlaintext using keys from
+// kNistKeys.  For each key, there are kNistPlaintextLengthsCount answers, all
+// listed one after the other as the input is truncated to the different sizes
+// in kNistPlaintextLengths.
+static const uint8_t kNistKnown[][AES_BLOCK_SIZE] = {
+    {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59, 0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
+     0x9B, 0x75, 0x67, 0x46},
+    {0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, 0xF7, 0x9B, 0xDD, 0x9D,
+     0xD0, 0x4A, 0x28, 0x7C},
+    {0x7D, 0x85, 0x44, 0x9E, 0xA6, 0xEA, 0x19, 0xC8, 0x23, 0xA7, 0xBF, 0x78,
+     0x83, 0x7D, 0xFA, 0xDE},
+    {0x51, 0xF0, 0xBE, 0xBF, 0x7E, 0x3B, 0x9D, 0x92, 0xFC, 0x49, 0x74, 0x17,
+     0x79, 0x36, 0x3C, 0xFE},
+    {0xD1, 0x7D, 0xDF, 0x46, 0xAD, 0xAA, 0xCD, 0xE5, 0x31, 0xCA, 0xC4, 0x83,
+     0xDE, 0x7A, 0x93, 0x67},
+    {0x9E, 0x99, 0xA7, 0xBF, 0x31, 0xE7, 0x10, 0x90, 0x06, 0x62, 0xF6, 0x5E,
+     0x61, 0x7C, 0x51, 0x84},
+    {0x3D, 0x75, 0xC1, 0x94, 0xED, 0x96, 0x07, 0x04, 0x44, 0xA9, 0xFA, 0x7E,
+     0xC7, 0x40, 0xEC, 0xF8},
+    {0xA1, 0xD5, 0xDF, 0x0E, 0xED, 0x79, 0x0F, 0x79, 0x4D, 0x77, 0x58, 0x96,
+     0x59, 0xF3, 0x9A, 0x11},
+    {0x02, 0x89, 0x62, 0xF6, 0x1B, 0x7B, 0xF8, 0x9E, 0xFC, 0x6B, 0x55, 0x1F,
+     0x46, 0x67, 0xD9, 0x83},
+    {0x28, 0xA7, 0x02, 0x3F, 0x45, 0x2E, 0x8F, 0x82, 0xBD, 0x4B, 0xF2, 0x8D,
+     0x8C, 0x37, 0xC3, 0x5C},
+    {0x15, 0x67, 0x27, 0xDC, 0x08, 0x78, 0x94, 0x4A, 0x02, 0x3C, 0x1F, 0xE0,
+     0x3B, 0xAD, 0x6D, 0x93},
+    {0xE1, 0x99, 0x21, 0x90, 0x54, 0x9F, 0x6E, 0xD5, 0x69, 0x6A, 0x2C, 0x05,
+     0x6C, 0x31, 0x54, 0x10}};
+PR_STATIC_ASSERT(PR_ARRAY_SIZE(kNistKnown) ==
+                 kNistKeyLengthsCount * kNistPlaintextLengthsCount);
+
+TEST_F(CmacAesTest, AesNistAligned) {
+  for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
+       key_index++) {
+    ScopedCMACContext ctx(CMAC_Create(CMAC_AES, kNistKeys[key_index],
+                                      kNistKeyLengths[key_index]));
+    ASSERT_NE(ctx, nullptr);
+
+    for (unsigned int plaintext_index = 0;
+         plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
+      CMAC_Begin(ctx.get());
+
+      unsigned int known_index =
+          (key_index * kNistPlaintextLengthsCount) + plaintext_index;
+      CMAC_Update(ctx.get(), kNistPlaintext,
+                  kNistPlaintextLengths[plaintext_index]);
+
+      uint8_t output[AES_BLOCK_SIZE];
+      CMAC_Finish(ctx.get(), output, NULL, AES_BLOCK_SIZE);
+
+      ASSERT_TRUE(Compare(output, kNistKnown[known_index], AES_BLOCK_SIZE));
+    }
+  }
+}
+
+TEST_F(CmacAesTest, AesNistUnaligned) {
+  for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
+       key_index++) {
+    unsigned int key_length = kNistKeyLengths[key_index];
+    ScopedCMACContext ctx(
+        CMAC_Create(CMAC_AES, kNistKeys[key_index], key_length));
+    ASSERT_NE(ctx, nullptr);
+
+    // Skip the zero-length test.
+    for (unsigned int plaintext_index = 1;
+         plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
+      unsigned int known_index =
+          (key_index * kNistPlaintextLengthsCount) + plaintext_index;
+      unsigned int plaintext_length = kNistPlaintextLengths[plaintext_index];
+
+      // Test all possible offsets and make sure that misaligned updates
+      // produce the desired result. That is, do two updates:
+      //  0      ... offset
+      //  offset ... len - offset
+      // and ensure the result is the same as doing one update.
+      for (unsigned int offset = 1; offset < plaintext_length; offset++) {
+        CMAC_Begin(ctx.get());
+
+        CMAC_Update(ctx.get(), kNistPlaintext, offset);
+        CMAC_Update(ctx.get(), kNistPlaintext + offset,
+                    plaintext_length - offset);
+
+        uint8_t output[AES_BLOCK_SIZE];
+        CMAC_Finish(ctx.get(), output, NULL, AES_BLOCK_SIZE);
+
+        ASSERT_TRUE(Compare(output, kNistKnown[known_index], AES_BLOCK_SIZE));
+      }
+    }
+  }
+}
+
+TEST_F(CmacAesTest, AesNistTruncated) {
+  for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
+       key_index++) {
+    unsigned int key_length = kNistKeyLengths[key_index];
+    ScopedCMACContext ctx(
+        CMAC_Create(CMAC_AES, kNistKeys[key_index], key_length));
+    ASSERT_TRUE(ctx != nullptr);
+
+    // Skip the zero-length test.
+    for (unsigned int plaintext_index = 1;
+         plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
+      unsigned int known_index =
+          (key_index * kNistPlaintextLengthsCount) + plaintext_index;
+      unsigned int plaintext_length = kNistPlaintextLengths[plaintext_index];
+
+      // Test truncated outputs to ensure that we always get the desired values.
+      for (unsigned int out_len = 1; out_len < AES_BLOCK_SIZE; out_len++) {
+        CMAC_Begin(ctx.get());
+
+        CMAC_Update(ctx.get(), kNistPlaintext, plaintext_length);
+
+        unsigned int actual_out_len = 0;
+        uint8_t output[AES_BLOCK_SIZE];
+        CMAC_Finish(ctx.get(), output, &actual_out_len, out_len);
+
+        ASSERT_TRUE(actual_out_len == out_len);
+        ASSERT_TRUE(Compare(output, kNistKnown[known_index], out_len));
+      }
+    }
+  }
+}
--- a/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
+++ b/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
@@ -30,16 +30,17 @@
       'target_name': 'freebl_gtest',
       'type': 'executable',
       'sources': [
         'mpi_unittest.cc',
         'dh_unittest.cc',
         'ecl_unittest.cc',
         'ghash_unittest.cc',
         'rsa_unittest.cc',
+        'cmac_unittests.cc',
         '<(DEPTH)/gtests/common/gtests.cc'
       ],
       'dependencies': [
         'freebl_gtest_deps',
         '<(DEPTH)/exports.gyp:nss_exports',
       ],
       'conditions': [
       [ 'cc_is_gcc==1 and (target_arch=="ia32" or target_arch=="x64")', {
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
@@ -0,0 +1,91 @@
+/* -*- 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 "sechash.h"
+
+#include "blapi.h"
+
+#include "gtest/gtest.h"
+#include "nss_scoped_ptrs.h"
+#include "util.h"
+
+namespace nss_test {
+
+class Pkcs11AesCmacTest : public ::testing::Test {
+ protected:
+  ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) {
+    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+    if (!slot) {
+      ADD_FAILURE() << "Can't get slot";
+      return nullptr;
+    }
+
+    ScopedPK11SymKey result(PK11_ImportSymKey(
+        slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, key_item, nullptr));
+
+    return result;
+  }
+
+  void RunTest(uint8_t *key, unsigned int key_len, uint8_t *data,
+               unsigned int data_len, uint8_t *expected,
+               unsigned int expected_len, CK_ULONG mechanism) {
+    // Create SECItems for everything...
+    std::vector<uint8_t> output(expected_len);
+    SECItem key_item = {siBuffer, key, key_len};
+    SECItem output_item = {siBuffer, output.data(), expected_len};
+    SECItem data_item = {siBuffer, data, data_len};
+    SECItem expected_item = {siBuffer, expected, expected_len};
+
+    // Do the PKCS #11 stuff...
+    ScopedPK11SymKey p11_key = ImportKey(mechanism, &key_item);
+    ASSERT_NE(nullptr, p11_key.get());
+
+    SECStatus ret = PK11_SignWithSymKey(p11_key.get(), CKM_AES_CMAC, NULL,
+                                        &output_item, &data_item);
+
+    // Verify the result...
+    ASSERT_EQ(SECSuccess, ret);
+    ASSERT_EQ(0, SECITEM_CompareItem(&output_item, &expected_item));
+  }
+};
+
+// Sanity check of the PKCS #11 API only. Extensive tests for correctness of
+// underling CMAC implementation conducted in the following file:
+//      gtests/freebl_gtest/cmac_unittests.cc
+
+TEST_F(Pkcs11AesCmacTest, Aes128NistExample1) {
+  uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
+                                     0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
+                                     0x09, 0xCF, 0x4F, 0x3C};
+  uint8_t known[AES_BLOCK_SIZE] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59,
+                                   0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
+                                   0x9B, 0x75, 0x67, 0x46};
+
+  RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, AES_BLOCK_SIZE,
+          CKM_AES_CMAC);
+}
+
+TEST_F(Pkcs11AesCmacTest, General) {
+  uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
+                                     0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
+                                     0x09, 0xCF, 0x4F, 0x3C};
+  uint8_t known[4] = {0xBB, 0x1D, 0x69, 0x29};
+
+  RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, 4, CKM_AES_CMAC_GENERAL);
+}
+
+TEST_F(Pkcs11AesCmacTest, InvalidKeySize) {
+  uint8_t key[4] = {0x00, 0x00, 0x00, 0x00};
+  SECItem key_item = {siBuffer, key, 4};
+
+  ScopedPK11SymKey result = ImportKey(CKM_AES_CMAC, &key_item);
+  ASSERT_EQ(nullptr, result.get());
+}
+}
--- a/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
@@ -122,20 +122,20 @@ std::vector<uint8_t> kUnrelatedTestCertD
     0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13, 0x11,
     0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91, 0xFF,
     0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80, 0x0A,
     0x70, 0xE6, 0x02, 0x20, 0x0F, 0x1A, 0x04, 0xC2, 0xF8, 0xBA, 0xC2, 0x94,
     0x26, 0x6E, 0xBC, 0x91, 0x7D, 0xDB, 0x75, 0x7B, 0xE8, 0xA3, 0x4F, 0x69,
     0x1B, 0xF3, 0x1F, 0x2C, 0xCE, 0x82, 0x67, 0xC9, 0x5B, 0xBB, 0xBA, 0x0A,
 };
 
-class PK11FindRawCertsBySubjectTest : public ::testing::Test {
+class PK11FindCertsTestBase : public ::testing::Test {
  protected:
-  PK11FindRawCertsBySubjectTest()
-      : mSlot(nullptr), mTestCertDBDir("PK11FindRawCertsBySubjectTest-") {}
+  PK11FindCertsTestBase()
+      : mSlot(nullptr), mTestCertDBDir("PK11FindCertsTestBase-") {}
 
   virtual void SetUp() {
     std::string testCertDBPath(mTestCertDBDir.GetPath());
     const char* testName =
         ::testing::UnitTest::GetInstance()->current_test_info()->name();
     std::string modspec = "configDir='sql:";
     modspec.append(testCertDBPath);
     modspec.append("' tokenDescription='");
@@ -152,16 +152,18 @@ class PK11FindRawCertsBySubjectTest : pu
     ASSERT_EQ(0, unlink((testCertDBPath + "/cert9.db").c_str()));
     ASSERT_EQ(0, unlink((testCertDBPath + "/key4.db").c_str()));
   }
 
   PK11SlotInfo* mSlot;
   ScopedUniqueDirectory mTestCertDBDir;
 };
 
+class PK11FindRawCertsBySubjectTest : public PK11FindCertsTestBase {};
+
 // If we don't have any certificates, we shouldn't get any when we search for
 // them.
 TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsImportedNoCertsFound) {
   SECItem subjectItem = {siBuffer,
                          const_cast<unsigned char*>(kTestCertSubjectDER.data()),
                          (unsigned int)kTestCertSubjectDER.size()};
   CERTCertificateList* certificates = nullptr;
   SECStatus rv =
@@ -339,9 +341,206 @@ TEST_F(PK11FindRawCertsBySubjectTest, Te
   SECItem subjectItem = {siBuffer, nullptr, 0};
   CERTCertificateList* certificates = nullptr;
   SECStatus rv =
       PK11_FindRawCertsWithSubject(mSlot, &subjectItem, &certificates);
   EXPECT_EQ(rv, SECSuccess);
   EXPECT_EQ(certificates, nullptr);
 }
 
+class PK11GetCertsMatchingPrivateKeyTest : public PK11FindCertsTestBase {};
+
+// This is the private secp256r1 key corresponding to the above test
+// certificates.
+std::vector<uint8_t> kTestPrivateKeyInfoDER = {
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+    0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
+    0x21, 0x91, 0x40, 0x3d, 0x57, 0x10, 0xbf, 0x15, 0xa2, 0x65, 0x81, 0x8c,
+    0xd4, 0x2e, 0xd6, 0xfe, 0xdf, 0x09, 0xad, 0xd9, 0x2d, 0x78, 0xb1, 0x8e,
+    0x7a, 0x1e, 0x9f, 0xeb, 0x95, 0x52, 0x47, 0x02, 0xa1, 0x44, 0x03, 0x42,
+    0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6,
+    0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c,
+    0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69,
+    0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e,
+    0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3,
+    0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0,
+};
+
+// issuer:test cert (different key)
+// subject:test cert (different key)
+// issuerKey:secp256k1
+// subjectKey:secp256k1
+// serialNumber:1
+std::vector<uint8_t> kTestCertWithOtherKeyDER = {
+    0x30, 0x82, 0x01, 0x3a, 0x30, 0x81, 0xdf, 0xa0, 0x03, 0x02, 0x01, 0x02,
+    0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x24, 0x31, 0x22, 0x30, 0x20,
+    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x74, 0x65, 0x73, 0x74, 0x20,
+    0x63, 0x65, 0x72, 0x74, 0x20, 0x28, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72,
+    0x65, 0x6e, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x30, 0x22, 0x18, 0x0f,
+    0x32, 0x30, 0x31, 0x37, 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30,
+    0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x24, 0x31, 0x22,
+    0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x74, 0x65, 0x73,
+    0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x20, 0x28, 0x64, 0x69, 0x66, 0x66,
+    0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x30, 0x56,
+    0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
+    0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a, 0x03, 0x42, 0x00, 0x04, 0x35, 0xee,
+    0x7c, 0x72, 0x89, 0xd8, 0xfe, 0xf7, 0xa8, 0x6a, 0xfe, 0x5d, 0xa6, 0x6d,
+    0x8b, 0xc2, 0xeb, 0xb6, 0xa8, 0x54, 0x3f, 0xd2, 0xfe, 0xad, 0x08, 0x9f,
+    0x45, 0xce, 0x7a, 0xcd, 0x0f, 0xa6, 0x43, 0x82, 0xa9, 0x50, 0x0c, 0x41,
+    0xda, 0xd7, 0x70, 0xff, 0xd4, 0xb5, 0x11, 0xbf, 0x4b, 0x49, 0x2e, 0xb1,
+    0x23, 0x88, 0x00, 0xc3, 0x2c, 0x4f, 0x76, 0xc7, 0x3a, 0x3f, 0x32, 0x94,
+    0xe7, 0xc5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20,
+    0x63, 0x59, 0x02, 0x01, 0x89, 0xd7, 0x3e, 0x5b, 0xff, 0xd1, 0x16, 0x4e,
+    0xe3, 0xe2, 0x0a, 0xe0, 0x4a, 0xd8, 0x75, 0xaf, 0x77, 0x5c, 0x93, 0x60,
+    0xba, 0x10, 0x1f, 0x97, 0xdd, 0x27, 0x2d, 0x24, 0x02, 0x20, 0x1e, 0xa0,
+    0x7b, 0xee, 0x90, 0x9b, 0x5f, 0x2c, 0x49, 0xd6, 0x61, 0xda, 0x31, 0x14,
+    0xb1, 0xa4, 0x0d, 0x2d, 0x90, 0x2b, 0x70, 0xd8, 0x6b, 0x07, 0x64, 0x27,
+    0xa5, 0x2e, 0xfe, 0xca, 0x6e, 0xe6,
+};
+
+// If there are no certs at all, we'll get back a null list.
+TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsAtAll) {
+  SECItem privateKeyInfo = {
+      siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
+      (unsigned int)kTestPrivateKeyInfoDER.size(),
+  };
+  SECKEYPrivateKey* privKey = nullptr;
+  ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
+                mSlot, &privateKeyInfo, nullptr, nullptr, false, false, KU_ALL,
+                &privKey, nullptr),
+            SECSuccess);
+  ASSERT_NE(privKey, nullptr);
+  ScopedSECKEYPrivateKey scopedPrivKey(privKey);
+  ScopedCERTCertList certs(
+      PK11_GetCertsMatchingPrivateKey(scopedPrivKey.get()));
+  ASSERT_TRUE(CERT_LIST_EMPTY(certs));
+}
+
+// If there are no certs for the private key, we'll get back a null list.
+TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsForKey) {
+  SECItem privateKeyInfo = {
+      siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
+      (unsigned int)kTestPrivateKeyInfoDER.size(),
+  };
+  SECKEYPrivateKey* privKey = nullptr;
+  ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
+                mSlot, &privateKeyInfo, nullptr, nullptr, false, false, KU_ALL,
+                &privKey, nullptr),
+            SECSuccess);
+  ASSERT_NE(privKey, nullptr);
+  ScopedSECKEYPrivateKey scopedPrivKey(privKey);
+
+  char certNickname[] = "Test Cert With Other Key";
+  SECItem certItem = {
+      siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()),
+      (unsigned int)kTestCertWithOtherKeyDER.size()};
+  ASSERT_EQ(PK11_ImportDERCert(mSlot, &certItem, CK_INVALID_HANDLE,
+                               certNickname, false),
+            SECSuccess);
+
+  ScopedCERTCertList certs(
+      PK11_GetCertsMatchingPrivateKey(scopedPrivKey.get()));
+  ASSERT_TRUE(CERT_LIST_EMPTY(certs));
+}
+
+void CheckCertListForSubjects(
+    ScopedCERTCertList& list,
+    const std::vector<const char*>& expectedSubjects) {
+  ASSERT_NE(list.get(), nullptr);
+  ASSERT_NE(expectedSubjects.size(), 0ul);
+  for (const auto& expectedSubject : expectedSubjects) {
+    size_t listLength = 0;
+    bool found = false;
+    for (CERTCertListNode* n = CERT_LIST_HEAD(list); !CERT_LIST_END(n, list);
+         n = CERT_LIST_NEXT(n)) {
+      listLength++;
+      if (strcmp(n->cert->subjectName, expectedSubject) == 0) {
+        ASSERT_FALSE(found);
+        found = true;
+      }
+    }
+    ASSERT_TRUE(found);
+    ASSERT_EQ(listLength, expectedSubjects.size());
+  }
+}
+
+// We should only get back certs that actually match the private key.
+TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestOneCertForKey) {
+  SECItem privateKeyInfo = {
+      siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
+      (unsigned int)kTestPrivateKeyInfoDER.size(),
+  };
+  SECKEYPrivateKey* privKey = nullptr;
+  ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
+                mSlot, &privateKeyInfo, nullptr, nullptr, false, false, KU_ALL,
+                &privKey, nullptr),
+            SECSuccess);
+  ASSERT_NE(privKey, nullptr);
+  ScopedSECKEYPrivateKey scopedPrivKey(privKey);
+
+  char cert1Nickname[] = "Test Cert 1";
+  SECItem cert1Item = {siBuffer,
+                       const_cast<unsigned char*>(kTestCert1DER.data()),
+                       (unsigned int)kTestCert1DER.size()};
+  ASSERT_EQ(PK11_ImportDERCert(mSlot, &cert1Item, CK_INVALID_HANDLE,
+                               cert1Nickname, false),
+            SECSuccess);
+
+  char certNickname[] = "Test Cert With Other Key";
+  SECItem certItem = {
+      siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()),
+      (unsigned int)kTestCertWithOtherKeyDER.size()};
+  ASSERT_EQ(PK11_ImportDERCert(mSlot, &certItem, CK_INVALID_HANDLE,
+                               certNickname, false),
+            SECSuccess);
+
+  ScopedCERTCertList certs(
+      PK11_GetCertsMatchingPrivateKey(scopedPrivKey.get()));
+  CheckCertListForSubjects(certs, {"CN=test cert"});
+}
+
+// We should be able to get back all certs that match the private key.
+TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestTwoCertsForKey) {
+  SECItem privateKeyInfo = {
+      siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
+      (unsigned int)kTestPrivateKeyInfoDER.size(),
+  };
+  SECKEYPrivateKey* privKey = nullptr;
+  ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
+                mSlot, &privateKeyInfo, nullptr, nullptr, false, false, KU_ALL,
+                &privKey, nullptr),
+            SECSuccess);
+  ASSERT_NE(privKey, nullptr);
+  ScopedSECKEYPrivateKey scopedPrivKey(privKey);
+
+  char cert1Nickname[] = "Test Cert 1";
+  SECItem cert1Item = {siBuffer,
+                       const_cast<unsigned char*>(kTestCert1DER.data()),
+                       (unsigned int)kTestCert1DER.size()};
+  ASSERT_EQ(PK11_ImportDERCert(mSlot, &cert1Item, CK_INVALID_HANDLE,
+                               cert1Nickname, false),
+            SECSuccess);
+  char cert2Nickname[] = "Test Cert 2 (same key, different subject)";
+  SECItem cert2Item = {siBuffer,
+                       const_cast<unsigned char*>(kUnrelatedTestCertDER.data()),
+                       (unsigned int)kUnrelatedTestCertDER.size()};
+  ASSERT_EQ(PK11_ImportDERCert(mSlot, &cert2Item, CK_INVALID_HANDLE,
+                               cert2Nickname, false),
+            SECSuccess);
+
+  char certNickname[] = "Test Cert With Other Key";
+  SECItem certItem = {
+      siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()),
+      (unsigned int)kTestCertWithOtherKeyDER.size()};
+  ASSERT_EQ(PK11_ImportDERCert(mSlot, &certItem, CK_INVALID_HANDLE,
+                               certNickname, false),
+            SECSuccess);
+
+  ScopedCERTCertList certs(
+      PK11_GetCertsMatchingPrivateKey(scopedPrivKey.get()));
+  CheckCertListForSubjects(certs, {"CN=test cert", "CN=unrelated subject DN"});
+}
+
 }  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -7,16 +7,17 @@
     '../common/gtest.gypi',
   ],
   'targets': [
     {
       'target_name': 'pk11_gtest',
       'type': 'executable',
       'sources': [
         'pk11_aeskeywrap_unittest.cc',
+        'pk11_aes_cmac_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_find_certs_unittest.cc',
--- a/security/nss/lib/freebl/blapi.h
+++ b/security/nss/lib/freebl/blapi.h
@@ -5,16 +5,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/. */
 
 #ifndef _BLAPI_H_
 #define _BLAPI_H_
 
 #include "blapit.h"
 #include "hasht.h"
+#include "cmac.h"
 #include "alghmac.h"
 
 SEC_BEGIN_PROTOS
 
 /*
 ** RSA encryption/decryption. When encrypting/decrypting the output
 ** buffer must be at least the size of the public key modulus.
 */
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/freebl/cmac.c
@@ -0,0 +1,322 @@
+/* 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/. */
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "rijndael.h"
+#include "blapi.h"
+#include "cmac.h"
+#include "secerr.h"
+#include "nspr.h"
+
+struct CMACContextStr {
+    /* Information about the block cipher to use internally. The cipher should
+     * be placed in ECB mode so that we can use it to directly encrypt blocks.
+     *
+     *
+     * To add a new cipher, add an entry to CMACCipher, update CMAC_Init,
+     * cmac_Encrypt, and CMAC_Destroy methods to handle the new cipher, and
+     * add a new Context pointer to the cipher union with the correct type. */
+    CMACCipher cipherType;
+    union {
+        AESContext aes;
+    } cipher;
+    int blockSize;
+
+    /* Internal keys which are conditionally used by the algorithm. Derived
+     * from encrypting the NULL block. We leave the storing of (and the
+     * cleanup of) the CMAC key to the underlying block cipher. */
+    unsigned char k1[MAX_BLOCK_SIZE];
+    unsigned char k2[MAX_BLOCK_SIZE];
+
+    /* When Update is called with data which isn't a multiple of the block
+     * size, we need a place to put it. HMAC handles this by passing it to
+     * the underlying hash function right away; we can't do that as the
+     * contract on the cipher object is different. */
+    unsigned int partialIndex;
+    unsigned char partialBlock[MAX_BLOCK_SIZE];
+
+    /* Last encrypted block. This gets xor-ed with partialBlock prior to
+     * encrypting it. NIST defines this to be the empty string to begin. */
+    unsigned char lastBlock[MAX_BLOCK_SIZE];
+};
+
+static void
+cmac_ShiftLeftOne(unsigned char *out, const unsigned char *in, int length)
+{
+    int i = 0;
+    for (; i < length - 1; i++) {
+        out[i] = in[i] << 1;
+        out[i] |= in[i + 1] >> 7;
+    }
+    out[i] = in[i] << 1;
+}
+
+static SECStatus
+cmac_Encrypt(CMACContext *ctx, unsigned char *output,
+             const unsigned char *input,
+             unsigned int inputLen)
+{
+    if (ctx->cipherType == CMAC_AES) {
+        unsigned int tmpOutputLen;
+        SECStatus rv = AES_Encrypt(&ctx->cipher.aes, output, &tmpOutputLen,
+                                   ctx->blockSize, input, inputLen);
+
+        /* Assumption: AES_Encrypt (when in ECB mode) always returns an
+         * output of length equal to blockSize (what was pass as the value
+         * of the maxOutputLen parameter). */
+        PORT_Assert(tmpOutputLen == ctx->blockSize);
+        return rv;
+    }
+
+    return SECFailure;
+}
+
+/* NIST SP.800-38B, 6.1 Subkey Generation */
+static SECStatus
+cmac_GenerateSubkeys(CMACContext *ctx)
+{
+    unsigned char null_block[MAX_BLOCK_SIZE] = { 0 };
+    unsigned char L[MAX_BLOCK_SIZE];
+    unsigned char v;
+    unsigned char i;
+
+    /* Step 1: L = AES(key, null_block) */
+    if (cmac_Encrypt(ctx, L, null_block, ctx->blockSize) != SECSuccess) {
+        return SECFailure;
+    }
+
+    /* In the following, some effort has been made to be constant time. Rather
+     * than conditioning on the value of the MSB (of L or K1), we use the loop
+     * to build a mask for the conditional constant. */
+
+    /* Step 2: If MSB(L) = 0, K1 = L << 1. Else, K1 = (L << 1) ^ R_b. */
+    cmac_ShiftLeftOne(ctx->k1, L, ctx->blockSize);
+    v = L[0] >> 7;
+    for (i = 1; i <= 7; i <<= 1) {
+        v |= (v << i);
+    }
+    ctx->k1[ctx->blockSize - 1] ^= (0x87 & v);
+
+    /* Step 3: If MSB(K1) = 0, K2 = K1 << 1. Else, K2 = (K1 <, 1) ^ R_b. */
+    cmac_ShiftLeftOne(ctx->k2, ctx->k1, ctx->blockSize);
+    v = ctx->k1[0] >> 7;
+    for (i = 1; i <= 7; i <<= 1) {
+        v |= (v << i);
+    }
+    ctx->k2[ctx->blockSize - 1] ^= (0x87 & v);
+
+    /* Any intermediate value in the computation of the subkey shall be
+     * secret. */
+    PORT_Memset(null_block, 0, MAX_BLOCK_SIZE);
+    PORT_Memset(L, 0, MAX_BLOCK_SIZE);
+
+    /* Step 4: Return the values. */
+    return SECSuccess;
+}
+
+/* NIST SP.800-38B, 6.2 MAC Generation step 6 */
+static SECStatus
+cmac_UpdateState(CMACContext *ctx)
+{
+    if (ctx == NULL || ctx->partialIndex != ctx->blockSize) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    /* Step 6: C_i = CIPHER(key, C_{i-1} ^ M_i)  for 1 <= i <= n, and
+     *         C_0 is defined as the empty string. */
+
+    for (unsigned int index = 0; index < ctx->blockSize; index++) {
+        ctx->partialBlock[index] ^= ctx->lastBlock[index];
+    }
+
+    return cmac_Encrypt(ctx, ctx->lastBlock, ctx->partialBlock, ctx->blockSize);
+}
+
+SECStatus
+CMAC_Init(CMACContext *ctx, CMACCipher type,
+          const unsigned char *key, unsigned int key_len)
+{
+    if (ctx == NULL) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+
+    /* We only currently support AES-CMAC. */
+    if (type != CMAC_AES) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    PORT_Memset(ctx, 0, sizeof(*ctx));
+
+    ctx->blockSize = AES_BLOCK_SIZE;
+    ctx->cipherType = CMAC_AES;
+    if (AES_InitContext(&ctx->cipher.aes, key, key_len, NULL, NSS_AES, 1,
+                        ctx->blockSize) != SECSuccess) {
+        return SECFailure;
+    }
+
+    return CMAC_Begin(ctx);
+}
+
+CMACContext *
+CMAC_Create(CMACCipher type, const unsigned char *key,
+            unsigned int key_len)
+{
+    CMACContext *result = PORT_New(CMACContext);
+
+    if (CMAC_Init(result, type, key, key_len) != SECSuccess) {
+        CMAC_Destroy(result, PR_TRUE);
+        return NULL;
+    }
+
+    return result;
+}
+
+SECStatus
+CMAC_Begin(CMACContext *ctx)
+{
+    if (ctx == NULL) {
+        return SECFailure;
+    }
+
+    /* Ensure that our blockSize is less than the maximum. When this fails,
+     * a cipher with a larger block size was added and MAX_BLOCK_SIZE needs
+     * to be updated accordingly. */
+    PORT_Assert(ctx->blockSize <= MAX_BLOCK_SIZE);
+
+    if (cmac_GenerateSubkeys(ctx) != SECSuccess) {
+        return SECFailure;
+    }
+
+    /* Set the index to write partial blocks at to zero. This saves us from
+     * having to clear ctx->partialBlock. */
+    ctx->partialIndex = 0;
+
+    /* Step 5: Let C_0 = 0^b. */
+    PORT_Memset(ctx->lastBlock, 0, ctx->blockSize);
+
+    return SECSuccess;
+}
+
+/* NIST SP.800-38B, 6.2 MAC Generation */
+SECStatus
+CMAC_Update(CMACContext *ctx, const unsigned char *data,
+            unsigned int data_len)
+{
+    int data_index = 0;
+    if (ctx == NULL) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (data == NULL || data_len == 0) {
+        return SECSuccess;
+    }
+
+    /* Copy as many bytes from data into ctx->partialBlock as we can, up to
+     * the maximum of the remaining data and the remaining space in
+     * ctx->partialBlock.
+     *
+     * Note that we swap the order (encrypt *then* copy) because the last
+     * block is different from the rest. If we end on an even multiple of
+     * the block size, we have to be able to XOR it with K1. But we won't know
+     * that it is the last until CMAC_Finish is called (and by then, CMAC_Update
+     * has already returned). */
+    while (data_index < data_len) {
+        if (ctx->partialIndex == ctx->blockSize) {
+            if (cmac_UpdateState(ctx) != SECSuccess) {
+                return SECFailure;
+            }
+
+            ctx->partialIndex = 0;
+        }
+
+        unsigned int copy_len = data_len - data_index;
+        if (copy_len > (ctx->blockSize - ctx->partialIndex)) {
+            copy_len = ctx->blockSize - ctx->partialIndex;
+        }
+
+        PORT_Memcpy(ctx->partialBlock + ctx->partialIndex, data + data_index, copy_len);
+        data_index += copy_len;
+        ctx->partialIndex += copy_len;
+    }
+
+    return SECSuccess;
+}
+
+/* NIST SP.800-38B, 6.2 MAC Generation */
+SECStatus
+CMAC_Finish(CMACContext *ctx, unsigned char *result,
+            unsigned int *result_len,
+            unsigned int max_result_len)
+{
+    if (ctx == NULL || result == NULL || max_result_len == 0) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (max_result_len > ctx->blockSize) {
+        /* This is a weird situation. The PKCS #11 soft tokencode passes
+         * sizeof(result) here, which is hard-coded as SFTK_MAX_MAC_LENGTH.
+         * This later gets truncated to min(SFTK_MAX_MAC_LENGTH, requested). */
+        max_result_len = ctx->blockSize;
+    }
+
+    /* Step 4: If M_n* is a complete block, M_n = K1 ^ M_n*. Else,
+     * M_n = K2 ^ (M_n* || 10^j). */
+    if (ctx->partialIndex == ctx->blockSize) {
+        /* XOR in K1. */
+        for (unsigned int index = 0; index < ctx->blockSize; index++) {
+            ctx->partialBlock[index] ^= ctx->k1[index];
+        }
+    } else {
+        /* Use 10* padding on the partial block. */
+        ctx->partialBlock[ctx->partialIndex++] = 0x80;
+        PORT_Memset(ctx->partialBlock + ctx->partialIndex, 0,
+                    ctx->blockSize - ctx->partialIndex);
+        ctx->partialIndex = ctx->blockSize;
+
+        /* XOR in K2. */
+        for (unsigned int index = 0; index < ctx->blockSize; index++) {
+            ctx->partialBlock[index] ^= ctx->k2[index];
+        }
+    }
+
+    /* Encrypt the block. */
+    if (cmac_UpdateState(ctx) != SECSuccess) {
+        return SECFailure;
+    }
+
+    /* Step 7 & 8: T = MSB_tlen(C_n); return T. */
+    PORT_Memcpy(result, ctx->lastBlock, max_result_len);
+    if (result_len != NULL) {
+        *result_len = max_result_len;
+    }
+    return SECSuccess;
+}
+
+void
+CMAC_Destroy(CMACContext *ctx, PRBool free_it)
+{
+    if (ctx == NULL) {
+        return;
+    }
+
+    if (ctx->cipherType == CMAC_AES) {
+        AES_DestroyContext(&ctx->cipher.aes, PR_FALSE);
+    }
+
+    /* Destroy everything in the context. This includes sensitive data in
+     * K1, K2, and lastBlock. */
+    PORT_Memset(ctx, 0, sizeof(*ctx));
+
+    if (free_it == PR_TRUE) {
+        PORT_Free(ctx);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/freebl/cmac.h
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _CMAC_H_
+#define _CMAC_H_
+
+typedef struct CMACContextStr CMACContext;
+
+SEC_BEGIN_PROTOS
+
+/* Enum for identifying the underlying block cipher we're using internally. */
+typedef enum {
+    CMAC_AES = 0
+} CMACCipher;
+
+/* Initialize an existing CMACContext struct. */
+SECStatus CMAC_Init(CMACContext *ctx, CMACCipher type,
+                    const unsigned char *key, unsigned int key_len);
+
+/* Allocate and initialize a new CMAC context with the specified cipher and
+ * key. */
+CMACContext *CMAC_Create(CMACCipher type, const unsigned char *key,
+                         unsigned int key_len);
+
+/* Called automatically by CMAC_*{Create,Init}(...). Only useful for restarting
+ * an already-started CMAC instance. */
+SECStatus CMAC_Begin(CMACContext *ctx);
+
+/* Add the specified bytes into the CMAC state. */
+SECStatus CMAC_Update(CMACContext *ctx, const unsigned char *data,
+                      unsigned int data_len);
+
+/* Finalize the CMAC state and return the result. */
+SECStatus CMAC_Finish(CMACContext *ctx, unsigned char *result,
+                      unsigned int *result_len,
+                      unsigned int max_result_len);
+
+/* Note: CMAC_Clone isn't implemented here because AES doesn't expose a
+ * context-cloning operation. */
+
+/* Destroy a CMAC context, optionally freeing it. */
+void CMAC_Destroy(CMACContext *ctx, PRBool free_it);
+
+SEC_END_PROTOS
+
+#endif
--- a/security/nss/lib/freebl/exports.gyp
+++ b/security/nss/lib/freebl/exports.gyp
@@ -22,16 +22,17 @@
                 'nsslowhash.h',
               ],
             }],
           ],
           'destination': '<(nss_public_dist_dir)/<(module)'
         },
         {
           'files': [
+            'cmac.h',
             'alghmac.h',
             'blapi.h',
             'blake2b.h',
             'chacha20poly1305.h',
             'ec.h',
             'ecl/ecl-curve.h',
             'ecl/ecl.h',
             'ecl/eclt.h',
--- a/security/nss/lib/freebl/freebl_base.gypi
+++ b/security/nss/lib/freebl/freebl_base.gypi
@@ -1,15 +1,16 @@
 # 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/.
 {
   'sources': [
     'aeskeywrap.c',
     'alg2268.c',
+    'cmac.c',
     'alghmac.c',
     'arcfive.c',
     'arcfour.c',
     'blake2b.c',
     'camellia.c',
     'chacha20poly1305.c',
     'crypto_primitives.c',
     'ctr.c',
--- a/security/nss/lib/freebl/ldvector.c
+++ b/security/nss/lib/freebl/ldvector.c
@@ -5,16 +5,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/. */
 
 #ifdef FREEBL_NO_DEPEND
 extern int FREEBL_InitStubs(void);
 #endif
 
 #include "loader.h"
+#include "cmac.h"
 #include "alghmac.h"
 #include "hmacct.h"
 #include "blapii.h"
 
 static const struct FREEBLVectorStr vector =
     {
 
       sizeof vector,
@@ -312,20 +313,28 @@ static const struct FREEBLVectorStr vect
       BLAKE2B_Update,
       BLAKE2B_End,
       BLAKE2B_FlattenSize,
       BLAKE2B_Flatten,
       BLAKE2B_Resurrect,
 
       /* End of Version 3.020 */
 
-      ChaCha20_Xor
+      ChaCha20_Xor,
 
       /* End of version 3.021 */
 
+      CMAC_Init,
+      CMAC_Create,
+      CMAC_Begin,
+      CMAC_Update,
+      CMAC_Finish,
+      CMAC_Destroy
+
+      /* End of version 3.022 */
     };
 
 const FREEBLVector*
 FREEBL_GetVector(void)
 {
 #ifdef FREEBL_NO_DEPEND
     SECStatus rv;
 #endif
--- a/security/nss/lib/freebl/loader.c
+++ b/security/nss/lib/freebl/loader.c
@@ -2240,8 +2240,59 @@ BLAKE2B_Flatten(BLAKE2BContext *ctx, uns
 BLAKE2BContext *
 BLAKE2B_Resurrect(unsigned char *space, void *arg)
 {
     if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) {
         return NULL;
     }
     return (vector->p_BLAKE2B_Resurrect)(space, arg);
 }
+
+/* == New for CMAC == */
+SECStatus
+CMAC_Init(CMACContext *ctx, CMACCipher type, const unsigned char *key,
+          unsigned int key_len)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
+        return SECFailure;
+    return (vector->p_CMAC_Init)(ctx, type, key, key_len);
+}
+
+CMACContext *
+CMAC_Create(CMACCipher type, const unsigned char *key, unsigned int key_len)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
+        return NULL;
+    return (vector->p_CMAC_Create)(type, key, key_len);
+}
+
+SECStatus
+CMAC_Begin(CMACContext *ctx)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
+        return SECFailure;
+    return (vector->p_CMAC_Begin)(ctx);
+}
+
+SECStatus
+CMAC_Update(CMACContext *ctx, const unsigned char *data, unsigned int data_len)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
+        return SECFailure;
+    return (vector->p_CMAC_Update)(ctx, data, data_len);
+}
+
+SECStatus
+CMAC_Finish(CMACContext *ctx, unsigned char *result, unsigned int *result_len,
+            unsigned int max_result_len)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
+        return SECFailure;
+    return (vector->p_CMAC_Finish)(ctx, result, result_len, max_result_len);
+}
+
+void
+CMAC_Destroy(CMACContext *ctx, PRBool free_it)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
+        return;
+    (vector->p_CMAC_Destroy)(ctx, free_it);
+}
--- a/security/nss/lib/freebl/loader.h
+++ b/security/nss/lib/freebl/loader.h
@@ -5,17 +5,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/. */
 
 #ifndef _LOADER_H_
 #define _LOADER_H_ 1
 
 #include "blapi.h"
 
-#define FREEBL_VERSION 0x0315
+#define FREEBL_VERSION 0x0316
 
 struct FREEBLVectorStr {
 
     unsigned short length;  /* of this struct in bytes */
     unsigned short version; /* of this struct. */
 
     RSAPrivateKey *(*p_RSA_NewKey)(int keySizeInBits,
                                    SECItem *publicExponent);
@@ -760,16 +760,30 @@ struct FREEBLVectorStr {
     /* Version 3.020 came to here */
 
     SECStatus (*p_ChaCha20_Xor)(unsigned char *output, const unsigned char *block,
                                 unsigned int len, const unsigned char *k,
                                 const unsigned char *nonce, PRUint32 ctr);
 
     /* Version 3.021 came to here */
 
+    SECStatus (*p_CMAC_Init)(CMACContext *ctx, CMACCipher type,
+                             const unsigned char *key, unsigned int key_len);
+    CMACContext *(*p_CMAC_Create)(CMACCipher type, const unsigned char *key,
+                                  unsigned int key_len);
+    SECStatus (*p_CMAC_Begin)(CMACContext *ctx);
+    SECStatus (*p_CMAC_Update)(CMACContext *ctx, const unsigned char *data,
+                               unsigned int data_len);
+    SECStatus (*p_CMAC_Finish)(CMACContext *ctx, unsigned char *result,
+                               unsigned int *result_len,
+                               unsigned int max_result_len);
+    void (*p_CMAC_Destroy)(CMACContext *ctx, PRBool free_it);
+
+    /* Version 3.022 came to here */
+
     /* Add new function pointers at the end of this struct and bump
      * FREEBL_VERSION at the beginning of this file. */
 };
 
 typedef struct FREEBLVectorStr FREEBLVector;
 
 #ifdef FREEBL_LOWHASH
 #include "nsslowhash.h"
--- a/security/nss/lib/freebl/manifest.mn
+++ b/security/nss/lib/freebl/manifest.mn
@@ -80,16 +80,17 @@ REQUIRES =
 EXPORTS = \
 	blapit.h \
 	shsign.h \
 	ecl-exp.h \
 	$(LOWHASH_EXPORTS) \
 	$(NULL)
 
 PRIVATE_EXPORTS = \
+	cmac.h \
 	alghmac.h \
 	blake2b.h \
 	blapi.h \
 	chacha20poly1305.h \
 	hmacct.h \
 	secmpi.h \
 	secrng.h \
 	ec.h \
@@ -114,16 +115,17 @@ VERIFIED_SRCS = $(NULL)
 CSRCS = \
 	freeblver.c \
 	ldvector.c \
 	sysrand.c \
 	$(SHA_SRCS) \
 	md2.c \
 	md5.c \
 	sha512.c \
+	cmac.c \
 	alghmac.c \
 	rawhash.c \
 	alg2268.c \
 	arcfour.c \
 	arcfive.c \
     crypto_primitives.c \
 	blake2b.c \
 	desblapi.c \
@@ -157,16 +159,17 @@ CSRCS = \
 	$(STUBS_SRCS) \
 	$(LOWHASH_SRCS) \
 	$(EXTRA_SRCS) \
 	$(NULL)
 
 ALL_CSRCS := $(CSRCS)
 
 ALL_HDRS =  \
+	cmac.h \
 	alghmac.h \
 	blake2b.h \
 	blapi.h \
 	blapit.h \
 	des.h \
 	ec.h \
 	loader.h \
 	rijndael.h \
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -1152,8 +1152,14 @@ CERT_GetCertificateDer;
 ;+       *;
 ;+};
 ;+NSS_3.45 { 	# NSS 3.45 release
 ;+    global:
 PK11_FindRawCertsWithSubject;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.47 { 	# NSS 3.47 release
+;+    global:
+PK11_GetCertsMatchingPrivateKey;
+;+    local:
+;+       *;
+;+};
--- 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.46" _NSS_CUSTOMIZED
+#define NSS_VERSION "3.47" _NSS_CUSTOMIZED " Beta"
 #define NSS_VMAJOR 3
-#define NSS_VMINOR 46
+#define NSS_VMINOR 47
 #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/debug_module.c
+++ b/security/nss/lib/pk11wrap/debug_module.c
@@ -371,16 +371,18 @@ print_mechanism(CK_MECHANISM_PTR m)
         CASE(CKM_AES_CTR);
         CASE(CKM_AES_CTS);
         CASE(CKM_AES_GCM);
         CASE(CKM_AES_ECB);
         CASE(CKM_AES_ECB_ENCRYPT_DATA);
         CASE(CKM_AES_KEY_GEN);
         CASE(CKM_AES_MAC);
         CASE(CKM_AES_MAC_GENERAL);
+        CASE(CKM_AES_CMAC);
+        CASE(CKM_AES_CMAC_GENERAL);
         CASE(CKM_CAMELLIA_CBC);
         CASE(CKM_CAMELLIA_CBC_ENCRYPT_DATA);
         CASE(CKM_CAMELLIA_CBC_PAD);
         CASE(CKM_CAMELLIA_ECB);
         CASE(CKM_CAMELLIA_ECB_ENCRYPT_DATA);
         CASE(CKM_CAMELLIA_KEY_GEN);
         CASE(CKM_CAMELLIA_MAC);
         CASE(CKM_CAMELLIA_MAC_GENERAL);
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -401,16 +401,103 @@ PK11_GetCertFromPrivateKey(SECKEYPrivate
     if (certID == CK_INVALID_HANDLE) {
         PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
         return NULL;
     }
     cert = PK11_MakeCertFromHandle(slot, certID, NULL);
     return (cert);
 }
 
+CK_OBJECT_HANDLE *
+PK11_FindCertHandlesForKeyHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle,
+                                 int *certHandleCountOut)
+{
+    if (!slot || !certHandleCountOut || keyHandle == CK_INVALID_HANDLE) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    PORTCheapArenaPool arena;
+    PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
+    CK_ATTRIBUTE idTemplate[] = {
+        { CKA_ID, NULL, 0 },
+    };
+    const int idAttrCount = sizeof(idTemplate) / sizeof(idTemplate[0]);
+    CK_RV crv = PK11_GetAttributes(&arena.arena, slot, keyHandle, idTemplate, idAttrCount);
+    if (crv != CKR_OK) {
+        PORT_DestroyCheapArena(&arena);
+        PORT_SetError(PK11_MapError(crv));
+        return NULL;
+    }
+
+    if ((idTemplate[0].ulValueLen == 0) || (idTemplate[0].ulValueLen == -1)) {
+        PORT_DestroyCheapArena(&arena);
+        PORT_SetError(SEC_ERROR_BAD_KEY);
+        return NULL;
+    }
+
+    CK_OBJECT_CLASS searchClass = CKO_CERTIFICATE;
+    CK_ATTRIBUTE searchTemplate[] = {
+        idTemplate[0],
+        { CKA_CLASS, &searchClass, sizeof(searchClass) }
+    };
+    const int searchAttrCount = sizeof(searchTemplate) / sizeof(searchTemplate[0]);
+    CK_OBJECT_HANDLE *ids = pk11_FindObjectsByTemplate(slot, searchTemplate, searchAttrCount, certHandleCountOut);
+
+    PORT_DestroyCheapArena(&arena);
+    return ids;
+}
+
+CERTCertList *
+PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey *privKey)
+{
+    if (!privKey) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+    CERTCertList *certs = CERT_NewCertList();
+    if (!certs) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return NULL;
+    }
+    PK11SlotInfo *slot = privKey->pkcs11Slot;
+    CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
+    CK_OBJECT_HANDLE certID = PK11_MatchItem(slot, handle, CKO_CERTIFICATE);
+    /* If we can't get a matching certID, there are no matching certificates,
+     * which is not an error. */
+    if (certID == CK_INVALID_HANDLE) {
+        return certs;
+    }
+    int certHandleCount = 0;
+    CK_OBJECT_HANDLE *certHandles = PK11_FindCertHandlesForKeyHandle(slot, handle, &certHandleCount);
+    if (!certHandles) {
+        /* If certHandleCount is 0, there are no matching certificates, which is
+         * not an error. */
+        if (certHandleCount == 0) {
+            return certs;
+        }
+        CERT_DestroyCertList(certs);
+        return NULL;
+    }
+    int i;
+    for (i = 0; i < certHandleCount; i++) {
+        CERTCertificate *cert = PK11_MakeCertFromHandle(slot, certHandles[i], NULL);
+        /* If PK11_MakeCertFromHandle fails for one handle, optimistically
+           assume other handles may succeed (i.e. this is best-effort). */
+        if (!cert) {
+            continue;
+        }
+        if (CERT_AddCertToListTail(certs, cert) != SECSuccess) {
+            CERT_DestroyCertificate(cert);
+        }
+    }
+    PORT_Free(certHandles);
+    return certs;
+}
+
 /*
  * delete a cert and it's private key (if no other certs are pointing to the
  * private key.
  */
 SECStatus
 PK11_DeleteTokenCertAndKey(CERTCertificate *cert, void *wincx)
 {
     SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert, wincx);
--- a/security/nss/lib/pk11wrap/pk11mech.c
+++ b/security/nss/lib/pk11wrap/pk11mech.c
@@ -231,16 +231,18 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, 
         case CKM_AES_ECB:
         case CKM_AES_CBC:
         case CKM_AES_CCM:
         case CKM_AES_CTR:
         case CKM_AES_CTS:
         case CKM_AES_GCM:
         case CKM_AES_MAC:
         case CKM_AES_MAC_GENERAL:
+        case CKM_AES_CMAC:
+        case CKM_AES_CMAC_GENERAL:
         case CKM_AES_CBC_PAD:
         case CKM_AES_KEY_GEN:
         case CKM_NETSCAPE_AES_KEY_WRAP:
         case CKM_NETSCAPE_AES_KEY_WRAP_PAD:
         case CKM_AES_XCBC_MAC:
         case CKM_AES_XCBC_MAC_96:
             return CKK_AES;
         case CKM_DES_ECB:
@@ -448,16 +450,18 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE
         case CKM_AES_ECB:
         case CKM_AES_CBC:
         case CKM_AES_CCM:
         case CKM_AES_CTR:
         case CKM_AES_CTS:
         case CKM_AES_GCM:
         case CKM_AES_MAC:
         case CKM_AES_MAC_GENERAL:
+        case CKM_AES_CMAC:
+        case CKM_AES_CMAC_GENERAL:
         case CKM_AES_CBC_PAD:
         case CKM_AES_KEY_GEN:
             return CKM_AES_KEY_GEN;
         case CKM_DES_ECB:
         case CKM_DES_CBC:
         case CKM_DES_MAC:
         case CKM_DES_MAC_GENERAL:
         case CKM_KEY_WRAP_LYNKS:
--- a/security/nss/lib/pk11wrap/pk11pub.h
+++ b/security/nss/lib/pk11wrap/pk11pub.h
@@ -878,16 +878,24 @@ PK11_GetAllSlotsForCert(CERTCertificate 
  * returns SECSuccess and sets *results to NULL. If a failure is encountered
  * while fetching any of the matching certificates, SECFailure is returned and
  * *results will be NULL.
  */
 SECStatus
 PK11_FindRawCertsWithSubject(PK11SlotInfo *slot, SECItem *derSubject,
                              CERTCertificateList **results);
 
+/*
+ * Finds and returns all certificates with a public key that matches the given
+ * private key. May return an empty list if no certificates match. Returns NULL
+ * if a failure is encountered.
+ */
+CERTCertList *
+PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey *privKey);
+
 /**********************************************************************
  * New functions which are already deprecated....
  **********************************************************************/
 SECItem *
 PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
                              CERTCertificate *cert, void *pwarg);
 SECItem *
 PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *key);
--- a/security/nss/lib/smime/cmssiginfo.c
+++ b/security/nss/lib/smime/cmssiginfo.c
@@ -126,29 +126,47 @@ NSS_CMSSignerInfo_Destroy(NSSCMSSignerIn
     if (si->cert != NULL)
         CERT_DestroyCertificate(si->cert);
 
     if (si->certList != NULL)
         CERT_DestroyCertificateList(si->certList);
 
     /* XXX storage ??? */
 }
+static SECOidTag
+NSS_CMSSignerInfo_GetSignatureAlgorithmOidTag(KeyType keyType,
+                                              SECOidTag pubkAlgTag,
+                                              SECOidTag signAlgTag)
+{
+    switch (keyType) {
+        case rsaKey:
+            return pubkAlgTag;
+        case rsaPssKey:
+        case dsaKey:
+        case ecKey:
+            return signAlgTag;
+        default:
+            return SEC_OID_UNKNOWN;
+    }
+}
 
 /*
  * NSS_CMSSignerInfo_Sign - sign something
  *
  */
 SECStatus
 NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
                        SECItem *contentType)
 {
     CERTCertificate *cert;
     SECKEYPrivateKey *privkey = NULL;
     SECOidTag digestalgtag;
     SECOidTag pubkAlgTag;
+    SECOidTag signAlgTag;
+    SECOidTag cmsSignAlgTag;
     SECItem signature = { 0 };
     SECStatus rv;
     PLArenaPool *poolp, *tmppoolp = NULL;
     SECAlgorithmID *algID, freeAlgID;
     CERTSubjectPublicKeyInfo *spki;
 
     PORT_Assert(digest != NULL);
 
@@ -177,22 +195,39 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo 
             goto loser;
     }
     digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
     /*
      * XXX I think there should be a cert-level interface for this,
      * so that I do not have to know about subjectPublicKeyInfo...
      */
     pubkAlgTag = SECOID_GetAlgorithmTag(algID);
-    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) {
+    if (algID == &freeAlgID) {
         SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
     }
 
+    signAlgTag = SEC_GetSignatureAlgorithmOidTag(SECKEY_GetPrivateKeyType(privkey),
+                                                 digestalgtag);
+    if (signAlgTag == SEC_OID_UNKNOWN) {
+        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+        goto loser;
+    }
+
+    cmsSignAlgTag = NSS_CMSSignerInfo_GetSignatureAlgorithmOidTag(
+        SECKEY_GetPrivateKeyType(privkey), pubkAlgTag, signAlgTag);
+    if (cmsSignAlgTag == SEC_OID_UNKNOWN) {
+        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+        goto loser;
+    }
+
+    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg),
+                              cmsSignAlgTag, NULL) != SECSuccess)
+        goto loser;
+
     if (signerinfo->authAttr != NULL) {
-        SECOidTag signAlgTag;
         SECItem encoded_attrs;
 
         /* find and fill in the message digest attribute. */
         rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
                                            SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
         if (rv != SECSuccess)
             goto loser;
 
@@ -225,23 +260,16 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo 
             goto loser;
 
         encoded_attrs.data = NULL;
         encoded_attrs.len = 0;
         if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr),
                                          &encoded_attrs) == NULL)
             goto loser;
 
-        signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
-                                                     digestalgtag);
-        if (signAlgTag == SEC_OID_UNKNOWN) {
-            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-            goto loser;
-        }
-
         rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len,
                           privkey, signAlgTag);
         PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
         tmppoolp = 0;
     } else {
         rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
     }
     SECKEY_DestroyPrivateKey(privkey);
@@ -250,20 +278,16 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo 
     if (rv != SECSuccess)
         goto loser;
 
     if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess)
         goto loser;
 
     SECITEM_FreeItem(&signature, PR_FALSE);
 
-    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag,
-                              NULL) != SECSuccess)
-        goto loser;
-
     return SECSuccess;
 
 loser:
     if (signature.len != 0)
         SECITEM_FreeItem(&signature, PR_FALSE);
     if (privkey)
         SECKEY_DestroyPrivateKey(privkey);
     if (tmppoolp)
@@ -321,16 +345,18 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInf
     SECKEYPublicKey *publickey = NULL;
     NSSCMSAttribute *attr;
     SECItem encoded_attrs;
     CERTCertificate *cert;
     NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
     PLArenaPool *poolp;
     SECOidTag digestalgtag;
     SECOidTag pubkAlgTag;
+    SECOidTag digestalgtagCmp;
+    SECOidTag sigAlgTag;
 
     if (signerinfo == NULL)
         return SECFailure;
 
     /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL
     ** and cert has not been verified
     */
     cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
@@ -340,18 +366,20 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInf
     }
 
     if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
         vs = NSSCMSVS_ProcessingError;
         goto loser;
     }
 
     digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
-    pubkAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
-    if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN)) {
+    pubkAlgTag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+    sigAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
+    if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN) ||
+        (sigAlgTag == SEC_OID_UNKNOWN)) {
         vs = NSSCMSVS_SignatureAlgorithmUnknown;
         goto loser;
     }
 
     if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
         if (contentType) {
             /*
          * Check content type
@@ -409,39 +437,68 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInf
         if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr),
                                          &encoded_attrs) == NULL ||
             encoded_attrs.data == NULL || encoded_attrs.len == 0) {
             PORT_FreeArena(poolp, PR_FALSE);
             vs = NSSCMSVS_ProcessingError;
             goto loser;
         }
 
-        vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
-                                   publickey, &(signerinfo->encDigest), pubkAlgTag,
-                                   digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess)
-                 ? NSSCMSVS_BadSignature
-                 : NSSCMSVS_GoodSignature;
+        if (sigAlgTag == pubkAlgTag) {
+            /* This is to handle cases in which signatureAlgorithm field
+	     * specifies the public key algorithm rather than a signature
+	     * algorithm. */
+            vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
+                                       publickey, &(signerinfo->encDigest), pubkAlgTag,
+                                       digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess)
+                     ? NSSCMSVS_BadSignature
+                     : NSSCMSVS_GoodSignature;
+        } else {
+            if (VFY_VerifyDataWithAlgorithmID(encoded_attrs.data,
+                                              encoded_attrs.len, publickey, &(signerinfo->encDigest),
+                                              &(signerinfo->digestEncAlg), &digestalgtagCmp,
+                                              signerinfo->cmsg->pwfn_arg) != SECSuccess) {
+                vs = NSSCMSVS_BadSignature;
+            } else if (digestalgtagCmp != digestalgtag) {
+                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+                vs = NSSCMSVS_BadSignature;
+            } else {
+                vs = NSSCMSVS_GoodSignature;
+            }
+        }
 
         PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */
 
     } else {
         SECItem *sig;
 
         /* No authenticated attributes.
     ** The signature is based on the plain message digest.
     */
         sig = &(signerinfo->encDigest);
         if (sig->len == 0)
             goto loser;
 
-        vs = (!digest ||
-              VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
-                                     digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess)
-                 ? NSSCMSVS_BadSignature
-                 : NSSCMSVS_GoodSignature;
+        if (sigAlgTag == pubkAlgTag) {
+            /* This is to handle cases in which signatureAlgorithm field
+	     * specifies the public key algorithm rather than a signature
+	     * algorithm. */
+            vs = (!digest ||
+                  VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
+                                         digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess)
+                     ? NSSCMSVS_BadSignature
+                     : NSSCMSVS_GoodSignature;
+        } else {
+            vs = (!digest ||
+                  VFY_VerifyDigestWithAlgorithmID(digest, publickey, sig,
+                                                  &(signerinfo->digestEncAlg), digestalgtag,
+                                                  signerinfo->cmsg->pwfn_arg) != SECSuccess)
+                     ? NSSCMSVS_BadSignature
+                     : NSSCMSVS_GoodSignature;
+        }
     }
 
     if (vs == NSSCMSVS_BadSignature) {
         int error = PORT_GetError();
         /*
      * XXX Change the generic error into our specific one, because
      * in that case we get a better explanation out of the Security
      * Advisor.  This is really a bug in the PSM error strings (the
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -319,16 +319,18 @@ static const struct mechanismList mechan
     { CKM_CDMF_MAC_GENERAL, { 8, 8, CKF_SN_VR }, PR_TRUE },
     { CKM_CDMF_CBC_PAD, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
     /* ------------------------- AES Operations --------------------------- */
     { CKM_AES_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
     { CKM_AES_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
     { CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
     { CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
     { CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
+    { CKM_AES_CMAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
+    { CKM_AES_CMAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
     { CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
     { CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE },
     { CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE },
     { CKM_AES_GCM, { 16, 32, CKF_EN_DE }, PR_TRUE },
     { CKM_AES_XCBC_MAC_96, { 16, 16, CKF_SN_VR }, PR_TRUE },
     { CKM_AES_XCBC_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
     /* ------------------------- Camellia Operations --------------------- */
     { CKM_CAMELLIA_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -25,16 +25,17 @@
 #include "pkcs11i.h"
 #include "pkcs1sig.h"
 #include "lowkeyi.h"
 #include "secder.h"
 #include "secdig.h"
 #include "lowpbe.h" /* We do PBE below */
 #include "pkcs11t.h"
 #include "secoid.h"
+#include "cmac.h"
 #include "alghmac.h"
 #include "softoken.h"
 #include "secasn1.h"
 #include "secerr.h"
 
 #include "prprf.h"
 #include "prenv.h"
 
@@ -1981,16 +1982,94 @@ sftk_doHMACInit(SFTKSessionContext *cont
     context->update = (SFTKCipher)sftk_SignCopy;
     context->verify = (SFTKVerify)sftk_HMACCmp;
     context->maxLen = hashObj->length;
     HMAC_Begin(HMACcontext);
     return CKR_OK;
 }
 
 /*
+ * common CMAC initialization routine
+ */
+static CK_RV
+sftk_doCMACInit(SFTKSessionContext *session, CMACCipher type,
+                SFTKObject *key, CK_ULONG mac_size)
+{
+    SFTKAttribute *keyval;
+    CMACContext *cmacContext;
+    CK_ULONG *intpointer;
+
+    /* Unlike HMAC, CMAC doesn't need to check key sizes as the underlying
+     * block cipher does this for us: block ciphers support only a single
+     * key size per variant.
+     *
+     * To introduce support for a CMAC based on a new block cipher, first add
+     * support for the relevant block cipher to CMAC in the freebl layer. Then
+     * update the switch statement at the end of this function. Also remember
+     * to update the switch statement in NSC_SignInit with the PKCS#11
+     * mechanism constants.
+     */
+
+    keyval = sftk_FindAttribute(key, CKA_VALUE);
+    if (keyval == NULL) {
+        return CKR_KEY_SIZE_RANGE;
+    }
+
+    /* Create the underlying CMACContext and associate it with the
+     * SFTKSessionContext's hashInfo field */
+    cmacContext = CMAC_Create(type,
+                              (const unsigned char *)keyval->attrib.pValue,
+                              keyval->attrib.ulValueLen);
+    sftk_FreeAttribute(keyval);
+
+    if (cmacContext == NULL) {
+        if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
+            return CKR_KEY_SIZE_RANGE;
+        }
+
+        return CKR_HOST_MEMORY;
+    }
+    session->hashInfo = cmacContext;
+
+    /* MACs all behave roughly the same. However, CMAC can fail because
+     * the underlying cipher can fail. In practice, this shouldn't occur
+     * because we're not using any chaining modes, letting us safely ignore
+     * the return value. */
+    session->multi = PR_TRUE;
+    session->hashUpdate = (SFTKHash)CMAC_Update;
+    session->end = (SFTKEnd)CMAC_Finish;
+    session->hashdestroy = (SFTKDestroy)CMAC_Destroy;
+
+    intpointer = PORT_New(CK_ULONG);
+    if (intpointer == NULL) {
+        return CKR_HOST_MEMORY;
+    }
+    *intpointer = mac_size;
+    session->cipherInfo = intpointer;
+
+    /* Since we're only "hashing", copy the result from session->end to the
+     * caller using sftk_SignCopy. */
+    session->update = (SFTKCipher)sftk_SignCopy;
+    session->verify = (SFTKVerify)sftk_HMACCmp;
+    session->destroy = (SFTKDestroy)sftk_Space;
+
+    /* Will need to be updated for additional block ciphers in the future. */
+    switch (type) {
+        case CMAC_AES:
+            session->maxLen = AES_BLOCK_SIZE;
+            break;
+        default:
+            PORT_Assert(0);
+            return CKR_KEY_SIZE_RANGE;
+    }
+
+    return CKR_OK;
+}
+
+/*
  *  SSL Macing support. SSL Macs are inited, then update with the base
  * hashing algorithm, then finalized in sign and verify
  */
 
 /*
  * FROM SSL:
  * 60 bytes is 3 times the maximum length MAC size that is supported.
  * We probably should have one copy of this table. We still need this table
@@ -2739,27 +2818,37 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
             INIT_HMAC_MECH(MD5)
             INIT_HMAC_MECH(SHA224)
             INIT_HMAC_MECH(SHA256)
             INIT_HMAC_MECH(SHA384)
             INIT_HMAC_MECH(SHA512)
 
         case CKM_SHA_1_HMAC_GENERAL:
             PORT_Assert(pMechanism->pParameter);
-            if (!pMechanism->pParameter) {
+            if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
                 crv = CKR_MECHANISM_PARAM_INVALID;
                 break;
             }
             crv = sftk_doHMACInit(context, HASH_AlgSHA1, key,
                                   *(CK_ULONG *)pMechanism->pParameter);
             break;
         case CKM_SHA_1_HMAC:
             crv = sftk_doHMACInit(context, HASH_AlgSHA1, key, SHA1_LENGTH);
             break;
-
+        case CKM_AES_CMAC_GENERAL:
+            PORT_Assert(pMechanism->pParameter);
+            if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
+                crv = CKR_MECHANISM_PARAM_INVALID;
+                break;
+            }
+            crv = sftk_doCMACInit(context, CMAC_AES, key, *(CK_ULONG *)pMechanism->pParameter);
+            break;
+        case CKM_AES_CMAC:
+            crv = sftk_doCMACInit(context, CMAC_AES, key, AES_BLOCK_SIZE);
+            break;
         case CKM_SSL3_MD5_MAC:
             PORT_Assert(pMechanism->pParameter);
             if (!pMechanism->pParameter) {
                 crv = CKR_MECHANISM_PARAM_INVALID;
                 break;
             }
             crv = sftk_doSSLMACInit(context, SEC_OID_MD5, key,
                                     *(CK_ULONG *)pMechanism->pParameter);
--- 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.46" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION "3.47" SOFTOKEN_ECC_STRING " Beta"
 #define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 46
+#define SOFTOKEN_VMINOR 47
 #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/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.46"
+#define NSSUTIL_VERSION "3.47 Beta"
 #define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 46
+#define NSSUTIL_VMINOR 47
 #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/lib/util/pkcs11t.h
+++ b/security/nss/lib/util/pkcs11t.h
@@ -877,16 +877,19 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
 #define CKM_AES_MAC_GENERAL 0x00001084
 #define CKM_AES_CBC_PAD 0x00001085
 /* new for v2.20 amendment 3 */
 #define CKM_AES_CTR 0x00001086
 /* new for v2.30 */
 #define CKM_AES_GCM 0x00001087
 #define CKM_AES_CCM 0x00001088
 #define CKM_AES_CTS 0x00001089
+/* AES-CMAC values copied from v2.40 errata 1 header file */
+#define CKM_AES_CMAC_GENERAL 0x0000108A
+#define CKM_AES_CMAC 0x0000108B
 #define CKM_AES_XCBC_MAC 0x0000108C
 #define CKM_AES_XCBC_MAC_96 0x0000108D
 
 /* BlowFish and TwoFish are new for v2.20 */
 #define CKM_BLOWFISH_KEY_GEN 0x00001090
 #define CKM_BLOWFISH_CBC 0x00001091
 #define CKM_TWOFISH_KEY_GEN 0x00001092
 #define CKM_TWOFISH_CBC 0x00001093