Skip to content

Commit

Permalink
Bug 1236720 - Provide sym key derive mechanism as result of encryptio…
Browse files Browse the repository at this point in the history
…n of message, r=mt

- Original patch by Robert Relyea was modified to make the tests gtests unit tests
- Tests modifications are a collaboration between Martin Thomson and Elio Maldonado

--HG--
extra : amend_source : 785d3649fdee274f1dbfc63ff805a25c8ac99a83
  • Loading branch information
rjrelyea committed Nov 1, 2017
1 parent 9827303 commit a10504d
Show file tree
Hide file tree
Showing 7 changed files with 438 additions and 5 deletions.
2 changes: 1 addition & 1 deletion gtests/common/util.h
Expand Up @@ -10,7 +10,7 @@
#include <cassert>
#include <vector>

std::vector<uint8_t> hex_string_to_bytes(std::string s) {
static inline std::vector<uint8_t> hex_string_to_bytes(std::string s) {
std::vector<uint8_t> bytes;
for (size_t i = 0; i < s.length(); i += 2) {
bytes.push_back(std::stoul(s.substr(i, 2), nullptr, 16));
Expand Down
1 change: 1 addition & 0 deletions gtests/pk11_gtest/manifest.mn
Expand Up @@ -11,6 +11,7 @@ CPPSRCS = \
pk11_chacha20poly1305_unittest.cc \
pk11_curve25519_unittest.cc \
pk11_ecdsa_unittest.cc \
pk11_encrypt_derive_unittest.cc \
pk11_export_unittest.cc \
pk11_pbkdf2_unittest.cc \
pk11_prf_unittest.cc \
Expand Down
216 changes: 216 additions & 0 deletions gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
@@ -0,0 +1,216 @@
/* 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 "pk11pub.h"
#include "nssutil.h"
#include <stdio.h>
#include "prerror.h"
#include "nss.h"
#include "gtest/gtest.h"
#include "scoped_ptrs.h"
#include "cpputil.h"
#include "databuffer.h"
#include "util.h"

#define MAX_KEY_SIZE 24

namespace nss_test {

static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
static const uint8_t kInput[] = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};

class EncryptDeriveTest
: public ::testing::Test,
public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {

public:
void TestEncryptDerive() {
ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(),
derive_param(), encrypt_mech(),
CKA_DECRYPT, keysize()));
ASSERT_TRUE(derived_key);

uint8_t derived_key_data[MAX_KEY_SIZE];
ASSERT_GE(sizeof(derived_key_data), keysize());
GetKeyData(derived_key, derived_key_data, keysize());
RemoveChecksum(derived_key_data);

uint8_t reference_key_data[MAX_KEY_SIZE];
unsigned int reference_len = 0;
SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(),
reference_key_data, &reference_len, keysize(),
kInput, keysize());
ASSERT_EQ(SECSuccess, rv);
ASSERT_EQ(keysize(), static_cast<size_t>(reference_len));
RemoveChecksum(reference_key_data);

EXPECT_EQ(DataBuffer(reference_key_data, keysize()),
DataBuffer(derived_key_data, keysize()));
}

protected:
unsigned int keysize() const { return 16; }

private:

CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); }

CK_MECHANISM_TYPE derive_mech() const {
switch (encrypt_mech()) {
case CKM_DES3_ECB:
return CKM_DES3_ECB_ENCRYPT_DATA;
case CKM_DES3_CBC:
return CKM_DES3_CBC_ENCRYPT_DATA;
case CKM_AES_ECB:
return CKM_AES_ECB_ENCRYPT_DATA;
case CKM_AES_CBC:
return CKM_AES_CBC_ENCRYPT_DATA;
case CKM_CAMELLIA_ECB:
return CKM_CAMELLIA_ECB_ENCRYPT_DATA;
case CKM_CAMELLIA_CBC:
return CKM_CAMELLIA_CBC_ENCRYPT_DATA;
case CKM_SEED_ECB:
return CKM_SEED_ECB_ENCRYPT_DATA;
case CKM_SEED_CBC:
return CKM_SEED_CBC_ENCRYPT_DATA;
default:
ADD_FAILURE() << "Unknown mechanism";
break;
}
return CKM_INVALID_MECHANISM;
}

SECItem* derive_param() const {
static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data;
static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data;
static CK_KEY_DERIVATION_STRING_DATA string_data;
static SECItem param = {siBuffer, NULL, 0};

switch (encrypt_mech()) {
case CKM_DES3_ECB:
case CKM_AES_ECB:
case CKM_CAMELLIA_ECB:
case CKM_SEED_ECB:
string_data.pData = toUcharPtr(kInput);
string_data.ulLen = keysize();
param.data = reinterpret_cast<uint8_t*>(&string_data);
param.len = sizeof(string_data);
break;

case CKM_DES3_CBC:
des_data.pData = toUcharPtr(kInput);
des_data.length = keysize();
PORT_Memcpy(des_data.iv, kIv, 8);
param.data = reinterpret_cast<uint8_t*>(&des_data);
param.len = sizeof(des_data);
break;

case CKM_AES_CBC:
case CKM_CAMELLIA_CBC:
case CKM_SEED_CBC:
aes_data.pData = toUcharPtr(kInput);
aes_data.length = keysize();
PORT_Memcpy(aes_data.iv, kIv, keysize());
param.data = reinterpret_cast<uint8_t*>(&aes_data);
param.len = sizeof(aes_data);
break;

default:
ADD_FAILURE() << "Unknown mechanism";
break;
}
return &param;
}

SECItem* encrypt_param() const {
static SECItem param = {siBuffer, NULL, 0};

switch (encrypt_mech()) {
case CKM_DES3_ECB:
case CKM_AES_ECB:
case CKM_CAMELLIA_ECB:
case CKM_SEED_ECB:
// No parameter needed here.
break;

case CKM_DES3_CBC:
case CKM_AES_CBC:
case CKM_CAMELLIA_CBC:
case CKM_SEED_CBC:
param.data = toUcharPtr(kIv);
param.len = keysize();
break;

default:
ADD_FAILURE() << "Unknown mechanism";
break;
}
return &param;
}

virtual void SetUp() {
slot_.reset(PK11_GetBestSlot(derive_mech(), NULL));
ASSERT_TRUE(slot_);

key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL,
keysize(), NULL,
CKF_ENCRYPT | CKF_DERIVE, 0, NULL));
ASSERT_TRUE(key_);
}

void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const {
ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get()));
SECItem* data = PK11_GetKeyData(key.get());
ASSERT_TRUE(data);
ASSERT_EQ(max_len, static_cast<size_t>(data->len));
PORT_Memcpy(buf, data->data, data->len);
}

// Remove checksum if the key is a 3DES key.
void RemoveChecksum(uint8_t* key_data) const {
if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) {
return;
}
for (size_t i = 0; i < keysize(); ++i) {
key_data[i] &= 0xfe;
}
}

ScopedPK11SlotInfo slot_;
ScopedPK11SymKey key_;
};

TEST_P(EncryptDeriveTest, Test) {
TestEncryptDerive();
}

static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = {
CKM_DES3_ECB, CKM_DES3_CBC, CKM_AES_ECB, CKM_AES_ECB, CKM_AES_CBC,
CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC, CKM_SEED_ECB, CKM_SEED_CBC};

INSTANTIATE_TEST_CASE_P(EncryptDeriveTests, EncryptDeriveTest,
::testing::ValuesIn(kEncryptDeriveMechanisms));

// This class handles the case where 3DES takes a 192-bit key
// where all 24 octets will be used.
class EncryptDerive3Test : public EncryptDeriveTest {
protected:
unsigned int keysize() const { return 24; }
};

TEST_P(EncryptDerive3Test, Test) {
TestEncryptDerive();
}

static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB,
CKM_DES3_CBC};

INSTANTIATE_TEST_CASE_P(Encrypt3DeriveTests, EncryptDerive3Test,
::testing::ValuesIn(kDES3EncryptDeriveMechanisms));

} // namespace nss_test
1 change: 1 addition & 0 deletions gtests/pk11_gtest/pk11_gtest.gyp
Expand Up @@ -16,6 +16,7 @@
'pk11_chacha20poly1305_unittest.cc',
'pk11_curve25519_unittest.cc',
'pk11_ecdsa_unittest.cc',
'pk11_encrypt_derive_unittest.cc',
'pk11_pbkdf2_unittest.cc',
'pk11_prf_unittest.cc',
'pk11_prng_unittest.cc',
Expand Down
17 changes: 13 additions & 4 deletions lib/softoken/pkcs11.c
Expand Up @@ -421,11 +421,20 @@ static const struct mechanismList mechanisms[] = {
#endif
/* --------------------- Secret Key Operations ------------------------ */
{ CKM_GENERIC_SECRET_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
{ CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_GENERATE }, PR_FALSE },
{ CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
{ CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_GENERATE }, PR_FALSE },
{ CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
{ CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_DES3_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_DES3_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_AES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_AES_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_CAMELLIA_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_CAMELLIA_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_SEED_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_SEED_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },

/* ---------------------- SSL Key Derivations ------------------------- */
{ CKM_SSL3_PRE_MASTER_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_FALSE },
{ CKM_SSL3_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
Expand Down

0 comments on commit a10504d

Please sign in to comment.