1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "pk11pub.h" 6 #include "nssutil.h" 7 #include <stdio.h> 8 #include "prerror.h" 9 #include "nss.h" 10 #include "gtest/gtest.h" 11 #include "nss_scoped_ptrs.h" 12 #include "cpputil.h" 13 #include "databuffer.h" 14 #include "util.h" 15 16 #define MAX_KEY_SIZE 24 17 18 namespace nss_test { 19 20 static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 21 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 22 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; 23 static const uint8_t kInput[] = { 24 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc, 25 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; 26 27 class EncryptDeriveTest 28 : public ::testing::Test, 29 public ::testing::WithParamInterface<CK_MECHANISM_TYPE> { 30 public: 31 void TestEncryptDerive() { 32 ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(), 33 derive_param(), encrypt_mech(), 34 CKA_DECRYPT, keysize())); 35 ASSERT_TRUE(derived_key); 36 37 uint8_t derived_key_data[MAX_KEY_SIZE]; 38 ASSERT_GE(sizeof(derived_key_data), keysize()); 39 GetKeyData(derived_key, derived_key_data, keysize()); 40 RemoveChecksum(derived_key_data); 41 42 uint8_t reference_key_data[MAX_KEY_SIZE]; 43 unsigned int reference_len = 0; 44 SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(), 45 reference_key_data, &reference_len, keysize(), 46 kInput, keysize()); 47 ASSERT_EQ(SECSuccess, rv); 48 ASSERT_EQ(keysize(), static_cast<size_t>(reference_len)); 49 RemoveChecksum(reference_key_data); 50 51 EXPECT_EQ(DataBuffer(reference_key_data, keysize()), 52 DataBuffer(derived_key_data, keysize())); 53 } 54 55 protected: 56 unsigned int keysize() const { return 16; } 57 58 private: 59 CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); } 60 61 CK_MECHANISM_TYPE derive_mech() const { 62 switch (encrypt_mech()) { 63 case CKM_DES3_ECB: 64 return CKM_DES3_ECB_ENCRYPT_DATA; 65 case CKM_DES3_CBC: 66 return CKM_DES3_CBC_ENCRYPT_DATA; 67 case CKM_AES_ECB: 68 return CKM_AES_ECB_ENCRYPT_DATA; 69 case CKM_AES_CBC: 70 return CKM_AES_CBC_ENCRYPT_DATA; 71 case CKM_CAMELLIA_ECB: 72 return CKM_CAMELLIA_ECB_ENCRYPT_DATA; 73 case CKM_CAMELLIA_CBC: 74 return CKM_CAMELLIA_CBC_ENCRYPT_DATA; 75 #ifndef NSS_DISABLE_DEPRECATED_SEED 76 case CKM_SEED_ECB: 77 return CKM_SEED_ECB_ENCRYPT_DATA; 78 case CKM_SEED_CBC: 79 return CKM_SEED_CBC_ENCRYPT_DATA; 80 #endif 81 default: 82 ADD_FAILURE() << "Unknown mechanism"; 83 break; 84 } 85 return CKM_INVALID_MECHANISM; 86 } 87 88 SECItem* derive_param() const { 89 static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data; 90 static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data; 91 static CK_KEY_DERIVATION_STRING_DATA string_data; 92 static SECItem param = {siBuffer, NULL, 0}; 93 94 switch (encrypt_mech()) { 95 case CKM_DES3_ECB: 96 case CKM_AES_ECB: 97 case CKM_CAMELLIA_ECB: 98 #ifndef NSS_DISABLE_DEPRECATED_SEED 99 case CKM_SEED_ECB: 100 #endif 101 string_data.pData = toUcharPtr(kInput); 102 string_data.ulLen = keysize(); 103 param.data = reinterpret_cast<uint8_t*>(&string_data); 104 param.len = sizeof(string_data); 105 break; 106 107 case CKM_DES3_CBC: 108 des_data.pData = toUcharPtr(kInput); 109 des_data.length = keysize(); 110 PORT_Memcpy(des_data.iv, kIv, 8); 111 param.data = reinterpret_cast<uint8_t*>(&des_data); 112 param.len = sizeof(des_data); 113 break; 114 115 case CKM_AES_CBC: 116 case CKM_CAMELLIA_CBC: 117 #ifndef NSS_DISABLE_DEPRECATED_SEED 118 case CKM_SEED_CBC: 119 #endif 120 aes_data.pData = toUcharPtr(kInput); 121 aes_data.length = keysize(); 122 PORT_Memcpy(aes_data.iv, kIv, keysize()); 123 param.data = reinterpret_cast<uint8_t*>(&aes_data); 124 param.len = sizeof(aes_data); 125 break; 126 127 default: 128 ADD_FAILURE() << "Unknown mechanism"; 129 break; 130 } 131 return ¶m; 132 } 133 134 SECItem* encrypt_param() const { 135 static SECItem param = {siBuffer, NULL, 0}; 136 137 switch (encrypt_mech()) { 138 case CKM_DES3_ECB: 139 case CKM_AES_ECB: 140 case CKM_CAMELLIA_ECB: 141 #ifndef NSS_DISABLE_DEPRECATED_SEED 142 case CKM_SEED_ECB: 143 #endif 144 // No parameter needed here. 145 break; 146 147 case CKM_DES3_CBC: 148 case CKM_AES_CBC: 149 case CKM_CAMELLIA_CBC: 150 #ifndef NSS_DISABLE_DEPRECATED_SEED 151 case CKM_SEED_CBC: 152 #endif 153 param.data = toUcharPtr(kIv); 154 param.len = keysize(); 155 break; 156 157 default: 158 ADD_FAILURE() << "Unknown mechanism"; 159 break; 160 } 161 return ¶m; 162 } 163 164 virtual void SetUp() { 165 slot_.reset(PK11_GetBestSlot(derive_mech(), NULL)); 166 ASSERT_TRUE(slot_); 167 168 key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL, 169 keysize(), NULL, 170 CKF_ENCRYPT | CKF_DERIVE, 0, NULL)); 171 ASSERT_TRUE(key_); 172 } 173 174 void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const { 175 ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get())); 176 SECItem* data = PK11_GetKeyData(key.get()); 177 ASSERT_TRUE(data); 178 ASSERT_EQ(max_len, static_cast<size_t>(data->len)); 179 PORT_Memcpy(buf, data->data, data->len); 180 } 181 182 // Remove checksum if the key is a 3DES key. 183 void RemoveChecksum(uint8_t* key_data) const { 184 if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) { 185 return; 186 } 187 for (size_t i = 0; i < keysize(); ++i) { 188 key_data[i] &= 0xfe; 189 } 190 } 191 192 ScopedPK11SlotInfo slot_; 193 ScopedPK11SymKey key_; 194 }; 195 196 TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); } 197 198 static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = { 199 CKM_DES3_ECB, CKM_DES3_CBC, CKM_AES_ECB, CKM_AES_ECB, CKM_AES_CBC, 200 CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC 201 #ifndef NSS_DISABLE_DEPRECATED_SEED 202 , 203 CKM_SEED_ECB, CKM_SEED_CBC 204 #endif 205 }; 206 207 INSTANTIATE_TEST_SUITE_P(EncryptDeriveTests, EncryptDeriveTest, 208 ::testing::ValuesIn(kEncryptDeriveMechanisms)); 209 210 // This class handles the case where 3DES takes a 192-bit key 211 // where all 24 octets will be used. 212 class EncryptDerive3Test : public EncryptDeriveTest { 213 protected: 214 unsigned int keysize() const { return 24; } 215 }; 216 217 TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); } 218 219 static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB, 220 CKM_DES3_CBC}; 221 222 INSTANTIATE_TEST_SUITE_P(Encrypt3DeriveTests, EncryptDerive3Test, 223 ::testing::ValuesIn(kDES3EncryptDeriveMechanisms)); 224 225 } // namespace nss_test 226