зеркало из https://github.com/mozilla/gecko-dev.git
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: Bug1560329
, 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 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
0b797e7d2e
Коммит
e46ef2b607
|
@ -1 +1 @@
|
|||
NSS_3_46_RTM
|
||||
cf0df88aa807
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
1 Added function:
|
||||
|
||||
'function CERTCertList* PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey*)' {PK11_GetCertsMatchingPrivateKey@@NSS_3.47}
|
||||
|
|
@ -1 +1 @@
|
|||
NSS_3_45_BRANCH
|
||||
NSS_3_46_BRANCH
|
||||
|
|
|
@ -20,8 +20,9 @@ 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
|
||||
|
|
|
@ -333,6 +333,8 @@ const Constant _consts[] = {
|
|||
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),
|
||||
|
|
|
@ -104,7 +104,7 @@ 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
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
|
|
@ -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__
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@
|
|||
'ecl_unittest.cc',
|
||||
'ghash_unittest.cc',
|
||||
'rsa_unittest.cc',
|
||||
'cmac_unittests.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -127,10 +127,10 @@ std::vector<uint8_t> kUnrelatedTestCertDER = {
|
|||
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());
|
||||
|
@ -157,6 +157,8 @@ class PK11FindRawCertsBySubjectTest : public ::testing::Test {
|
|||
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) {
|
||||
|
@ -344,4 +346,201 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestSearchForNullSubject) {
|
|||
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
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
'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',
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "blapit.h"
|
||||
#include "hasht.h"
|
||||
#include "cmac.h"
|
||||
#include "alghmac.h"
|
||||
|
||||
SEC_BEGIN_PROTOS
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -27,6 +27,7 @@
|
|||
},
|
||||
{
|
||||
'files': [
|
||||
'cmac.h',
|
||||
'alghmac.h',
|
||||
'blapi.h',
|
||||
'blake2b.h',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
'sources': [
|
||||
'aeskeywrap.c',
|
||||
'alg2268.c',
|
||||
'cmac.c',
|
||||
'alghmac.c',
|
||||
'arcfive.c',
|
||||
'arcfour.c',
|
||||
|
|
|
@ -10,6 +10,7 @@ extern int FREEBL_InitStubs(void);
|
|||
#endif
|
||||
|
||||
#include "loader.h"
|
||||
#include "cmac.h"
|
||||
#include "alghmac.h"
|
||||
#include "hmacct.h"
|
||||
#include "blapii.h"
|
||||
|
@ -317,10 +318,18 @@ static const struct FREEBLVectorStr vector =
|
|||
|
||||
/* 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*
|
||||
|
|
|
@ -2245,3 +2245,54 @@ BLAKE2B_Resurrect(unsigned char *space, void *arg)
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "blapi.h"
|
||||
|
||||
#define FREEBL_VERSION 0x0315
|
||||
#define FREEBL_VERSION 0x0316
|
||||
|
||||
struct FREEBLVectorStr {
|
||||
|
||||
|
@ -765,6 +765,20 @@ struct FREEBLVectorStr {
|
|||
|
||||
/* 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. */
|
||||
};
|
||||
|
|
|
@ -85,6 +85,7 @@ EXPORTS = \
|
|||
$(NULL)
|
||||
|
||||
PRIVATE_EXPORTS = \
|
||||
cmac.h \
|
||||
alghmac.h \
|
||||
blake2b.h \
|
||||
blapi.h \
|
||||
|
@ -119,6 +120,7 @@ CSRCS = \
|
|||
md2.c \
|
||||
md5.c \
|
||||
sha512.c \
|
||||
cmac.c \
|
||||
alghmac.c \
|
||||
rawhash.c \
|
||||
alg2268.c \
|
||||
|
@ -162,6 +164,7 @@ CSRCS = \
|
|||
ALL_CSRCS := $(CSRCS)
|
||||
|
||||
ALL_HDRS = \
|
||||
cmac.h \
|
||||
alghmac.h \
|
||||
blake2b.h \
|
||||
blapi.h \
|
||||
|
|
|
@ -1157,3 +1157,9 @@ PK11_FindRawCertsWithSubject;
|
|||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
;+NSS_3.47 { # NSS 3.47 release
|
||||
;+ global:
|
||||
PK11_GetCertsMatchingPrivateKey;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
* 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
|
||||
|
||||
|
|
|
@ -376,6 +376,8 @@ print_mechanism(CK_MECHANISM_PTR m)
|
|||
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);
|
||||
|
|
|
@ -406,6 +406,93 @@ PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
|
|||
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.
|
||||
|
|
|
@ -236,6 +236,8 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len)
|
|||
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:
|
||||
|
@ -453,6 +455,8 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size)
|
|||
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;
|
||||
|
|
|
@ -883,6 +883,14 @@ 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....
|
||||
**********************************************************************/
|
||||
|
|
|
@ -131,6 +131,22 @@ NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
|
|||
|
||||
/* 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
|
||||
|
@ -144,6 +160,8 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
|
|||
SECKEYPrivateKey *privkey = NULL;
|
||||
SECOidTag digestalgtag;
|
||||
SECOidTag pubkAlgTag;
|
||||
SECOidTag signAlgTag;
|
||||
SECOidTag cmsSignAlgTag;
|
||||
SECItem signature = { 0 };
|
||||
SECStatus rv;
|
||||
PLArenaPool *poolp, *tmppoolp = NULL;
|
||||
|
@ -182,12 +200,29 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
|
|||
* 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. */
|
||||
|
@ -230,13 +265,6 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
|
|||
&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 :-( */
|
||||
|
@ -255,10 +283,6 @@ NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
|
|||
|
||||
SECITEM_FreeItem(&signature, PR_FALSE);
|
||||
|
||||
if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag,
|
||||
NULL) != SECSuccess)
|
||||
goto loser;
|
||||
|
||||
return SECSuccess;
|
||||
|
||||
loser:
|
||||
|
@ -326,6 +350,8 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
|
|||
PLArenaPool *poolp;
|
||||
SECOidTag digestalgtag;
|
||||
SECOidTag pubkAlgTag;
|
||||
SECOidTag digestalgtagCmp;
|
||||
SECOidTag sigAlgTag;
|
||||
|
||||
if (signerinfo == NULL)
|
||||
return SECFailure;
|
||||
|
@ -345,8 +371,10 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -414,11 +442,28 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
|
|||
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 :-( */
|
||||
|
||||
|
@ -432,11 +477,23 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
|
|||
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) {
|
||||
|
|
|
@ -324,6 +324,8 @@ static const struct mechanismList mechanisms[] = {
|
|||
{ 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 },
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#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"
|
||||
|
@ -1985,6 +1986,84 @@ sftk_doHMACInit(SFTKSessionContext *context, HASH_HashType hash,
|
|||
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
|
||||
|
@ -2744,7 +2823,7 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -2754,7 +2833,17 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
|
|||
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) {
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
* 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_ */
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
* 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
|
||||
|
||||
|
|
|
@ -882,6 +882,9 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
|
|||
#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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче