Skip to content

Commit

Permalink
Bug 1570501 - Expose AES-CMAC in PKCS #11 API, r=mt
Browse files Browse the repository at this point in the history
Differential Revision: https://phabricator.services.mozilla.com/D40121

--HG--
extra : source : 20c543ab422e06d610bb316690a01a77b2668a66
  • Loading branch information
cipherboy committed Aug 30, 2019
1 parent 879dde4 commit 5e02c0f
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 4 deletions.
5 changes: 3 additions & 2 deletions automation/taskcluster/scripts/build_softoken.sh
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions cmd/lib/pk11table.c
Expand Up @@ -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),
Expand Down
91 changes: 91 additions & 0 deletions gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
@@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <memory>
#include "nss.h"
#include "pk11pub.h"
#include "secerr.h"
#include "sechash.h"

#include "blapi.h"

#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
#include "util.h"

namespace nss_test {

class Pkcs11AesCmacTest : public ::testing::Test {
protected:
ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
ADD_FAILURE() << "Can't get slot";
return nullptr;
}

ScopedPK11SymKey result(PK11_ImportSymKey(
slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, key_item, nullptr));

return result;
}

void RunTest(uint8_t *key, unsigned int key_len, uint8_t *data,
unsigned int data_len, uint8_t *expected,
unsigned int expected_len, CK_ULONG mechanism) {
// Create SECItems for everything...
std::vector<uint8_t> output(expected_len);
SECItem key_item = {siBuffer, key, key_len};
SECItem output_item = {siBuffer, output.data(), expected_len};
SECItem data_item = {siBuffer, data, data_len};
SECItem expected_item = {siBuffer, expected, expected_len};

// Do the PKCS #11 stuff...
ScopedPK11SymKey p11_key = ImportKey(mechanism, &key_item);
ASSERT_NE(nullptr, p11_key.get());

SECStatus ret = PK11_SignWithSymKey(p11_key.get(), CKM_AES_CMAC, NULL,
&output_item, &data_item);

// Verify the result...
ASSERT_EQ(SECSuccess, ret);
ASSERT_EQ(0, SECITEM_CompareItem(&output_item, &expected_item));
}
};

// Sanity check of the PKCS #11 API only. Extensive tests for correctness of
// underling CMAC implementation conducted in the following file:
// gtests/freebl_gtest/cmac_unittests.cc

TEST_F(Pkcs11AesCmacTest, Aes128NistExample1) {
uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
0x09, 0xCF, 0x4F, 0x3C};
uint8_t known[AES_BLOCK_SIZE] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59,
0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
0x9B, 0x75, 0x67, 0x46};

RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, AES_BLOCK_SIZE,
CKM_AES_CMAC);
}

TEST_F(Pkcs11AesCmacTest, General) {
uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
0x09, 0xCF, 0x4F, 0x3C};
uint8_t known[4] = {0xBB, 0x1D, 0x69, 0x29};

RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, 4, CKM_AES_CMAC_GENERAL);
}

TEST_F(Pkcs11AesCmacTest, InvalidKeySize) {
uint8_t key[4] = {0x00, 0x00, 0x00, 0x00};
SECItem key_item = {siBuffer, key, 4};

ScopedPK11SymKey result = ImportKey(CKM_AES_CMAC, &key_item);
ASSERT_EQ(nullptr, result.get());
}
}
1 change: 1 addition & 0 deletions gtests/pk11_gtest/pk11_gtest.gyp
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions lib/pk11wrap/debug_module.c
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions lib/pk11wrap/pk11mech.c
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions lib/softoken/pkcs11.c
Expand Up @@ -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 },
Expand Down
93 changes: 91 additions & 2 deletions lib/softoken/pkcs11c.c
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions lib/util/pkcs11t.h
Expand Up @@ -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

Expand Down

0 comments on commit 5e02c0f

Please sign in to comment.