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