1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include <memory>
8 #include "gtest/gtest.h"
9 #include "nss.h"
10 #include "nss_scoped_ptrs.h"
11 #include "pk11pub.h"
12
13 namespace nss_test {
14
15 class Pkcs11AESKeyWrapPadTest : public ::testing::Test {};
16
17 // Encrypt an ephemeral EC key (U2F use case)
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapECKey)18 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapECKey) {
19 const uint32_t kwrappedBufLen = 256;
20 const uint32_t kPublicKeyLen = 65;
21 const uint32_t kOidLen = 65;
22 unsigned char param_buf[kOidLen];
23 unsigned char unwrap_buf[kPublicKeyLen];
24
25 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
26 ASSERT_NE(nullptr, slot);
27
28 SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)};
29 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
30 ASSERT_NE(oid_data, nullptr);
31 ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID;
32 ecdsa_params.data[1] = oid_data->oid.len;
33 memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len);
34 ecdsa_params.len = oid_data->oid.len + 2;
35
36 SECKEYPublicKey* pub_tmp;
37 ScopedSECKEYPublicKey pub_key;
38 ScopedSECKEYPrivateKey priv_key(
39 PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params,
40 &pub_tmp, PR_FALSE, PR_TRUE, nullptr));
41 ASSERT_NE(nullptr, priv_key);
42 ASSERT_NE(nullptr, pub_tmp);
43 pub_key.reset(pub_tmp);
44
45 // Generate a KEK.
46 ScopedPK11SymKey kek(
47 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
48 ASSERT_NE(nullptr, kek);
49
50 // Wrap the key
51 ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
52 ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr));
53
54 SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(),
55 CKM_NSS_AES_KEY_WRAP_PAD, param.get(),
56 wrapped.get(), nullptr);
57 ASSERT_EQ(rv, SECSuccess);
58
59 SECItem pubKey = {siBuffer, unwrap_buf, kPublicKeyLen};
60 CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN};
61 int usageCount = 1;
62
63 ScopedSECKEYPrivateKey unwrapped(
64 PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD,
65 param.get(), wrapped.get(), nullptr, &pubKey, false,
66 true, CKK_EC, usages, usageCount, nullptr));
67 ASSERT_EQ(0, PORT_GetError());
68 ASSERT_TRUE(!!unwrapped);
69
70 // Try it with internal params allocation.
71 SECKEYPrivateKey* tmp = PK11_UnwrapPrivKey(
72 slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, nullptr, wrapped.get(),
73 nullptr, &pubKey, false, true, CKK_EC, usages, usageCount, nullptr);
74 ASSERT_EQ(0, PORT_GetError());
75 ASSERT_NE(nullptr, tmp);
76 unwrapped.reset(tmp);
77 }
78
79 // Encrypt an ephemeral RSA key
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRsaKey)80 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRsaKey) {
81 const uint32_t kwrappedBufLen = 648;
82 unsigned char unwrap_buf[kwrappedBufLen];
83
84 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
85 ASSERT_NE(nullptr, slot);
86
87 PK11RSAGenParams rsa_param;
88 rsa_param.keySizeInBits = 1024;
89 rsa_param.pe = 65537L;
90
91 SECKEYPublicKey* pub_tmp;
92 ScopedSECKEYPublicKey pub_key;
93 ScopedSECKEYPrivateKey priv_key(
94 PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_param,
95 &pub_tmp, PR_FALSE, PR_FALSE, nullptr));
96 ASSERT_NE(nullptr, priv_key);
97 ASSERT_NE(nullptr, pub_tmp);
98 pub_key.reset(pub_tmp);
99
100 // Generate a KEK.
101 ScopedPK11SymKey kek(
102 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
103 ASSERT_NE(nullptr, kek);
104
105 // Wrap the key
106 ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
107 ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr));
108
109 SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(),
110 CKM_NSS_AES_KEY_WRAP_PAD, param.get(),
111 wrapped.get(), nullptr);
112 ASSERT_EQ(rv, SECSuccess);
113
114 SECItem pubKey = {siBuffer, unwrap_buf, kwrappedBufLen};
115 CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN};
116 int usageCount = 1;
117
118 ScopedSECKEYPrivateKey unwrapped(
119 PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD,
120 param.get(), wrapped.get(), nullptr, &pubKey, false,
121 false, CKK_EC, usages, usageCount, nullptr));
122 ASSERT_EQ(0, PORT_GetError());
123 ASSERT_TRUE(!!unwrapped);
124
125 ScopedSECItem priv_key_data(
126 PK11_ExportDERPrivateKeyInfo(priv_key.get(), nullptr));
127 ScopedSECItem unwrapped_data(
128 PK11_ExportDERPrivateKeyInfo(unwrapped.get(), nullptr));
129 EXPECT_TRUE(!!priv_key_data);
130 EXPECT_TRUE(!!unwrapped_data);
131 ASSERT_EQ(priv_key_data->len, unwrapped_data->len);
132 ASSERT_EQ(
133 0, memcmp(priv_key_data->data, unwrapped_data->data, priv_key_data->len));
134 }
135
136 // Wrap a random that's a multiple of the block size, and compare the unwrap
137 // result.
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_EvenBlock)138 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_EvenBlock) {
139 const uint32_t kInputKeyLen = 128;
140 uint32_t out_len = 0;
141 std::vector<unsigned char> input_key(kInputKeyLen);
142 std::vector<unsigned char> wrapped_key(
143 kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
144 std::vector<unsigned char> unwrapped_key(
145 kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
146
147 // Generate input key material
148 SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
149 EXPECT_EQ(SECSuccess, rv);
150
151 // Generate a KEK.
152 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
153 ASSERT_NE(nullptr, slot);
154 ScopedPK11SymKey kek(
155 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
156 ASSERT_NE(nullptr, kek);
157
158 // Wrap the key
159 rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
160 wrapped_key.data(), &out_len,
161 static_cast<unsigned int>(wrapped_key.size()),
162 input_key.data(),
163 static_cast<unsigned int>(input_key.size()));
164 ASSERT_EQ(SECSuccess, rv);
165
166 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
167 unwrapped_key.data(), &out_len,
168 static_cast<unsigned int>(unwrapped_key.size()),
169 wrapped_key.data(), out_len);
170 ASSERT_EQ(SECSuccess, rv);
171 ASSERT_EQ(input_key.size(), out_len);
172 ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
173 }
174
175 // Wrap a random that's NOT a multiple of the block size, and compare the unwrap
176 // result.
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_OddBlock1)177 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock1) {
178 const uint32_t kInputKeyLen = 65;
179 uint32_t out_len = 0;
180 std::vector<unsigned char> input_key(kInputKeyLen);
181 std::vector<unsigned char> wrapped_key(
182 kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
183 std::vector<unsigned char> unwrapped_key(
184 kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
185
186 // Generate input key material
187 SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
188 EXPECT_EQ(SECSuccess, rv);
189
190 // Generate a KEK.
191 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
192 ASSERT_NE(nullptr, slot);
193 ScopedPK11SymKey kek(
194 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
195 ASSERT_NE(nullptr, kek);
196
197 // Wrap the key
198 rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
199 wrapped_key.data(), &out_len,
200 static_cast<unsigned int>(wrapped_key.size()),
201 input_key.data(),
202 static_cast<unsigned int>(input_key.size()));
203 ASSERT_EQ(SECSuccess, rv);
204
205 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
206 unwrapped_key.data(), &out_len,
207 static_cast<unsigned int>(unwrapped_key.size()),
208 wrapped_key.data(), out_len);
209 ASSERT_EQ(SECSuccess, rv);
210 ASSERT_EQ(input_key.size(), out_len);
211 ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
212 }
213
214 // Wrap a random that's NOT a multiple of the block size, and compare the unwrap
215 // result.
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_OddBlock2)216 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock2) {
217 const uint32_t kInputKeyLen = 63;
218 uint32_t out_len = 0;
219 std::vector<unsigned char> input_key(kInputKeyLen);
220 std::vector<unsigned char> wrapped_key(
221 kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
222 std::vector<unsigned char> unwrapped_key(
223 kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
224
225 // Generate input key material
226 SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
227 EXPECT_EQ(SECSuccess, rv);
228
229 // Generate a KEK.
230 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
231 ASSERT_NE(nullptr, slot);
232 ScopedPK11SymKey kek(
233 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
234 ASSERT_NE(nullptr, kek);
235
236 // Wrap the key
237 rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
238 wrapped_key.data(), &out_len, wrapped_key.size(),
239 input_key.data(), input_key.size());
240 ASSERT_EQ(SECSuccess, rv);
241
242 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
243 unwrapped_key.data(), &out_len,
244 static_cast<unsigned int>(unwrapped_key.size()),
245 wrapped_key.data(), out_len);
246 ASSERT_EQ(SECSuccess, rv);
247 ASSERT_EQ(input_key.size(), out_len);
248 ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
249 }
250
251 // Invalid long padding (over the block size, but otherwise valid)
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_PaddingTooLong)252 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_PaddingTooLong) {
253 const uint32_t kInputKeyLen = 32;
254 uint32_t out_len = 0;
255
256 // Apply our own padding
257 const unsigned char buf[32] = {
258 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
259 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
260 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
261 std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
262 std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
263
264 // Generate a KEK.
265 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
266 ASSERT_NE(nullptr, slot);
267 ScopedPK11SymKey kek(
268 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
269 ASSERT_NE(nullptr, kek);
270
271 // Wrap the key
272 SECStatus rv =
273 PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
274 /* param */ nullptr, wrapped_key.data(), &out_len,
275 wrapped_key.size(), buf, sizeof(buf));
276 ASSERT_EQ(SECSuccess, rv);
277
278 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
279 unwrapped_key.data(), &out_len,
280 static_cast<unsigned int>(unwrapped_key.size()),
281 wrapped_key.data(), out_len);
282 ASSERT_EQ(SECFailure, rv);
283 }
284
285 // Invalid 0-length padding (there should be a full block if the message doesn't
286 // need to be padded)
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_NoPadding)287 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_NoPadding) {
288 const uint32_t kInputKeyLen = 32;
289 uint32_t out_len = 0;
290
291 // Apply our own padding
292 const unsigned char buf[32] = {0};
293 std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
294 std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
295
296 // Generate a KEK.
297 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
298 ASSERT_NE(nullptr, slot);
299 ScopedPK11SymKey kek(
300 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
301 ASSERT_NE(nullptr, kek);
302
303 // Wrap the key
304 SECStatus rv =
305 PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
306 /* param */ nullptr, wrapped_key.data(), &out_len,
307 wrapped_key.size(), buf, sizeof(buf));
308 ASSERT_EQ(SECSuccess, rv);
309
310 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
311 unwrapped_key.data(), &out_len,
312 static_cast<unsigned int>(unwrapped_key.size()),
313 wrapped_key.data(), out_len);
314 ASSERT_EQ(SECFailure, rv);
315 }
316
317 // Invalid padding
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_BadPadding1)318 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding1) {
319 const uint32_t kInputKeyLen = 32;
320 uint32_t out_len = 0;
321
322 // Apply our own padding
323 const unsigned char buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08,
327 0x08, 0x08, 0x08, 0x08}; // Check all 8 bytes
328 std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
329 std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
330
331 // Generate a KEK.
332 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
333 ASSERT_NE(nullptr, slot);
334 ScopedPK11SymKey kek(
335 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
336 ASSERT_NE(nullptr, kek);
337
338 // Wrap the key
339 SECStatus rv =
340 PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
341 /* param */ nullptr, wrapped_key.data(), &out_len,
342 wrapped_key.size(), buf, sizeof(buf));
343 ASSERT_EQ(SECSuccess, rv);
344
345 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
346 unwrapped_key.data(), &out_len,
347 static_cast<unsigned int>(unwrapped_key.size()),
348 wrapped_key.data(), out_len);
349 ASSERT_EQ(SECFailure, rv);
350 }
351
352 // Invalid padding
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_BadPadding2)353 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding2) {
354 const uint32_t kInputKeyLen = 32;
355 uint32_t out_len = 0;
356
357 // Apply our own padding
358 const unsigned char
359 buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 0x00, 0x00, 0x00, 0x01, 0x02}; // Check first loop repeat
363 std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
364 std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
365
366 // Generate a KEK.
367 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
368 ASSERT_NE(nullptr, slot);
369 ScopedPK11SymKey kek(
370 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
371 ASSERT_NE(nullptr, kek);
372
373 // Wrap the key
374 SECStatus rv =
375 PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
376 /* param */ nullptr, wrapped_key.data(), &out_len,
377 wrapped_key.size(), buf, sizeof(buf));
378 ASSERT_EQ(SECSuccess, rv);
379
380 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
381 unwrapped_key.data(), &out_len,
382 static_cast<unsigned int>(unwrapped_key.size()),
383 wrapped_key.data(), out_len);
384 ASSERT_EQ(SECFailure, rv);
385 }
386
387 // Minimum valid padding
TEST_F(Pkcs11AESKeyWrapPadTest,WrapUnwrapRandom_ShortValidPadding)388 TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_ShortValidPadding) {
389 const uint32_t kInputKeyLen = 32;
390 uint32_t out_len = 0;
391
392 // Apply our own padding
393 const unsigned char buf[kInputKeyLen] = {
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; // Minimum
397 std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
398 std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
399
400 // Generate a KEK.
401 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
402 ASSERT_NE(nullptr, slot);
403 ScopedPK11SymKey kek(
404 PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
405 ASSERT_NE(nullptr, kek);
406
407 // Wrap the key
408 SECStatus rv =
409 PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
410 /* param */ nullptr, wrapped_key.data(), &out_len,
411 wrapped_key.size(), buf, sizeof(buf));
412 ASSERT_EQ(SECSuccess, rv);
413
414 rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
415 unwrapped_key.data(), &out_len,
416 static_cast<unsigned int>(unwrapped_key.size()),
417 wrapped_key.data(), out_len);
418 ASSERT_EQ(SECSuccess, rv);
419 ASSERT_EQ(kInputKeyLen - 1, out_len);
420 ASSERT_EQ(0, memcmp(buf, unwrapped_key.data(), out_len));
421 }
422
423 } // namespace nss_test
424