ddf7d0
diff -up ./automation/taskcluster/scripts/build_softoken.sh.cmac ./automation/taskcluster/scripts/build_softoken.sh
ddf7d0
--- ./automation/taskcluster/scripts/build_softoken.sh.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./automation/taskcluster/scripts/build_softoken.sh	2019-11-06 16:49:57.878508650 -0800
ddf7d0
@@ -20,8 +20,9 @@ export NSS_BUILD_SOFTOKEN_ONLY=1
ddf7d0
 rm -rf dist
ddf7d0
 make -C nss-softoken nss_build_all
ddf7d0
 
ddf7d0
-mv dist/private/nss/blapi.h dist/public/nss
ddf7d0
-mv dist/private/nss/alghmac.h dist/public/nss
ddf7d0
+for i in blapi alghmac cmac; do
ddf7d0
+    mv "dist/private/nss/${i}.h" dist/public/nss
ddf7d0
+done
ddf7d0
 
ddf7d0
 # Package.
ddf7d0
 test -d artifacts || mkdir artifacts
ddf7d0
diff -up ./cmd/lib/pk11table.c.cmac ./cmd/lib/pk11table.c
ddf7d0
--- ./cmd/lib/pk11table.c.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./cmd/lib/pk11table.c	2019-11-06 16:49:57.879508660 -0800
ddf7d0
@@ -333,6 +333,8 @@ const Constant _consts[] = {
ddf7d0
     mkEntry(CKM_SHA512, Mechanism),
ddf7d0
     mkEntry(CKM_SHA512_HMAC_GENERAL, Mechanism),
ddf7d0
     mkEntry(CKM_SHA512_HMAC, Mechanism),
ddf7d0
+    mkEntry(CKM_AES_CMAC, Mechanism),
ddf7d0
+    mkEntry(CKM_AES_CMAC_GENERAL, Mechanism),
ddf7d0
     mkEntry(CKM_CAST_KEY_GEN, Mechanism),
ddf7d0
     mkEntry(CKM_CAST_ECB, Mechanism),
ddf7d0
     mkEntry(CKM_CAST_CBC, Mechanism),
ddf7d0
diff -up ./cpputil/freebl_scoped_ptrs.h.cmac ./cpputil/freebl_scoped_ptrs.h
ddf7d0
--- ./cpputil/freebl_scoped_ptrs.h.cmac	2019-11-06 16:49:35.504266721 -0800
ddf7d0
+++ ./cpputil/freebl_scoped_ptrs.h	2019-11-06 16:49:35.504266721 -0800
ddf7d0
@@ -0,0 +1,33 @@
ddf7d0
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
ddf7d0
+/* vim: set ts=2 et sw=2 tw=80: */
ddf7d0
+/* This Source Code Form is subject to the terms of the Mozilla Public
ddf7d0
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
ddf7d0
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
ddf7d0
+
ddf7d0
+#ifndef freebl_scoped_ptrs_h__
ddf7d0
+#define freebl_scoped_ptrs_h__
ddf7d0
+
ddf7d0
+#include <memory>
ddf7d0
+#include "blapi.h"
ddf7d0
+
ddf7d0
+struct ScopedDelete {
ddf7d0
+  void operator()(CMACContext* ctx) { CMAC_Destroy(ctx, PR_TRUE); }
ddf7d0
+};
ddf7d0
+
ddf7d0
+template <class T>
ddf7d0
+struct ScopedMaybeDelete {
ddf7d0
+  void operator()(T* ptr) {
ddf7d0
+    if (ptr) {
ddf7d0
+      ScopedDelete del;
ddf7d0
+      del(ptr);
ddf7d0
+    }
ddf7d0
+  }
ddf7d0
+};
ddf7d0
+
ddf7d0
+#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
ddf7d0
+
ddf7d0
+SCOPED(CMACContext);
ddf7d0
+
ddf7d0
+#undef SCOPED
ddf7d0
+
ddf7d0
+#endif  // freebl_scoped_ptrs_h__
ddf7d0
diff -up ./gtests/freebl_gtest/cmac_unittests.cc.cmac ./gtests/freebl_gtest/cmac_unittests.cc
ddf7d0
--- ./gtests/freebl_gtest/cmac_unittests.cc.cmac	2019-11-06 16:49:35.504266721 -0800
ddf7d0
+++ ./gtests/freebl_gtest/cmac_unittests.cc	2019-11-06 16:49:35.504266721 -0800
ddf7d0
@@ -0,0 +1,187 @@
ddf7d0
+// This Source Code Form is subject to the terms of the Mozilla Public
ddf7d0
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
ddf7d0
+// You can obtain one at http://mozilla.org/MPL/2.0/.
ddf7d0
+
ddf7d0
+#include "gtest/gtest.h"
ddf7d0
+
ddf7d0
+#include <stdint.h>
ddf7d0
+#include <memory>
ddf7d0
+
ddf7d0
+#include "blapi.h"
ddf7d0
+#include "secitem.h"
ddf7d0
+#include "freebl_scoped_ptrs.h"
ddf7d0
+
ddf7d0
+class CmacAesTest : public ::testing::Test {
ddf7d0
+ protected:
ddf7d0
+  bool Compare(const uint8_t *actual, const uint8_t *expected,
ddf7d0
+               unsigned int length) {
ddf7d0
+    return strncmp((const char *)actual, (const char *)expected, length) == 0;
ddf7d0
+  }
ddf7d0
+};
ddf7d0
+
ddf7d0
+TEST_F(CmacAesTest, CreateInvalidSize) {
ddf7d0
+  uint8_t key[1] = {0x00};
ddf7d0
+  ScopedCMACContext ctx(CMAC_Create(CMAC_AES, key, sizeof(key)));
ddf7d0
+  ASSERT_EQ(ctx, nullptr);
ddf7d0
+}
ddf7d0
+
ddf7d0
+TEST_F(CmacAesTest, CreateRightSize) {
ddf7d0
+  uint8_t *key = PORT_NewArray(uint8_t, AES_128_KEY_LENGTH);
ddf7d0
+  ScopedCMACContext ctx(CMAC_Create(CMAC_AES, key, AES_128_KEY_LENGTH));
ddf7d0
+
ddf7d0
+  ASSERT_NE(ctx, nullptr);
ddf7d0
+  PORT_Free(key);
ddf7d0
+}
ddf7d0
+
ddf7d0
+// The following tests were taken from NIST's Cryptographic Standards and
ddf7d0
+// Guidelines page for AES-CMAC Examples with Intermediate Values. These same
ddf7d0
+// test vectors for AES-128 can be found in RFC 4493, Section 4.
ddf7d0
+
ddf7d0
+static const uint8_t kNistKeys[][AES_256_KEY_LENGTH] = {
ddf7d0
+    {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15,
ddf7d0
+     0x88, 0x09, 0xCF, 0x4F, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
ddf7d0
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
ddf7d0
+    {0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, 0xC8, 0x10, 0xF3,
ddf7d0
+     0x2B, 0x80, 0x90, 0x79, 0xE5, 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C,
ddf7d0
+     0x6B, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
ddf7d0
+    {0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 0x2B, 0x73, 0xAE,
ddf7d0
+     0xF0, 0x85, 0x7D, 0x77, 0x81, 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61,
ddf7d0
+     0x08, 0xD7, 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4}};
ddf7d0
+static const size_t kNistKeyLengthsCount = PR_ARRAY_SIZE(kNistKeys);
ddf7d0
+static const unsigned int kNistKeyLengths[kNistKeyLengthsCount] = {
ddf7d0
+    AES_128_KEY_LENGTH, AES_192_KEY_LENGTH, AES_256_KEY_LENGTH};
ddf7d0
+
ddf7d0
+static const uint8_t kNistPlaintext[64] = {
ddf7d0
+    0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E,
ddf7d0
+    0x11, 0x73, 0x93, 0x17, 0x2A, 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03,
ddf7d0
+    0xAC, 0x9C, 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, 0x30,
ddf7d0
+    0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, 0xE5, 0xFB, 0xC1, 0x19,
ddf7d0
+    0x1A, 0x0A, 0x52, 0xEF, 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B,
ddf7d0
+    0x17, 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10};
ddf7d0
+static const unsigned int kNistPlaintextLengths[] = {0, 16, 20, 64};
ddf7d0
+static const size_t kNistPlaintextLengthsCount =
ddf7d0
+    PR_ARRAY_SIZE(kNistPlaintextLengths);
ddf7d0
+
ddf7d0
+// This table contains the result of a CMAC over kNistPlaintext using keys from
ddf7d0
+// kNistKeys.  For each key, there are kNistPlaintextLengthsCount answers, all
ddf7d0
+// listed one after the other as the input is truncated to the different sizes
ddf7d0
+// in kNistPlaintextLengths.
ddf7d0
+static const uint8_t kNistKnown[][AES_BLOCK_SIZE] = {
ddf7d0
+    {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59, 0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
ddf7d0
+     0x9B, 0x75, 0x67, 0x46},
ddf7d0
+    {0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, 0xF7, 0x9B, 0xDD, 0x9D,
ddf7d0
+     0xD0, 0x4A, 0x28, 0x7C},
ddf7d0
+    {0x7D, 0x85, 0x44, 0x9E, 0xA6, 0xEA, 0x19, 0xC8, 0x23, 0xA7, 0xBF, 0x78,
ddf7d0
+     0x83, 0x7D, 0xFA, 0xDE},
ddf7d0
+    {0x51, 0xF0, 0xBE, 0xBF, 0x7E, 0x3B, 0x9D, 0x92, 0xFC, 0x49, 0x74, 0x17,
ddf7d0
+     0x79, 0x36, 0x3C, 0xFE},
ddf7d0
+    {0xD1, 0x7D, 0xDF, 0x46, 0xAD, 0xAA, 0xCD, 0xE5, 0x31, 0xCA, 0xC4, 0x83,
ddf7d0
+     0xDE, 0x7A, 0x93, 0x67},
ddf7d0
+    {0x9E, 0x99, 0xA7, 0xBF, 0x31, 0xE7, 0x10, 0x90, 0x06, 0x62, 0xF6, 0x5E,
ddf7d0
+     0x61, 0x7C, 0x51, 0x84},
ddf7d0
+    {0x3D, 0x75, 0xC1, 0x94, 0xED, 0x96, 0x07, 0x04, 0x44, 0xA9, 0xFA, 0x7E,
ddf7d0
+     0xC7, 0x40, 0xEC, 0xF8},
ddf7d0
+    {0xA1, 0xD5, 0xDF, 0x0E, 0xED, 0x79, 0x0F, 0x79, 0x4D, 0x77, 0x58, 0x96,
ddf7d0
+     0x59, 0xF3, 0x9A, 0x11},
ddf7d0
+    {0x02, 0x89, 0x62, 0xF6, 0x1B, 0x7B, 0xF8, 0x9E, 0xFC, 0x6B, 0x55, 0x1F,
ddf7d0
+     0x46, 0x67, 0xD9, 0x83},
ddf7d0
+    {0x28, 0xA7, 0x02, 0x3F, 0x45, 0x2E, 0x8F, 0x82, 0xBD, 0x4B, 0xF2, 0x8D,
ddf7d0
+     0x8C, 0x37, 0xC3, 0x5C},
ddf7d0
+    {0x15, 0x67, 0x27, 0xDC, 0x08, 0x78, 0x94, 0x4A, 0x02, 0x3C, 0x1F, 0xE0,
ddf7d0
+     0x3B, 0xAD, 0x6D, 0x93},
ddf7d0
+    {0xE1, 0x99, 0x21, 0x90, 0x54, 0x9F, 0x6E, 0xD5, 0x69, 0x6A, 0x2C, 0x05,
ddf7d0
+     0x6C, 0x31, 0x54, 0x10}};
ddf7d0
+PR_STATIC_ASSERT(PR_ARRAY_SIZE(kNistKnown) ==
ddf7d0
+                 kNistKeyLengthsCount * kNistPlaintextLengthsCount);
ddf7d0
+
ddf7d0
+TEST_F(CmacAesTest, AesNistAligned) {
ddf7d0
+  for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
ddf7d0
+       key_index++) {
ddf7d0
+    ScopedCMACContext ctx(CMAC_Create(CMAC_AES, kNistKeys[key_index],
ddf7d0
+                                      kNistKeyLengths[key_index]));
ddf7d0
+    ASSERT_NE(ctx, nullptr);
ddf7d0
+
ddf7d0
+    for (unsigned int plaintext_index = 0;
ddf7d0
+         plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
ddf7d0
+      CMAC_Begin(ctx.get());
ddf7d0
+
ddf7d0
+      unsigned int known_index =
ddf7d0
+          (key_index * kNistPlaintextLengthsCount) + plaintext_index;
ddf7d0
+      CMAC_Update(ctx.get(), kNistPlaintext,
ddf7d0
+                  kNistPlaintextLengths[plaintext_index]);
ddf7d0
+
ddf7d0
+      uint8_t output[AES_BLOCK_SIZE];
ddf7d0
+      CMAC_Finish(ctx.get(), output, NULL, AES_BLOCK_SIZE);
ddf7d0
+
ddf7d0
+      ASSERT_TRUE(Compare(output, kNistKnown[known_index], AES_BLOCK_SIZE));
ddf7d0
+    }
ddf7d0
+  }
ddf7d0
+}
ddf7d0
+
ddf7d0
+TEST_F(CmacAesTest, AesNistUnaligned) {
ddf7d0
+  for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
ddf7d0
+       key_index++) {
ddf7d0
+    unsigned int key_length = kNistKeyLengths[key_index];
ddf7d0
+    ScopedCMACContext ctx(
ddf7d0
+        CMAC_Create(CMAC_AES, kNistKeys[key_index], key_length));
ddf7d0
+    ASSERT_NE(ctx, nullptr);
ddf7d0
+
ddf7d0
+    // Skip the zero-length test.
ddf7d0
+    for (unsigned int plaintext_index = 1;
ddf7d0
+         plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
ddf7d0
+      unsigned int known_index =
ddf7d0
+          (key_index * kNistPlaintextLengthsCount) + plaintext_index;
ddf7d0
+      unsigned int plaintext_length = kNistPlaintextLengths[plaintext_index];
ddf7d0
+
ddf7d0
+      // Test all possible offsets and make sure that misaligned updates
ddf7d0
+      // produce the desired result. That is, do two updates:
ddf7d0
+      //  0      ... offset
ddf7d0
+      //  offset ... len - offset
ddf7d0
+      // and ensure the result is the same as doing one update.
ddf7d0
+      for (unsigned int offset = 1; offset < plaintext_length; offset++) {
ddf7d0
+        CMAC_Begin(ctx.get());
ddf7d0
+
ddf7d0
+        CMAC_Update(ctx.get(), kNistPlaintext, offset);
ddf7d0
+        CMAC_Update(ctx.get(), kNistPlaintext + offset,
ddf7d0
+                    plaintext_length - offset);
ddf7d0
+
ddf7d0
+        uint8_t output[AES_BLOCK_SIZE];
ddf7d0
+        CMAC_Finish(ctx.get(), output, NULL, AES_BLOCK_SIZE);
ddf7d0
+
ddf7d0
+        ASSERT_TRUE(Compare(output, kNistKnown[known_index], AES_BLOCK_SIZE));
ddf7d0
+      }
ddf7d0
+    }
ddf7d0
+  }
ddf7d0
+}
ddf7d0
+
ddf7d0
+TEST_F(CmacAesTest, AesNistTruncated) {
ddf7d0
+  for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
ddf7d0
+       key_index++) {
ddf7d0
+    unsigned int key_length = kNistKeyLengths[key_index];
ddf7d0
+    ScopedCMACContext ctx(
ddf7d0
+        CMAC_Create(CMAC_AES, kNistKeys[key_index], key_length));
ddf7d0
+    ASSERT_TRUE(ctx != nullptr);
ddf7d0
+
ddf7d0
+    // Skip the zero-length test.
ddf7d0
+    for (unsigned int plaintext_index = 1;
ddf7d0
+         plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
ddf7d0
+      unsigned int known_index =
ddf7d0
+          (key_index * kNistPlaintextLengthsCount) + plaintext_index;
ddf7d0
+      unsigned int plaintext_length = kNistPlaintextLengths[plaintext_index];
ddf7d0
+
ddf7d0
+      // Test truncated outputs to ensure that we always get the desired values.
ddf7d0
+      for (unsigned int out_len = 1; out_len < AES_BLOCK_SIZE; out_len++) {
ddf7d0
+        CMAC_Begin(ctx.get());
ddf7d0
+
ddf7d0
+        CMAC_Update(ctx.get(), kNistPlaintext, plaintext_length);
ddf7d0
+
ddf7d0
+        unsigned int actual_out_len = 0;
ddf7d0
+        uint8_t output[AES_BLOCK_SIZE];
ddf7d0
+        CMAC_Finish(ctx.get(), output, &actual_out_len, out_len);
ddf7d0
+
ddf7d0
+        ASSERT_TRUE(actual_out_len == out_len);
ddf7d0
+        ASSERT_TRUE(Compare(output, kNistKnown[known_index], out_len));
ddf7d0
+      }
ddf7d0
+    }
ddf7d0
+  }
ddf7d0
+}
ddf7d0
diff -up ./gtests/freebl_gtest/freebl_gtest.gyp.cmac ./gtests/freebl_gtest/freebl_gtest.gyp
ddf7d0
--- ./gtests/freebl_gtest/freebl_gtest.gyp.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./gtests/freebl_gtest/freebl_gtest.gyp	2019-11-06 16:49:35.617267943 -0800
ddf7d0
@@ -34,6 +34,7 @@
ddf7d0
         'ecl_unittest.cc',
ddf7d0
         'ghash_unittest.cc',
ddf7d0
         'rsa_unittest.cc',
ddf7d0
+        'cmac_unittests.cc',
ddf7d0
         '<(DEPTH)/gtests/common/gtests.cc'
ddf7d0
       ],
ddf7d0
       'dependencies': [
ddf7d0
diff -up ./gtests/pk11_gtest/manifest.mn.cmac ./gtests/pk11_gtest/manifest.mn
ddf7d0
diff -up ./gtests/pk11_gtest/pk11_aes_cmac_unittest.cc.cmac ./gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
ddf7d0
--- ./gtests/pk11_gtest/pk11_aes_cmac_unittest.cc.cmac	2019-11-06 16:49:57.879508660 -0800
ddf7d0
+++ ./gtests/pk11_gtest/pk11_aes_cmac_unittest.cc	2019-11-06 16:49:57.879508660 -0800
ddf7d0
@@ -0,0 +1,91 @@
ddf7d0
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
ddf7d0
+/* vim: set ts=2 et sw=2 tw=80: */
ddf7d0
+/* This Source Code Form is subject to the terms of the Mozilla Public
ddf7d0
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
ddf7d0
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
ddf7d0
+
ddf7d0
+#include <memory>
ddf7d0
+#include "nss.h"
ddf7d0
+#include "pk11pub.h"
ddf7d0
+#include "secerr.h"
ddf7d0
+#include "sechash.h"
ddf7d0
+
ddf7d0
+#include "blapi.h"
ddf7d0
+
ddf7d0
+#include "gtest/gtest.h"
ddf7d0
+#include "nss_scoped_ptrs.h"
ddf7d0
+#include "util.h"
ddf7d0
+
ddf7d0
+namespace nss_test {
ddf7d0
+
ddf7d0
+class Pkcs11AesCmacTest : public ::testing::Test {
ddf7d0
+ protected:
ddf7d0
+  ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) {
ddf7d0
+    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ddf7d0
+    if (!slot) {
ddf7d0
+      ADD_FAILURE() << "Can't get slot";
ddf7d0
+      return nullptr;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    ScopedPK11SymKey result(PK11_ImportSymKey(
ddf7d0
+        slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, key_item, nullptr));
ddf7d0
+
ddf7d0
+    return result;
ddf7d0
+  }
ddf7d0
+
ddf7d0
+  void RunTest(uint8_t *key, unsigned int key_len, uint8_t *data,
ddf7d0
+               unsigned int data_len, uint8_t *expected,
ddf7d0
+               unsigned int expected_len, CK_ULONG mechanism) {
ddf7d0
+    // Create SECItems for everything...
ddf7d0
+    std::vector<uint8_t> output(expected_len);
ddf7d0
+    SECItem key_item = {siBuffer, key, key_len};
ddf7d0
+    SECItem output_item = {siBuffer, output.data(), expected_len};
ddf7d0
+    SECItem data_item = {siBuffer, data, data_len};
ddf7d0
+    SECItem expected_item = {siBuffer, expected, expected_len};
ddf7d0
+
ddf7d0
+    // Do the PKCS #11 stuff...
ddf7d0
+    ScopedPK11SymKey p11_key = ImportKey(mechanism, &key_item);
ddf7d0
+    ASSERT_NE(nullptr, p11_key.get());
ddf7d0
+
ddf7d0
+    SECStatus ret = PK11_SignWithSymKey(p11_key.get(), CKM_AES_CMAC, NULL,
ddf7d0
+                                        &output_item, &data_item);
ddf7d0
+
ddf7d0
+    // Verify the result...
ddf7d0
+    ASSERT_EQ(SECSuccess, ret);
ddf7d0
+    ASSERT_EQ(0, SECITEM_CompareItem(&output_item, &expected_item));
ddf7d0
+  }
ddf7d0
+};
ddf7d0
+
ddf7d0
+// Sanity check of the PKCS #11 API only. Extensive tests for correctness of
ddf7d0
+// underling CMAC implementation conducted in the following file:
ddf7d0
+//      gtests/freebl_gtest/cmac_unittests.cc
ddf7d0
+
ddf7d0
+TEST_F(Pkcs11AesCmacTest, Aes128NistExample1) {
ddf7d0
+  uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
ddf7d0
+                                     0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
ddf7d0
+                                     0x09, 0xCF, 0x4F, 0x3C};
ddf7d0
+  uint8_t known[AES_BLOCK_SIZE] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59,
ddf7d0
+                                   0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
ddf7d0
+                                   0x9B, 0x75, 0x67, 0x46};
ddf7d0
+
ddf7d0
+  RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, AES_BLOCK_SIZE,
ddf7d0
+          CKM_AES_CMAC);
ddf7d0
+}
ddf7d0
+
ddf7d0
+TEST_F(Pkcs11AesCmacTest, General) {
ddf7d0
+  uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
ddf7d0
+                                     0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
ddf7d0
+                                     0x09, 0xCF, 0x4F, 0x3C};
ddf7d0
+  uint8_t known[4] = {0xBB, 0x1D, 0x69, 0x29};
ddf7d0
+
ddf7d0
+  RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, 4, CKM_AES_CMAC_GENERAL);
ddf7d0
+}
ddf7d0
+
ddf7d0
+TEST_F(Pkcs11AesCmacTest, InvalidKeySize) {
ddf7d0
+  uint8_t key[4] = {0x00, 0x00, 0x00, 0x00};
ddf7d0
+  SECItem key_item = {siBuffer, key, 4};
ddf7d0
+
ddf7d0
+  ScopedPK11SymKey result = ImportKey(CKM_AES_CMAC, &key_item);
ddf7d0
+  ASSERT_EQ(nullptr, result.get());
ddf7d0
+}
ddf7d0
+}
ddf7d0
diff -up ./gtests/pk11_gtest/pk11_gtest.gyp.cmac ./gtests/pk11_gtest/pk11_gtest.gyp
ddf7d0
--- ./gtests/pk11_gtest/pk11_gtest.gyp.cmac	2019-11-06 16:49:57.880508671 -0800
ddf7d0
+++ ./gtests/pk11_gtest/pk11_gtest.gyp	2019-11-06 17:12:07.541834483 -0800
ddf7d0
@@ -12,6 +12,7 @@
ddf7d0
       'type': 'executable',
ddf7d0
       'sources': [
ddf7d0
         'pk11_aeskeywrap_unittest.cc',
ddf7d0
+        'pk11_aes_cmac_unittest.cc',
ddf7d0
         'pk11_aes_gcm_unittest.cc',
ddf7d0
         'pk11_chacha20poly1305_unittest.cc',
ddf7d0
         'pk11_cipherop_unittest.cc',
ddf7d0
diff -up ./lib/freebl/blapi.h.cmac ./lib/freebl/blapi.h
ddf7d0
--- ./lib/freebl/blapi.h.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/blapi.h	2019-11-06 16:49:35.618267953 -0800
ddf7d0
@@ -10,6 +10,7 @@
ddf7d0
 
ddf7d0
 #include "blapit.h"
ddf7d0
 #include "hasht.h"
ddf7d0
+#include "cmac.h"
ddf7d0
 #include "alghmac.h"
ddf7d0
 
ddf7d0
 SEC_BEGIN_PROTOS
ddf7d0
diff -up ./lib/freebl/cmac.c.cmac ./lib/freebl/cmac.c
ddf7d0
--- ./lib/freebl/cmac.c.cmac	2019-11-06 16:49:35.620267975 -0800
ddf7d0
+++ ./lib/freebl/cmac.c	2019-11-06 16:49:35.620267975 -0800
ddf7d0
@@ -0,0 +1,322 @@
ddf7d0
+/* This Source Code Form is subject to the terms of the Mozilla Public
ddf7d0
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
ddf7d0
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
ddf7d0
+
ddf7d0
+#ifdef FREEBL_NO_DEPEND
ddf7d0
+#include "stubs.h"
ddf7d0
+#endif
ddf7d0
+
ddf7d0
+#include "rijndael.h"
ddf7d0
+#include "blapi.h"
ddf7d0
+#include "cmac.h"
ddf7d0
+#include "secerr.h"
ddf7d0
+#include "nspr.h"
ddf7d0
+
ddf7d0
+struct CMACContextStr {
ddf7d0
+    /* Information about the block cipher to use internally. The cipher should
ddf7d0
+     * be placed in ECB mode so that we can use it to directly encrypt blocks.
ddf7d0
+     *
ddf7d0
+     *
ddf7d0
+     * To add a new cipher, add an entry to CMACCipher, update CMAC_Init,
ddf7d0
+     * cmac_Encrypt, and CMAC_Destroy methods to handle the new cipher, and
ddf7d0
+     * add a new Context pointer to the cipher union with the correct type. */
ddf7d0
+    CMACCipher cipherType;
ddf7d0
+    union {
ddf7d0
+        AESContext aes;
ddf7d0
+    } cipher;
ddf7d0
+    int blockSize;
ddf7d0
+
ddf7d0
+    /* Internal keys which are conditionally used by the algorithm. Derived
ddf7d0
+     * from encrypting the NULL block. We leave the storing of (and the
ddf7d0
+     * cleanup of) the CMAC key to the underlying block cipher. */
ddf7d0
+    unsigned char k1[MAX_BLOCK_SIZE];
ddf7d0
+    unsigned char k2[MAX_BLOCK_SIZE];
ddf7d0
+
ddf7d0
+    /* When Update is called with data which isn't a multiple of the block
ddf7d0
+     * size, we need a place to put it. HMAC handles this by passing it to
ddf7d0
+     * the underlying hash function right away; we can't do that as the
ddf7d0
+     * contract on the cipher object is different. */
ddf7d0
+    unsigned int partialIndex;
ddf7d0
+    unsigned char partialBlock[MAX_BLOCK_SIZE];
ddf7d0
+
ddf7d0
+    /* Last encrypted block. This gets xor-ed with partialBlock prior to
ddf7d0
+     * encrypting it. NIST defines this to be the empty string to begin. */
ddf7d0
+    unsigned char lastBlock[MAX_BLOCK_SIZE];
ddf7d0
+};
ddf7d0
+
ddf7d0
+static void
ddf7d0
+cmac_ShiftLeftOne(unsigned char *out, const unsigned char *in, int length)
ddf7d0
+{
ddf7d0
+    int i = 0;
ddf7d0
+    for (; i < length - 1; i++) {
ddf7d0
+        out[i] = in[i] << 1;
ddf7d0
+        out[i] |= in[i + 1] >> 7;
ddf7d0
+    }
ddf7d0
+    out[i] = in[i] << 1;
ddf7d0
+}
ddf7d0
+
ddf7d0
+static SECStatus
ddf7d0
+cmac_Encrypt(CMACContext *ctx, unsigned char *output,
ddf7d0
+             const unsigned char *input,
ddf7d0
+             unsigned int inputLen)
ddf7d0
+{
ddf7d0
+    if (ctx->cipherType == CMAC_AES) {
ddf7d0
+        unsigned int tmpOutputLen;
ddf7d0
+        SECStatus rv = AES_Encrypt(&ctx->cipher.aes, output, &tmpOutputLen,
ddf7d0
+                                   ctx->blockSize, input, inputLen);
ddf7d0
+
ddf7d0
+        /* Assumption: AES_Encrypt (when in ECB mode) always returns an
ddf7d0
+         * output of length equal to blockSize (what was pass as the value
ddf7d0
+         * of the maxOutputLen parameter). */
ddf7d0
+        PORT_Assert(tmpOutputLen == ctx->blockSize);
ddf7d0
+        return rv;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    return SECFailure;
ddf7d0
+}
ddf7d0
+
ddf7d0
+/* NIST SP.800-38B, 6.1 Subkey Generation */
ddf7d0
+static SECStatus
ddf7d0
+cmac_GenerateSubkeys(CMACContext *ctx)
ddf7d0
+{
ddf7d0
+    unsigned char null_block[MAX_BLOCK_SIZE] = { 0 };
ddf7d0
+    unsigned char L[MAX_BLOCK_SIZE];
ddf7d0
+    unsigned char v;
ddf7d0
+    unsigned char i;
ddf7d0
+
ddf7d0
+    /* Step 1: L = AES(key, null_block) */
ddf7d0
+    if (cmac_Encrypt(ctx, L, null_block, ctx->blockSize) != SECSuccess) {
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* In the following, some effort has been made to be constant time. Rather
ddf7d0
+     * than conditioning on the value of the MSB (of L or K1), we use the loop
ddf7d0
+     * to build a mask for the conditional constant. */
ddf7d0
+
ddf7d0
+    /* Step 2: If MSB(L) = 0, K1 = L << 1. Else, K1 = (L << 1) ^ R_b. */
ddf7d0
+    cmac_ShiftLeftOne(ctx->k1, L, ctx->blockSize);
ddf7d0
+    v = L[0] >> 7;
ddf7d0
+    for (i = 1; i <= 7; i <<= 1) {
ddf7d0
+        v |= (v << i);
ddf7d0
+    }
ddf7d0
+    ctx->k1[ctx->blockSize - 1] ^= (0x87 & v);
ddf7d0
+
ddf7d0
+    /* Step 3: If MSB(K1) = 0, K2 = K1 << 1. Else, K2 = (K1 <, 1) ^ R_b. */
ddf7d0
+    cmac_ShiftLeftOne(ctx->k2, ctx->k1, ctx->blockSize);
ddf7d0
+    v = ctx->k1[0] >> 7;
ddf7d0
+    for (i = 1; i <= 7; i <<= 1) {
ddf7d0
+        v |= (v << i);
ddf7d0
+    }
ddf7d0
+    ctx->k2[ctx->blockSize - 1] ^= (0x87 & v);
ddf7d0
+
ddf7d0
+    /* Any intermediate value in the computation of the subkey shall be
ddf7d0
+     * secret. */
ddf7d0
+    PORT_Memset(null_block, 0, MAX_BLOCK_SIZE);
ddf7d0
+    PORT_Memset(L, 0, MAX_BLOCK_SIZE);
ddf7d0
+
ddf7d0
+    /* Step 4: Return the values. */
ddf7d0
+    return SECSuccess;
ddf7d0
+}
ddf7d0
+
ddf7d0
+/* NIST SP.800-38B, 6.2 MAC Generation step 6 */
ddf7d0
+static SECStatus
ddf7d0
+cmac_UpdateState(CMACContext *ctx)
ddf7d0
+{
ddf7d0
+    if (ctx == NULL || ctx->partialIndex != ctx->blockSize) {
ddf7d0
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Step 6: C_i = CIPHER(key, C_{i-1} ^ M_i)  for 1 <= i <= n, and
ddf7d0
+     *         C_0 is defined as the empty string. */
ddf7d0
+
ddf7d0
+    for (unsigned int index = 0; index < ctx->blockSize; index++) {
ddf7d0
+        ctx->partialBlock[index] ^= ctx->lastBlock[index];
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    return cmac_Encrypt(ctx, ctx->lastBlock, ctx->partialBlock, ctx->blockSize);
ddf7d0
+}
ddf7d0
+
ddf7d0
+SECStatus
ddf7d0
+CMAC_Init(CMACContext *ctx, CMACCipher type,
ddf7d0
+          const unsigned char *key, unsigned int key_len)
ddf7d0
+{
ddf7d0
+    if (ctx == NULL) {
ddf7d0
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* We only currently support AES-CMAC. */
ddf7d0
+    if (type != CMAC_AES) {
ddf7d0
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    PORT_Memset(ctx, 0, sizeof(*ctx));
ddf7d0
+
ddf7d0
+    ctx->blockSize = AES_BLOCK_SIZE;
ddf7d0
+    ctx->cipherType = CMAC_AES;
ddf7d0
+    if (AES_InitContext(&ctx->cipher.aes, key, key_len, NULL, NSS_AES, 1,
ddf7d0
+                        ctx->blockSize) != SECSuccess) {
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    return CMAC_Begin(ctx);
ddf7d0
+}
ddf7d0
+
ddf7d0
+CMACContext *
ddf7d0
+CMAC_Create(CMACCipher type, const unsigned char *key,
ddf7d0
+            unsigned int key_len)
ddf7d0
+{
ddf7d0
+    CMACContext *result = PORT_New(CMACContext);
ddf7d0
+
ddf7d0
+    if (CMAC_Init(result, type, key, key_len) != SECSuccess) {
ddf7d0
+        CMAC_Destroy(result, PR_TRUE);
ddf7d0
+        return NULL;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    return result;
ddf7d0
+}
ddf7d0
+
ddf7d0
+SECStatus
ddf7d0
+CMAC_Begin(CMACContext *ctx)
ddf7d0
+{
ddf7d0
+    if (ctx == NULL) {
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Ensure that our blockSize is less than the maximum. When this fails,
ddf7d0
+     * a cipher with a larger block size was added and MAX_BLOCK_SIZE needs
ddf7d0
+     * to be updated accordingly. */
ddf7d0
+    PORT_Assert(ctx->blockSize <= MAX_BLOCK_SIZE);
ddf7d0
+
ddf7d0
+    if (cmac_GenerateSubkeys(ctx) != SECSuccess) {
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Set the index to write partial blocks at to zero. This saves us from
ddf7d0
+     * having to clear ctx->partialBlock. */
ddf7d0
+    ctx->partialIndex = 0;
ddf7d0
+
ddf7d0
+    /* Step 5: Let C_0 = 0^b. */
ddf7d0
+    PORT_Memset(ctx->lastBlock, 0, ctx->blockSize);
ddf7d0
+
ddf7d0
+    return SECSuccess;
ddf7d0
+}
ddf7d0
+
ddf7d0
+/* NIST SP.800-38B, 6.2 MAC Generation */
ddf7d0
+SECStatus
ddf7d0
+CMAC_Update(CMACContext *ctx, const unsigned char *data,
ddf7d0
+            unsigned int data_len)
ddf7d0
+{
ddf7d0
+    int data_index = 0;
ddf7d0
+    if (ctx == NULL) {
ddf7d0
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (data == NULL || data_len == 0) {
ddf7d0
+        return SECSuccess;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Copy as many bytes from data into ctx->partialBlock as we can, up to
ddf7d0
+     * the maximum of the remaining data and the remaining space in
ddf7d0
+     * ctx->partialBlock.
ddf7d0
+     *
ddf7d0
+     * Note that we swap the order (encrypt *then* copy) because the last
ddf7d0
+     * block is different from the rest. If we end on an even multiple of
ddf7d0
+     * the block size, we have to be able to XOR it with K1. But we won't know
ddf7d0
+     * that it is the last until CMAC_Finish is called (and by then, CMAC_Update
ddf7d0
+     * has already returned). */
ddf7d0
+    while (data_index < data_len) {
ddf7d0
+        if (ctx->partialIndex == ctx->blockSize) {
ddf7d0
+            if (cmac_UpdateState(ctx) != SECSuccess) {
ddf7d0
+                return SECFailure;
ddf7d0
+            }
ddf7d0
+
ddf7d0
+            ctx->partialIndex = 0;
ddf7d0
+        }
ddf7d0
+
ddf7d0
+        unsigned int copy_len = data_len - data_index;
ddf7d0
+        if (copy_len > (ctx->blockSize - ctx->partialIndex)) {
ddf7d0
+            copy_len = ctx->blockSize - ctx->partialIndex;
ddf7d0
+        }
ddf7d0
+
ddf7d0
+        PORT_Memcpy(ctx->partialBlock + ctx->partialIndex, data + data_index, copy_len);
ddf7d0
+        data_index += copy_len;
ddf7d0
+        ctx->partialIndex += copy_len;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    return SECSuccess;
ddf7d0
+}
ddf7d0
+
ddf7d0
+/* NIST SP.800-38B, 6.2 MAC Generation */
ddf7d0
+SECStatus
ddf7d0
+CMAC_Finish(CMACContext *ctx, unsigned char *result,
ddf7d0
+            unsigned int *result_len,
ddf7d0
+            unsigned int max_result_len)
ddf7d0
+{
ddf7d0
+    if (ctx == NULL || result == NULL || max_result_len == 0) {
ddf7d0
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (max_result_len > ctx->blockSize) {
ddf7d0
+        /* This is a weird situation. The PKCS #11 soft tokencode passes
ddf7d0
+         * sizeof(result) here, which is hard-coded as SFTK_MAX_MAC_LENGTH.
ddf7d0
+         * This later gets truncated to min(SFTK_MAX_MAC_LENGTH, requested). */
ddf7d0
+        max_result_len = ctx->blockSize;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Step 4: If M_n* is a complete block, M_n = K1 ^ M_n*. Else,
ddf7d0
+     * M_n = K2 ^ (M_n* || 10^j). */
ddf7d0
+    if (ctx->partialIndex == ctx->blockSize) {
ddf7d0
+        /* XOR in K1. */
ddf7d0
+        for (unsigned int index = 0; index < ctx->blockSize; index++) {
ddf7d0
+            ctx->partialBlock[index] ^= ctx->k1[index];
ddf7d0
+        }
ddf7d0
+    } else {
ddf7d0
+        /* Use 10* padding on the partial block. */
ddf7d0
+        ctx->partialBlock[ctx->partialIndex++] = 0x80;
ddf7d0
+        PORT_Memset(ctx->partialBlock + ctx->partialIndex, 0,
ddf7d0
+                    ctx->blockSize - ctx->partialIndex);
ddf7d0
+        ctx->partialIndex = ctx->blockSize;
ddf7d0
+
ddf7d0
+        /* XOR in K2. */
ddf7d0
+        for (unsigned int index = 0; index < ctx->blockSize; index++) {
ddf7d0
+            ctx->partialBlock[index] ^= ctx->k2[index];
ddf7d0
+        }
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Encrypt the block. */
ddf7d0
+    if (cmac_UpdateState(ctx) != SECSuccess) {
ddf7d0
+        return SECFailure;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Step 7 & 8: T = MSB_tlen(C_n); return T. */
ddf7d0
+    PORT_Memcpy(result, ctx->lastBlock, max_result_len);
ddf7d0
+    if (result_len != NULL) {
ddf7d0
+        *result_len = max_result_len;
ddf7d0
+    }
ddf7d0
+    return SECSuccess;
ddf7d0
+}
ddf7d0
+
ddf7d0
+void
ddf7d0
+CMAC_Destroy(CMACContext *ctx, PRBool free_it)
ddf7d0
+{
ddf7d0
+    if (ctx == NULL) {
ddf7d0
+        return;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (ctx->cipherType == CMAC_AES) {
ddf7d0
+        AES_DestroyContext(&ctx->cipher.aes, PR_FALSE);
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Destroy everything in the context. This includes sensitive data in
ddf7d0
+     * K1, K2, and lastBlock. */
ddf7d0
+    PORT_Memset(ctx, 0, sizeof(*ctx));
ddf7d0
+
ddf7d0
+    if (free_it == PR_TRUE) {
ddf7d0
+        PORT_Free(ctx);
ddf7d0
+    }
ddf7d0
+}
ddf7d0
diff -up ./lib/freebl/cmac.h.cmac ./lib/freebl/cmac.h
ddf7d0
--- ./lib/freebl/cmac.h.cmac	2019-11-06 16:49:35.621267986 -0800
ddf7d0
+++ ./lib/freebl/cmac.h	2019-11-06 16:49:35.621267986 -0800
ddf7d0
@@ -0,0 +1,47 @@
ddf7d0
+/* This Source Code Form is subject to the terms of the Mozilla Public
ddf7d0
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
ddf7d0
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
ddf7d0
+
ddf7d0
+#ifndef _CMAC_H_
ddf7d0
+#define _CMAC_H_
ddf7d0
+
ddf7d0
+typedef struct CMACContextStr CMACContext;
ddf7d0
+
ddf7d0
+SEC_BEGIN_PROTOS
ddf7d0
+
ddf7d0
+/* Enum for identifying the underlying block cipher we're using internally. */
ddf7d0
+typedef enum {
ddf7d0
+    CMAC_AES = 0
ddf7d0
+} CMACCipher;
ddf7d0
+
ddf7d0
+/* Initialize an existing CMACContext struct. */
ddf7d0
+SECStatus CMAC_Init(CMACContext *ctx, CMACCipher type,
ddf7d0
+                    const unsigned char *key, unsigned int key_len);
ddf7d0
+
ddf7d0
+/* Allocate and initialize a new CMAC context with the specified cipher and
ddf7d0
+ * key. */
ddf7d0
+CMACContext *CMAC_Create(CMACCipher type, const unsigned char *key,
ddf7d0
+                         unsigned int key_len);
ddf7d0
+
ddf7d0
+/* Called automatically by CMAC_*{Create,Init}(...). Only useful for restarting
ddf7d0
+ * an already-started CMAC instance. */
ddf7d0
+SECStatus CMAC_Begin(CMACContext *ctx);
ddf7d0
+
ddf7d0
+/* Add the specified bytes into the CMAC state. */
ddf7d0
+SECStatus CMAC_Update(CMACContext *ctx, const unsigned char *data,
ddf7d0
+                      unsigned int data_len);
ddf7d0
+
ddf7d0
+/* Finalize the CMAC state and return the result. */
ddf7d0
+SECStatus CMAC_Finish(CMACContext *ctx, unsigned char *result,
ddf7d0
+                      unsigned int *result_len,
ddf7d0
+                      unsigned int max_result_len);
ddf7d0
+
ddf7d0
+/* Note: CMAC_Clone isn't implemented here because AES doesn't expose a
ddf7d0
+ * context-cloning operation. */
ddf7d0
+
ddf7d0
+/* Destroy a CMAC context, optionally freeing it. */
ddf7d0
+void CMAC_Destroy(CMACContext *ctx, PRBool free_it);
ddf7d0
+
ddf7d0
+SEC_END_PROTOS
ddf7d0
+
ddf7d0
+#endif
ddf7d0
diff -up ./lib/freebl/exports.gyp.cmac ./lib/freebl/exports.gyp
ddf7d0
--- ./lib/freebl/exports.gyp.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/exports.gyp	2019-11-06 16:49:35.621267986 -0800
ddf7d0
@@ -27,6 +27,7 @@
ddf7d0
         },
ddf7d0
         {
ddf7d0
           'files': [
ddf7d0
+            'cmac.h',
ddf7d0
             'alghmac.h',
ddf7d0
             'blapi.h',
ddf7d0
             'blake2b.h',
ddf7d0
diff -up ./lib/freebl/freebl_base.gypi.cmac ./lib/freebl/freebl_base.gypi
ddf7d0
--- ./lib/freebl/freebl_base.gypi.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/freebl_base.gypi	2019-11-06 16:49:35.622267997 -0800
ddf7d0
@@ -5,6 +5,7 @@
ddf7d0
   'sources': [
ddf7d0
     'aeskeywrap.c',
ddf7d0
     'alg2268.c',
ddf7d0
+    'cmac.c',
ddf7d0
     'alghmac.c',
ddf7d0
     'arcfive.c',
ddf7d0
     'arcfour.c',
ddf7d0
diff -up ./lib/freebl/ldvector.c.cmac ./lib/freebl/ldvector.c
ddf7d0
--- ./lib/freebl/ldvector.c.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/ldvector.c	2019-11-06 16:49:35.623268007 -0800
ddf7d0
@@ -10,6 +10,7 @@ extern int FREEBL_InitStubs(void);
ddf7d0
 #endif
ddf7d0
 
ddf7d0
 #include "loader.h"
ddf7d0
+#include "cmac.h"
ddf7d0
 #include "alghmac.h"
ddf7d0
 #include "hmacct.h"
ddf7d0
 #include "blapii.h"
ddf7d0
@@ -317,10 +318,18 @@ static const struct FREEBLVectorStr vect
ddf7d0
 
ddf7d0
       /* End of Version 3.020 */
ddf7d0
 
ddf7d0
-      ChaCha20_Xor
ddf7d0
+      ChaCha20_Xor,
ddf7d0
 
ddf7d0
       /* End of version 3.021 */
ddf7d0
 
ddf7d0
+      CMAC_Init,
ddf7d0
+      CMAC_Create,
ddf7d0
+      CMAC_Begin,
ddf7d0
+      CMAC_Update,
ddf7d0
+      CMAC_Finish,
ddf7d0
+      CMAC_Destroy
ddf7d0
+
ddf7d0
+      /* End of version 3.022 */
ddf7d0
     };
ddf7d0
 
ddf7d0
 const FREEBLVector*
ddf7d0
diff -up ./lib/freebl/loader.c.cmac ./lib/freebl/loader.c
ddf7d0
--- ./lib/freebl/loader.c.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/loader.c	2019-11-06 16:49:35.624268018 -0800
ddf7d0
@@ -2245,3 +2245,54 @@ BLAKE2B_Resurrect(unsigned char *space,
ddf7d0
     }
ddf7d0
     return (vector->p_BLAKE2B_Resurrect)(space, arg);
ddf7d0
 }
ddf7d0
+
ddf7d0
+/* == New for CMAC == */
ddf7d0
+SECStatus
ddf7d0
+CMAC_Init(CMACContext *ctx, CMACCipher type, const unsigned char *key,
ddf7d0
+          unsigned int key_len)
ddf7d0
+{
ddf7d0
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
ddf7d0
+        return SECFailure;
ddf7d0
+    return (vector->p_CMAC_Init)(ctx, type, key, key_len);
ddf7d0
+}
ddf7d0
+
ddf7d0
+CMACContext *
ddf7d0
+CMAC_Create(CMACCipher type, const unsigned char *key, unsigned int key_len)
ddf7d0
+{
ddf7d0
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
ddf7d0
+        return NULL;
ddf7d0
+    return (vector->p_CMAC_Create)(type, key, key_len);
ddf7d0
+}
ddf7d0
+
ddf7d0
+SECStatus
ddf7d0
+CMAC_Begin(CMACContext *ctx)
ddf7d0
+{
ddf7d0
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
ddf7d0
+        return SECFailure;
ddf7d0
+    return (vector->p_CMAC_Begin)(ctx);
ddf7d0
+}
ddf7d0
+
ddf7d0
+SECStatus
ddf7d0
+CMAC_Update(CMACContext *ctx, const unsigned char *data, unsigned int data_len)
ddf7d0
+{
ddf7d0
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
ddf7d0
+        return SECFailure;
ddf7d0
+    return (vector->p_CMAC_Update)(ctx, data, data_len);
ddf7d0
+}
ddf7d0
+
ddf7d0
+SECStatus
ddf7d0
+CMAC_Finish(CMACContext *ctx, unsigned char *result, unsigned int *result_len,
ddf7d0
+            unsigned int max_result_len)
ddf7d0
+{
ddf7d0
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
ddf7d0
+        return SECFailure;
ddf7d0
+    return (vector->p_CMAC_Finish)(ctx, result, result_len, max_result_len);
ddf7d0
+}
ddf7d0
+
ddf7d0
+void
ddf7d0
+CMAC_Destroy(CMACContext *ctx, PRBool free_it)
ddf7d0
+{
ddf7d0
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
ddf7d0
+        return;
ddf7d0
+    (vector->p_CMAC_Destroy)(ctx, free_it);
ddf7d0
+}
ddf7d0
diff -up ./lib/freebl/loader.h.cmac ./lib/freebl/loader.h
ddf7d0
--- ./lib/freebl/loader.h.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/loader.h	2019-11-06 16:49:35.625268029 -0800
ddf7d0
@@ -10,7 +10,7 @@
ddf7d0
 
ddf7d0
 #include "blapi.h"
ddf7d0
 
ddf7d0
-#define FREEBL_VERSION 0x0315
ddf7d0
+#define FREEBL_VERSION 0x0316
ddf7d0
 
ddf7d0
 struct FREEBLVectorStr {
ddf7d0
 
ddf7d0
@@ -765,6 +765,20 @@ struct FREEBLVectorStr {
ddf7d0
 
ddf7d0
     /* Version 3.021 came to here */
ddf7d0
 
ddf7d0
+    SECStatus (*p_CMAC_Init)(CMACContext *ctx, CMACCipher type,
ddf7d0
+                             const unsigned char *key, unsigned int key_len);
ddf7d0
+    CMACContext *(*p_CMAC_Create)(CMACCipher type, const unsigned char *key,
ddf7d0
+                                  unsigned int key_len);
ddf7d0
+    SECStatus (*p_CMAC_Begin)(CMACContext *ctx);
ddf7d0
+    SECStatus (*p_CMAC_Update)(CMACContext *ctx, const unsigned char *data,
ddf7d0
+                               unsigned int data_len);
ddf7d0
+    SECStatus (*p_CMAC_Finish)(CMACContext *ctx, unsigned char *result,
ddf7d0
+                               unsigned int *result_len,
ddf7d0
+                               unsigned int max_result_len);
ddf7d0
+    void (*p_CMAC_Destroy)(CMACContext *ctx, PRBool free_it);
ddf7d0
+
ddf7d0
+    /* Version 3.022 came to here */
ddf7d0
+
ddf7d0
     /* Add new function pointers at the end of this struct and bump
ddf7d0
      * FREEBL_VERSION at the beginning of this file. */
ddf7d0
 };
ddf7d0
diff -up ./lib/freebl/manifest.mn.cmac ./lib/freebl/manifest.mn
ddf7d0
--- ./lib/freebl/manifest.mn.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/freebl/manifest.mn	2019-11-06 16:49:35.626268040 -0800
ddf7d0
@@ -85,6 +85,7 @@ EXPORTS = \
ddf7d0
 	$(NULL)
ddf7d0
 
ddf7d0
 PRIVATE_EXPORTS = \
ddf7d0
+	cmac.h \
ddf7d0
 	alghmac.h \
ddf7d0
 	blake2b.h \
ddf7d0
 	blapi.h \
ddf7d0
@@ -119,6 +120,7 @@ CSRCS = \
ddf7d0
 	md2.c \
ddf7d0
 	md5.c \
ddf7d0
 	sha512.c \
ddf7d0
+	cmac.c \
ddf7d0
 	alghmac.c \
ddf7d0
 	rawhash.c \
ddf7d0
 	alg2268.c \
ddf7d0
@@ -162,6 +164,7 @@ CSRCS = \
ddf7d0
 ALL_CSRCS := $(CSRCS)
ddf7d0
 
ddf7d0
 ALL_HDRS =  \
ddf7d0
+	cmac.h \
ddf7d0
 	alghmac.h \
ddf7d0
 	blake2b.h \
ddf7d0
 	blapi.h \
ddf7d0
diff -up ./lib/pk11wrap/debug_module.c.cmac ./lib/pk11wrap/debug_module.c
ddf7d0
--- ./lib/pk11wrap/debug_module.c.cmac	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/pk11wrap/debug_module.c	2019-11-06 16:49:57.881508682 -0800
ddf7d0
@@ -376,6 +376,8 @@ print_mechanism(CK_MECHANISM_PTR m)
ddf7d0
         CASE(CKM_AES_KEY_GEN);
ddf7d0
         CASE(CKM_AES_MAC);
ddf7d0
         CASE(CKM_AES_MAC_GENERAL);
ddf7d0
+        CASE(CKM_AES_CMAC);
ddf7d0
+        CASE(CKM_AES_CMAC_GENERAL);
ddf7d0
         CASE(CKM_CAMELLIA_CBC);
ddf7d0
         CASE(CKM_CAMELLIA_CBC_ENCRYPT_DATA);
ddf7d0
         CASE(CKM_CAMELLIA_CBC_PAD);
ddf7d0
diff -up ./lib/pk11wrap/pk11mech.c.cmac ./lib/pk11wrap/pk11mech.c
ddf7d0
--- ./lib/pk11wrap/pk11mech.c.cmac	2019-11-06 16:49:20.284102148 -0800
ddf7d0
+++ ./lib/pk11wrap/pk11mech.c	2019-11-06 16:49:57.882508693 -0800
ddf7d0
@@ -236,6 +236,8 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type,
ddf7d0
         case CKM_AES_GCM:
ddf7d0
         case CKM_AES_MAC:
ddf7d0
         case CKM_AES_MAC_GENERAL:
ddf7d0
+        case CKM_AES_CMAC:
ddf7d0
+        case CKM_AES_CMAC_GENERAL:
ddf7d0
         case CKM_AES_CBC_PAD:
ddf7d0
         case CKM_AES_KEY_GEN:
ddf7d0
         case CKM_NETSCAPE_AES_KEY_WRAP:
ddf7d0
@@ -453,6 +455,8 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE
ddf7d0
         case CKM_AES_GCM:
ddf7d0
         case CKM_AES_MAC:
ddf7d0
         case CKM_AES_MAC_GENERAL:
ddf7d0
+        case CKM_AES_CMAC:
ddf7d0
+        case CKM_AES_CMAC_GENERAL:
ddf7d0
         case CKM_AES_CBC_PAD:
ddf7d0
         case CKM_AES_KEY_GEN:
ddf7d0
             return CKM_AES_KEY_GEN;
ddf7d0
diff -up ./lib/softoken/pkcs11c.c.cmac ./lib/softoken/pkcs11c.c
ddf7d0
--- ./lib/softoken/pkcs11c.c.cmac	2019-11-06 16:49:20.315102483 -0800
ddf7d0
+++ ./lib/softoken/pkcs11c.c	2019-11-06 16:49:57.887508747 -0800
ddf7d0
@@ -30,6 +30,7 @@
ddf7d0
 #include "lowpbe.h" /* We do PBE below */
ddf7d0
 #include "pkcs11t.h"
ddf7d0
 #include "secoid.h"
ddf7d0
+#include "cmac.h"
ddf7d0
 #include "alghmac.h"
ddf7d0
 #include "softoken.h"
ddf7d0
 #include "secasn1.h"
ddf7d0
@@ -1971,6 +1972,84 @@ sftk_doHMACInit(SFTKSessionContext *cont
ddf7d0
 }
ddf7d0
 
ddf7d0
 /*
ddf7d0
+ * common CMAC initialization routine
ddf7d0
+ */
ddf7d0
+static CK_RV
ddf7d0
+sftk_doCMACInit(SFTKSessionContext *session, CMACCipher type,
ddf7d0
+                SFTKObject *key, CK_ULONG mac_size)
ddf7d0
+{
ddf7d0
+    SFTKAttribute *keyval;
ddf7d0
+    CMACContext *cmacContext;
ddf7d0
+    CK_ULONG *intpointer;
ddf7d0
+
ddf7d0
+    /* Unlike HMAC, CMAC doesn't need to check key sizes as the underlying
ddf7d0
+     * block cipher does this for us: block ciphers support only a single
ddf7d0
+     * key size per variant.
ddf7d0
+     *
ddf7d0
+     * To introduce support for a CMAC based on a new block cipher, first add
ddf7d0
+     * support for the relevant block cipher to CMAC in the freebl layer. Then
ddf7d0
+     * update the switch statement at the end of this function. Also remember
ddf7d0
+     * to update the switch statement in NSC_SignInit with the PKCS#11
ddf7d0
+     * mechanism constants.
ddf7d0
+     */
ddf7d0
+
ddf7d0
+    keyval = sftk_FindAttribute(key, CKA_VALUE);
ddf7d0
+    if (keyval == NULL) {
ddf7d0
+        return CKR_KEY_SIZE_RANGE;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* Create the underlying CMACContext and associate it with the
ddf7d0
+     * SFTKSessionContext's hashInfo field */
ddf7d0
+    cmacContext = CMAC_Create(type,
ddf7d0
+                              (const unsigned char *)keyval->attrib.pValue,
ddf7d0
+                              keyval->attrib.ulValueLen);
ddf7d0
+    sftk_FreeAttribute(keyval);
ddf7d0
+
ddf7d0
+    if (cmacContext == NULL) {
ddf7d0
+        if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
ddf7d0
+            return CKR_KEY_SIZE_RANGE;
ddf7d0
+        }
ddf7d0
+
ddf7d0
+        return CKR_HOST_MEMORY;
ddf7d0
+    }
ddf7d0
+    session->hashInfo = cmacContext;
ddf7d0
+
ddf7d0
+    /* MACs all behave roughly the same. However, CMAC can fail because
ddf7d0
+     * the underlying cipher can fail. In practice, this shouldn't occur
ddf7d0
+     * because we're not using any chaining modes, letting us safely ignore
ddf7d0
+     * the return value. */
ddf7d0
+    session->multi = PR_TRUE;
ddf7d0
+    session->hashUpdate = (SFTKHash)CMAC_Update;
ddf7d0
+    session->end = (SFTKEnd)CMAC_Finish;
ddf7d0
+    session->hashdestroy = (SFTKDestroy)CMAC_Destroy;
ddf7d0
+
ddf7d0
+    intpointer = PORT_New(CK_ULONG);
ddf7d0
+    if (intpointer == NULL) {
ddf7d0
+        return CKR_HOST_MEMORY;
ddf7d0
+    }
ddf7d0
+    *intpointer = mac_size;
ddf7d0
+    session->cipherInfo = intpointer;
ddf7d0
+
ddf7d0
+    /* Since we're only "hashing", copy the result from session->end to the
ddf7d0
+     * caller using sftk_SignCopy. */
ddf7d0
+    session->update = (SFTKCipher)sftk_SignCopy;
ddf7d0
+    session->verify = (SFTKVerify)sftk_HMACCmp;
ddf7d0
+    session->destroy = (SFTKDestroy)sftk_Space;
ddf7d0
+
ddf7d0
+    /* Will need to be updated for additional block ciphers in the future. */
ddf7d0
+    switch (type) {
ddf7d0
+        case CMAC_AES:
ddf7d0
+            session->maxLen = AES_BLOCK_SIZE;
ddf7d0
+            break;
ddf7d0
+        default:
ddf7d0
+            PORT_Assert(0);
ddf7d0
+            return CKR_KEY_SIZE_RANGE;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    return CKR_OK;
ddf7d0
+}
ddf7d0
+
ddf7d0
+/*
ddf7d0
  *  SSL Macing support. SSL Macs are inited, then update with the base
ddf7d0
  * hashing algorithm, then finalized in sign and verify
ddf7d0
  */
ddf7d0
@@ -2729,7 +2808,7 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
ddf7d0
 
ddf7d0
         case CKM_SHA_1_HMAC_GENERAL:
ddf7d0
             PORT_Assert(pMechanism->pParameter);
ddf7d0
-            if (!pMechanism->pParameter) {
ddf7d0
+            if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
ddf7d0
                 crv = CKR_MECHANISM_PARAM_INVALID;
ddf7d0
                 break;
ddf7d0
             }
ddf7d0
@@ -2739,7 +2818,17 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
ddf7d0
         case CKM_SHA_1_HMAC:
ddf7d0
             crv = sftk_doHMACInit(context, HASH_AlgSHA1, key, SHA1_LENGTH);
ddf7d0
             break;
ddf7d0
-
ddf7d0
+        case CKM_AES_CMAC_GENERAL:
ddf7d0
+            PORT_Assert(pMechanism->pParameter);
ddf7d0
+            if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
ddf7d0
+                crv = CKR_MECHANISM_PARAM_INVALID;
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_doCMACInit(context, CMAC_AES, key, *(CK_ULONG *)pMechanism->pParameter);
ddf7d0
+            break;
ddf7d0
+        case CKM_AES_CMAC:
ddf7d0
+            crv = sftk_doCMACInit(context, CMAC_AES, key, AES_BLOCK_SIZE);
ddf7d0
+            break;
ddf7d0
         case CKM_SSL3_MD5_MAC:
ddf7d0
             PORT_Assert(pMechanism->pParameter);
ddf7d0
             if (!pMechanism->pParameter) {
ddf7d0
diff -up ./lib/softoken/pkcs11.c.cmac ./lib/softoken/pkcs11.c
ddf7d0
--- ./lib/softoken/pkcs11.c.cmac	2019-11-06 16:49:57.884508714 -0800
ddf7d0
+++ ./lib/softoken/pkcs11.c	2019-11-06 16:51:37.330584008 -0800
ddf7d0
@@ -324,6 +324,8 @@ static const struct mechanismList mechan
ddf7d0
     { CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
ddf7d0
     { CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
ddf7d0
     { CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
ddf7d0
+    { CKM_AES_CMAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
ddf7d0
+    { CKM_AES_CMAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
ddf7d0
     { CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
ddf7d0
     { CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE },
ddf7d0
     { CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE },
ddf7d0
diff -up ./lib/util/pkcs11t.h.cmac ./lib/util/pkcs11t.h
ddf7d0
--- ./lib/util/pkcs11t.h.cmac	2019-11-06 16:49:20.289102202 -0800
ddf7d0
+++ ./lib/util/pkcs11t.h	2019-11-06 16:49:57.887508747 -0800
ddf7d0
@@ -882,6 +882,9 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
ddf7d0
 #define CKM_AES_GCM 0x00001087
ddf7d0
 #define CKM_AES_CCM 0x00001088
ddf7d0
 #define CKM_AES_CTS 0x00001089
ddf7d0
+/* AES-CMAC values copied from v2.40 errata 1 header file */
ddf7d0
+#define CKM_AES_CMAC_GENERAL 0x0000108A
ddf7d0
+#define CKM_AES_CMAC 0x0000108B
ddf7d0
 #define CKM_AES_XCBC_MAC 0x0000108C
ddf7d0
 #define CKM_AES_XCBC_MAC_96 0x0000108D
ddf7d0