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:
TestEncryptDerive()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:
keysize() const56 unsigned int keysize() const { return 16; }
57
58 private:
encrypt_mech() const59 CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); }
60
derive_mech() const61 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
derive_param() const88 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
encrypt_param() const134 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
SetUp()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
GetKeyData(ScopedPK11SymKey & key,uint8_t * buf,size_t max_len) const174 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.
RemoveChecksum(uint8_t * key_data) const183 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
TEST_P(EncryptDeriveTest,Test)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:
keysize() const214 unsigned int keysize() const { return 24; }
215 };
216
TEST_P(EncryptDerive3Test,Test)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