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 "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 case CKM_SEED_ECB:
76 return CKM_SEED_ECB_ENCRYPT_DATA;
77 case CKM_SEED_CBC:
78 return CKM_SEED_CBC_ENCRYPT_DATA;
79 default:
80 ADD_FAILURE() << "Unknown mechanism";
81 break;
82 }
83 return CKM_INVALID_MECHANISM;
84 }
85
derive_param() const86 SECItem* derive_param() const {
87 static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data;
88 static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data;
89 static CK_KEY_DERIVATION_STRING_DATA string_data;
90 static SECItem param = {siBuffer, NULL, 0};
91
92 switch (encrypt_mech()) {
93 case CKM_DES3_ECB:
94 case CKM_AES_ECB:
95 case CKM_CAMELLIA_ECB:
96 case CKM_SEED_ECB:
97 string_data.pData = toUcharPtr(kInput);
98 string_data.ulLen = keysize();
99 param.data = reinterpret_cast<uint8_t*>(&string_data);
100 param.len = sizeof(string_data);
101 break;
102
103 case CKM_DES3_CBC:
104 des_data.pData = toUcharPtr(kInput);
105 des_data.length = keysize();
106 PORT_Memcpy(des_data.iv, kIv, 8);
107 param.data = reinterpret_cast<uint8_t*>(&des_data);
108 param.len = sizeof(des_data);
109 break;
110
111 case CKM_AES_CBC:
112 case CKM_CAMELLIA_CBC:
113 case CKM_SEED_CBC:
114 aes_data.pData = toUcharPtr(kInput);
115 aes_data.length = keysize();
116 PORT_Memcpy(aes_data.iv, kIv, keysize());
117 param.data = reinterpret_cast<uint8_t*>(&aes_data);
118 param.len = sizeof(aes_data);
119 break;
120
121 default:
122 ADD_FAILURE() << "Unknown mechanism";
123 break;
124 }
125 return ¶m;
126 }
127
encrypt_param() const128 SECItem* encrypt_param() const {
129 static SECItem param = {siBuffer, NULL, 0};
130
131 switch (encrypt_mech()) {
132 case CKM_DES3_ECB:
133 case CKM_AES_ECB:
134 case CKM_CAMELLIA_ECB:
135 case CKM_SEED_ECB:
136 // No parameter needed here.
137 break;
138
139 case CKM_DES3_CBC:
140 case CKM_AES_CBC:
141 case CKM_CAMELLIA_CBC:
142 case CKM_SEED_CBC:
143 param.data = toUcharPtr(kIv);
144 param.len = keysize();
145 break;
146
147 default:
148 ADD_FAILURE() << "Unknown mechanism";
149 break;
150 }
151 return ¶m;
152 }
153
SetUp()154 virtual void SetUp() {
155 slot_.reset(PK11_GetBestSlot(derive_mech(), NULL));
156 ASSERT_TRUE(slot_);
157
158 key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL,
159 keysize(), NULL,
160 CKF_ENCRYPT | CKF_DERIVE, 0, NULL));
161 ASSERT_TRUE(key_);
162 }
163
GetKeyData(ScopedPK11SymKey & key,uint8_t * buf,size_t max_len) const164 void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const {
165 ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get()));
166 SECItem* data = PK11_GetKeyData(key.get());
167 ASSERT_TRUE(data);
168 ASSERT_EQ(max_len, static_cast<size_t>(data->len));
169 PORT_Memcpy(buf, data->data, data->len);
170 }
171
172 // Remove checksum if the key is a 3DES key.
RemoveChecksum(uint8_t * key_data) const173 void RemoveChecksum(uint8_t* key_data) const {
174 if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) {
175 return;
176 }
177 for (size_t i = 0; i < keysize(); ++i) {
178 key_data[i] &= 0xfe;
179 }
180 }
181
182 ScopedPK11SlotInfo slot_;
183 ScopedPK11SymKey key_;
184 };
185
TEST_P(EncryptDeriveTest,Test)186 TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); }
187
188 static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = {
189 CKM_DES3_ECB, CKM_DES3_CBC, CKM_AES_ECB, CKM_AES_ECB, CKM_AES_CBC,
190 CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC, CKM_SEED_ECB, CKM_SEED_CBC};
191
192 INSTANTIATE_TEST_CASE_P(EncryptDeriveTests, EncryptDeriveTest,
193 ::testing::ValuesIn(kEncryptDeriveMechanisms));
194
195 // This class handles the case where 3DES takes a 192-bit key
196 // where all 24 octets will be used.
197 class EncryptDerive3Test : public EncryptDeriveTest {
198 protected:
keysize() const199 unsigned int keysize() const { return 24; }
200 };
201
TEST_P(EncryptDerive3Test,Test)202 TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); }
203
204 static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB,
205 CKM_DES3_CBC};
206
207 INSTANTIATE_TEST_CASE_P(Encrypt3DeriveTests, EncryptDerive3Test,
208 ::testing::ValuesIn(kDES3EncryptDeriveMechanisms));
209
210 } // namespace nss_test
211