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 &param;
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 &param;
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