1 #include "cert.h"
2 #include "certdb.h"
3 #include "nspr.h"
4 #include "nss.h"
5 #include "pk11pub.h"
6 #include "secmod.h"
7 #include "secerr.h"
8
9 #include "nss_scoped_ptrs.h"
10 #include "util.h"
11
12 #define GTEST_HAS_RTTI 0
13 #include "gtest/gtest.h"
14 #include "databuffer.h"
15 #include <fstream>
16 #include <chrono>
17 #include <sqlite3.h>
18 using namespace std::chrono;
19
20 #include "softoken_dh_vectors.h"
21
22 namespace nss_test {
23 class SoftokenTest : public ::testing::Test {
24 protected:
SoftokenTest()25 SoftokenTest() : mNSSDBDir("SoftokenTest.d-") {}
SoftokenTest(const std::string & prefix)26 SoftokenTest(const std::string &prefix) : mNSSDBDir(prefix) {}
27
SetUp()28 virtual void SetUp() {
29 std::string nssInitArg("sql:");
30 nssInitArg.append(mNSSDBDir.GetUTF8Path());
31 ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
32 NSS_INIT_NOROOTINIT));
33 }
34
TearDown()35 virtual void TearDown() {
36 ASSERT_EQ(SECSuccess, NSS_Shutdown());
37 const std::string &nssDBDirPath = mNSSDBDir.GetPath();
38 ASSERT_EQ(0, unlink((nssDBDirPath + "/cert9.db").c_str()));
39 ASSERT_EQ(0, unlink((nssDBDirPath + "/key4.db").c_str()));
40 ASSERT_EQ(0, unlink((nssDBDirPath + "/pkcs11.txt").c_str()));
41 }
42
43 ScopedUniqueDirectory mNSSDBDir;
44 };
45
TEST_F(SoftokenTest,CheckDefaultPbkdf2Iterations)46 TEST_F(SoftokenTest, CheckDefaultPbkdf2Iterations) {
47 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
48 ASSERT_TRUE(slot);
49 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
50
51 // Open key4.db and check encoded PBE algorithm and iteration count.
52 // Compare bytes against the expected values to avoid ASN.1 here.
53 std::string key_db = mNSSDBDir.GetPath() + "/key4.db";
54
55 sqlite3 *sql_db = NULL;
56 ASSERT_EQ(SQLITE_OK, sqlite3_open(key_db.c_str(), &sql_db));
57
58 char *query_str = sqlite3_mprintf("SELECT item2 FROM metaData;");
59 ASSERT_NE(nullptr, query_str);
60
61 sqlite3_stmt *statement = NULL;
62 ASSERT_EQ(SQLITE_OK,
63 sqlite3_prepare_v2(sql_db, query_str, -1, &statement, NULL));
64 ASSERT_EQ(SQLITE_ROW, sqlite3_step(statement));
65 unsigned int len = sqlite3_column_bytes(statement, 0);
66 const unsigned char *reader = sqlite3_column_text(statement, 0);
67
68 ASSERT_NE(nullptr, reader);
69 ASSERT_EQ(133U, len);
70
71 // pkcs5PBES2, pkcs5PBKDF2
72 const uint8_t pkcs5_with_pbkdf2[] = {
73 0x30, 0x81, 0x82, 0x30, 0x6E, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
74 0xF7, 0x0D, 0x01, 0x05, 0x0D, 0x30, 0x61, 0x30, 0x42, 0x06, 0x09,
75 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C, 0x30, 0x35};
76 EXPECT_EQ(0, memcmp(reader, pkcs5_with_pbkdf2, sizeof(pkcs5_with_pbkdf2)));
77 reader += sizeof(pkcs5_with_pbkdf2);
78
79 // Skip over the 32B random salt
80 const uint8_t salt_prefix[] = {0x04, 0x20};
81 EXPECT_EQ(0, memcmp(reader, salt_prefix, sizeof(salt_prefix)));
82 reader += sizeof(salt_prefix) + 0x20;
83
84 // Expect 10000 iterations
85 const uint8_t iterations[] = {0x02, 0x02, 0x27, 0x10};
86 EXPECT_EQ(0, memcmp(reader, iterations, sizeof(iterations)));
87 reader += sizeof(iterations);
88
89 // hmacWithSHA256, aes256-CBC
90 const uint8_t oids[] = {0x02, 0x01, 0x20, 0x30, 0x0A, 0x06, 0x08,
91 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02,
92 0x09, 0x30, 0x1B, 0x06, 0x09, 0x60, 0x86,
93 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2A};
94 EXPECT_EQ(0, memcmp(reader, oids, sizeof(oids)));
95
96 EXPECT_EQ(SQLITE_OK, sqlite3_finalize(statement));
97 sqlite3_free(query_str);
98 sqlite3_close(sql_db);
99 }
100
TEST_F(SoftokenTest,ResetSoftokenEmptyPassword)101 TEST_F(SoftokenTest, ResetSoftokenEmptyPassword) {
102 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
103 ASSERT_TRUE(slot);
104 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
105 EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
106 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
107 }
108
TEST_F(SoftokenTest,ResetSoftokenNonEmptyPassword)109 TEST_F(SoftokenTest, ResetSoftokenNonEmptyPassword) {
110 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
111 ASSERT_TRUE(slot);
112 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
113 EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
114 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password2"));
115 }
116
117 // Test certificate to use in the CreateObject tests.
118 static const CK_OBJECT_CLASS cko_nss_trust = CKO_NSS_TRUST;
119 static const CK_BBOOL ck_false = CK_FALSE;
120 static const CK_BBOOL ck_true = CK_TRUE;
121 static const CK_TRUST ckt_nss_must_verify_trust = CKT_NSS_MUST_VERIFY_TRUST;
122 static const CK_TRUST ckt_nss_trusted_delegator = CKT_NSS_TRUSTED_DELEGATOR;
123 static const CK_ATTRIBUTE attributes[] = {
124 {CKA_CLASS, (void *)&cko_nss_trust, (PRUint32)sizeof(CK_OBJECT_CLASS)},
125 {CKA_TOKEN, (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL)},
126 {CKA_PRIVATE, (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL)},
127 {CKA_MODIFIABLE, (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL)},
128 {CKA_LABEL,
129 (void *)"Symantec Class 2 Public Primary Certification Authority - G4",
130 (PRUint32)61},
131 {CKA_CERT_SHA1_HASH,
132 (void *)"\147\044\220\056\110\001\260\042\226\100\020\106\264\261\147\054"
133 "\251\165\375\053",
134 (PRUint32)20},
135 {CKA_CERT_MD5_HASH,
136 (void *)"\160\325\060\361\332\224\227\324\327\164\337\276\355\150\336\226",
137 (PRUint32)16},
138 {CKA_ISSUER,
139 (void *)"\060\201\224\061\013\060\011\006\003\125\004\006\023\002\125\123"
140 "\061\035\060\033\006\003\125\004\012\023\024\123\171\155\141\156"
141 "\164\145\143\040\103\157\162\160\157\162\141\164\151\157\156\061"
142 "\037\060\035\006\003\125\004\013\023\026\123\171\155\141\156\164"
143 "\145\143\040\124\162\165\163\164\040\116\145\164\167\157\162\153"
144 "\061\105\060\103\006\003\125\004\003\023\074\123\171\155\141\156"
145 "\164\145\143\040\103\154\141\163\163\040\062\040\120\165\142\154"
146 "\151\143\040\120\162\151\155\141\162\171\040\103\145\162\164\151"
147 "\146\151\143\141\164\151\157\156\040\101\165\164\150\157\162\151"
148 "\164\171\040\055\040\107\064",
149 (PRUint32)151},
150 {CKA_SERIAL_NUMBER,
151 (void *)"\002\020\064\027\145\022\100\073\267\126\200\055\200\313\171\125"
152 "\246\036",
153 (PRUint32)18},
154 {CKA_TRUST_SERVER_AUTH, (void *)&ckt_nss_must_verify_trust,
155 (PRUint32)sizeof(CK_TRUST)},
156 {CKA_TRUST_EMAIL_PROTECTION, (void *)&ckt_nss_trusted_delegator,
157 (PRUint32)sizeof(CK_TRUST)},
158 {CKA_TRUST_CODE_SIGNING, (void *)&ckt_nss_must_verify_trust,
159 (PRUint32)sizeof(CK_TRUST)},
160 {CKA_TRUST_STEP_UP_APPROVED, (void *)&ck_false,
161 (PRUint32)sizeof(CK_BBOOL)}};
162
TEST_F(SoftokenTest,GetInvalidAttribute)163 TEST_F(SoftokenTest, GetInvalidAttribute) {
164 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
165 ASSERT_TRUE(slot);
166 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
167 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
168 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
169 ASSERT_NE(nullptr, obj);
170 SECItem out = {siBuffer, nullptr, 0};
171 SECStatus rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj.get(),
172 CKA_ALLOWED_MECHANISMS, &out);
173 EXPECT_EQ(SECFailure, rv);
174 // CKR_ATTRIBUTE_TYPE_INVALID maps to SEC_ERROR_BAD_DATA.
175 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
176 }
177
TEST_F(SoftokenTest,GetValidAttributes)178 TEST_F(SoftokenTest, GetValidAttributes) {
179 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
180 ASSERT_TRUE(slot);
181 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
182 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
183 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
184 ASSERT_NE(nullptr, obj);
185
186 CK_ATTRIBUTE template_attrs[] = {
187 {CKA_LABEL, NULL, 0},
188 {CKA_CERT_SHA1_HASH, NULL, 0},
189 {CKA_ISSUER, NULL, 0},
190 };
191 SECStatus rv =
192 PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
193 template_attrs, PR_ARRAY_SIZE(template_attrs));
194 EXPECT_EQ(SECSuccess, rv);
195 ASSERT_EQ(attributes[4].ulValueLen, template_attrs[0].ulValueLen);
196 EXPECT_EQ(0, memcmp(attributes[4].pValue, template_attrs[0].pValue,
197 template_attrs[0].ulValueLen));
198 ASSERT_EQ(attributes[5].ulValueLen, template_attrs[1].ulValueLen);
199 EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[1].pValue,
200 template_attrs[1].ulValueLen));
201 ASSERT_EQ(attributes[7].ulValueLen, template_attrs[2].ulValueLen);
202 EXPECT_EQ(0, memcmp(attributes[7].pValue, template_attrs[2].pValue,
203 template_attrs[2].ulValueLen));
204 for (unsigned int i = 0; i < PR_ARRAY_SIZE(template_attrs); i++) {
205 PORT_Free(template_attrs[i].pValue);
206 }
207 }
208
TEST_F(SoftokenTest,GetOnlyInvalidAttributes)209 TEST_F(SoftokenTest, GetOnlyInvalidAttributes) {
210 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
211 ASSERT_TRUE(slot);
212 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
213 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
214 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
215 ASSERT_NE(nullptr, obj);
216
217 // Provide buffers of sufficient size, so that token
218 // will write the data. This is annoying, but PK11_GetAttributes
219 // won't allocate in the cases below when a single attribute
220 // is missing. So, just put them all on the stack.
221 unsigned char buf1[100];
222 unsigned char buf2[100];
223 CK_ATTRIBUTE template_attrs[] = {{0xffffffffUL, buf1, sizeof(buf1)},
224 {0xfffffffeUL, buf2, sizeof(buf2)}};
225 SECStatus rv =
226 PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
227 template_attrs, PR_ARRAY_SIZE(template_attrs));
228 EXPECT_EQ(SECFailure, rv);
229 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
230
231 // MSVC rewards -1UL with a C4146 warning...
232 ASSERT_EQ(0UL, template_attrs[0].ulValueLen + 1);
233 ASSERT_EQ(0UL, template_attrs[1].ulValueLen + 1);
234 }
235
TEST_F(SoftokenTest,GetAttributesInvalidInterspersed1)236 TEST_F(SoftokenTest, GetAttributesInvalidInterspersed1) {
237 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
238 ASSERT_TRUE(slot);
239 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
240 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
241 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
242 ASSERT_NE(nullptr, obj);
243
244 unsigned char buf1[100];
245 unsigned char buf2[100];
246 unsigned char buf3[200];
247 CK_ATTRIBUTE template_attrs[] = {{0xffffffff, buf1, sizeof(buf1)},
248 {CKA_CERT_SHA1_HASH, buf2, sizeof(buf2)},
249 {CKA_ISSUER, buf3, sizeof(buf3)}};
250 SECStatus rv =
251 PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
252 template_attrs, PR_ARRAY_SIZE(template_attrs));
253 EXPECT_EQ(SECFailure, rv);
254 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
255 ASSERT_EQ(0UL, template_attrs[0].ulValueLen + 1);
256 ASSERT_EQ(attributes[5].ulValueLen, template_attrs[1].ulValueLen);
257 EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[1].pValue,
258 template_attrs[1].ulValueLen));
259 ASSERT_EQ(attributes[7].ulValueLen, template_attrs[2].ulValueLen);
260 EXPECT_EQ(0, memcmp(attributes[7].pValue, template_attrs[2].pValue,
261 template_attrs[2].ulValueLen));
262 }
263
TEST_F(SoftokenTest,GetAttributesInvalidInterspersed2)264 TEST_F(SoftokenTest, GetAttributesInvalidInterspersed2) {
265 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
266 ASSERT_TRUE(slot);
267 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
268 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
269 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
270 ASSERT_NE(nullptr, obj);
271
272 unsigned char buf1[100];
273 unsigned char buf2[100];
274 unsigned char buf3[100];
275 CK_ATTRIBUTE template_attrs[] = {{CKA_LABEL, buf1, sizeof(buf1)},
276 {CKA_CERT_SHA1_HASH, buf2, sizeof(buf2)},
277 {0xffffffffUL, buf3, sizeof(buf3)}};
278 SECStatus rv =
279 PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
280 template_attrs, PR_ARRAY_SIZE(template_attrs));
281 EXPECT_EQ(SECFailure, rv);
282 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
283 ASSERT_EQ(attributes[4].ulValueLen, template_attrs[0].ulValueLen);
284 EXPECT_EQ(0, memcmp(attributes[4].pValue, template_attrs[0].pValue,
285 template_attrs[0].ulValueLen));
286 ASSERT_EQ(attributes[5].ulValueLen, template_attrs[1].ulValueLen);
287 EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[1].pValue,
288 template_attrs[1].ulValueLen));
289 ASSERT_EQ(0UL, template_attrs[2].ulValueLen + 1);
290 }
291
TEST_F(SoftokenTest,GetAttributesInvalidInterspersed3)292 TEST_F(SoftokenTest, GetAttributesInvalidInterspersed3) {
293 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
294 ASSERT_TRUE(slot);
295 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
296 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
297 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
298 ASSERT_NE(nullptr, obj);
299
300 unsigned char buf1[100];
301 unsigned char buf2[100];
302 unsigned char buf3[100];
303 unsigned char buf4[100];
304 unsigned char buf5[100];
305 unsigned char buf6[200];
306 CK_ATTRIBUTE template_attrs[6] = {{CKA_LABEL, buf1, sizeof(buf1)},
307 {0xffffffffUL, buf2, sizeof(buf2)},
308 {0xfffffffeUL, buf3, sizeof(buf3)},
309 {CKA_CERT_SHA1_HASH, buf4, sizeof(buf4)},
310 {0xfffffffdUL, buf5, sizeof(buf5)},
311 {CKA_ISSUER, buf6, sizeof(buf6)}};
312 SECStatus rv =
313 PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
314 template_attrs, PR_ARRAY_SIZE(template_attrs));
315 EXPECT_EQ(SECFailure, rv);
316 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
317
318 ASSERT_EQ(attributes[4].ulValueLen, template_attrs[0].ulValueLen);
319 EXPECT_EQ(0, memcmp(attributes[4].pValue, template_attrs[0].pValue,
320 template_attrs[0].ulValueLen));
321 ASSERT_EQ(0UL, template_attrs[1].ulValueLen + 1);
322 ASSERT_EQ(0UL, template_attrs[2].ulValueLen + 1);
323 ASSERT_EQ(attributes[5].ulValueLen, template_attrs[3].ulValueLen);
324 EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[3].pValue,
325 template_attrs[3].ulValueLen));
326 ASSERT_EQ(0UL, template_attrs[4].ulValueLen + 1);
327 ASSERT_EQ(attributes[7].ulValueLen, template_attrs[5].ulValueLen);
328 EXPECT_EQ(0, memcmp(attributes[7].pValue, template_attrs[5].pValue,
329 template_attrs[5].ulValueLen));
330 }
331
TEST_F(SoftokenTest,CreateObjectNonEmptyPassword)332 TEST_F(SoftokenTest, CreateObjectNonEmptyPassword) {
333 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
334 ASSERT_TRUE(slot);
335 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
336 EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
337 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
338 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
339 EXPECT_EQ(nullptr, obj);
340 }
341
TEST_F(SoftokenTest,CreateObjectChangePassword)342 TEST_F(SoftokenTest, CreateObjectChangePassword) {
343 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
344 ASSERT_TRUE(slot);
345 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
346 EXPECT_EQ(SECSuccess, PK11_ChangePW(slot.get(), "", "password"));
347 EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
348 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
349 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
350 EXPECT_EQ(nullptr, obj);
351 }
352
353 // The size limit for a password is 500 characters as defined in pkcs11i.h
TEST_F(SoftokenTest,CreateObjectChangeToBigPassword)354 TEST_F(SoftokenTest, CreateObjectChangeToBigPassword) {
355 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
356 ASSERT_TRUE(slot);
357 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
358 EXPECT_EQ(
359 SECSuccess,
360 PK11_ChangePW(slot.get(), "",
361 "rUIFIFr2bxKnbJbitsfkyqttpk6vCJzlYMNxcxXcaN37gSZKbLk763X7iR"
362 "yeVNWZHQ02lSF69HYjzTyPW3318ZD0DBFMMbALZ8ZPZP73CIo5uIQlaowV"
363 "IbP8eOhRYtGUqoLGlcIFNEYogV8Q3GN58VeBMs0KxrIOvPQ9s8SnYYkqvt"
364 "zzgntmAvCgvk64x6eQf0okHwegd5wi6m0WVJytEepWXkP9J629FSa5kNT8"
365 "FvL3jvslkiImzTNuTvl32fQDXXMSc8vVk5Q3mH7trMZM0VDdwHWYERjHbz"
366 "kGxFgp0VhediHx7p9kkz6H6ac4et9sW4UkTnN7xhYc1Zr17wRSk2heQtcX"
367 "oZJGwuzhiKm8A8wkuVxms6zO56P4JORIk8oaUW6lyNTLo2kWWnTA"));
368 EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
369 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
370 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
371 EXPECT_EQ(nullptr, obj);
372 }
373
TEST_F(SoftokenTest,CreateObjectChangeToEmptyPassword)374 TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
375 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
376 ASSERT_TRUE(slot);
377 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
378 EXPECT_EQ(SECSuccess, PK11_ChangePW(slot.get(), "password", ""));
379 // PK11_Logout returnes an error and SEC_ERROR_TOKEN_NOT_LOGGED_IN if the user
380 // is not "logged in".
381 EXPECT_EQ(SECFailure, PK11_Logout(slot.get()));
382 EXPECT_EQ(SEC_ERROR_TOKEN_NOT_LOGGED_IN, PORT_GetError());
383 ScopedPK11GenericObject obj(PK11_CreateGenericObject(
384 slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
385 // Because there's no password we can't logout and the operation should have
386 // succeeded.
387 EXPECT_NE(nullptr, obj);
388 }
389
390 // We should be able to read CRLF, LF and CR.
391 // During the Initialization of the NSS Database, is called a function to load
392 // PKCS11 modules defined in pkcs11.txt. This file is read to get the
393 // specifications, parse them and load the modules. Here we are ensuring that
394 // the parsing will work correctly, independent of the breaking line format of
395 // pkcs11.txt file, which could vary depending where it was created.
396 // If the parsing is not well interpreted, the database cannot initialize.
TEST_F(SoftokenTest,CreateObjectReadBreakLine)397 TEST_F(SoftokenTest, CreateObjectReadBreakLine) {
398 const std::string path = mNSSDBDir.GetPath();
399 const std::string dbname_in = path + "/pkcs11.txt";
400 const std::string dbname_out_cr = path + "/pkcs11_cr.txt";
401 const std::string dbname_out_crlf = path + "/pkcs11_crlf.txt";
402 const std::string dbname_out_lf = path + "/pkcs11_lf.txt";
403
404 std::ifstream in(dbname_in);
405 ASSERT_TRUE(in);
406 std::ofstream out_cr(dbname_out_cr);
407 ASSERT_TRUE(out_cr);
408 std::ofstream out_crlf(dbname_out_crlf);
409 ASSERT_TRUE(out_crlf);
410 std::ofstream out_lf(dbname_out_lf);
411 ASSERT_TRUE(out_lf);
412
413 // Database should be correctly initialized by Setup()
414 ASSERT_TRUE(NSS_IsInitialized());
415 ASSERT_EQ(SECSuccess, NSS_Shutdown());
416
417 // Prepare the file formats with CR, CRLF and LF
418 for (std::string line; getline(in, line);) {
419 out_cr << line << "\r";
420 out_crlf << line << "\r\n";
421 out_lf << line << "\n";
422 }
423 in.close();
424 out_cr.close();
425 out_crlf.close();
426 out_lf.close();
427
428 // Change the pkcs11.txt to CR format.
429 ASSERT_TRUE(!remove(dbname_in.c_str()));
430 ASSERT_TRUE(!rename(dbname_out_cr.c_str(), dbname_in.c_str()));
431
432 // Try to initialize with CR format.
433 std::string nssInitArg("sql:");
434 nssInitArg.append(mNSSDBDir.GetUTF8Path());
435 ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
436 NSS_INIT_NOROOTINIT));
437 ASSERT_TRUE(NSS_IsInitialized());
438 ASSERT_EQ(SECSuccess, NSS_Shutdown());
439
440 // Change the pkcs11.txt to CRLF format.
441 ASSERT_TRUE(!remove(dbname_in.c_str()));
442 ASSERT_TRUE(!rename(dbname_out_crlf.c_str(), dbname_in.c_str()));
443
444 // Try to initialize with CRLF format.
445 ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
446 NSS_INIT_NOROOTINIT));
447 ASSERT_TRUE(NSS_IsInitialized());
448 ASSERT_EQ(SECSuccess, NSS_Shutdown());
449
450 // Change the pkcs11.txt to LF format.
451 ASSERT_TRUE(!remove(dbname_in.c_str()));
452 ASSERT_TRUE(!rename(dbname_out_lf.c_str(), dbname_in.c_str()));
453
454 // Try to initialize with LF format.
455 ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
456 NSS_INIT_NOROOTINIT));
457 ASSERT_TRUE(NSS_IsInitialized());
458 }
459
460 class SoftokenNonAsciiTest : public SoftokenTest {
461 protected:
SoftokenNonAsciiTest()462 SoftokenNonAsciiTest() : SoftokenTest("SoftokenTest.\xF7-") {}
463 };
464
TEST_F(SoftokenNonAsciiTest,NonAsciiPathWorking)465 TEST_F(SoftokenNonAsciiTest, NonAsciiPathWorking) {
466 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
467 ASSERT_TRUE(slot);
468 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
469 EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
470 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
471 }
472
473 // This is just any X509 certificate. Its contents don't matter.
474 static unsigned char certDER[] = {
475 0x30, 0x82, 0x01, 0xEF, 0x30, 0x82, 0x01, 0x94, 0xA0, 0x03, 0x02, 0x01,
476 0x02, 0x02, 0x14, 0x49, 0xC4, 0xC4, 0x4A, 0xB6, 0x86, 0x07, 0xA3, 0x06,
477 0xDC, 0x4D, 0xC8, 0xC3, 0xFE, 0xC7, 0x21, 0x3A, 0x2D, 0xE4, 0xDA, 0x30,
478 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
479 0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C,
480 0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31,
481 0x35, 0x31, 0x31, 0x32, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
482 0x18, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30,
483 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06,
484 0x03, 0x55, 0x04, 0x03, 0x0C, 0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x82,
485 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
486 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82,
487 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBA, 0x88, 0x51, 0xA8, 0x44,
488 0x8E, 0x16, 0xD6, 0x41, 0xFD, 0x6E, 0xB6, 0x88, 0x06, 0x36, 0x10, 0x3D,
489 0x3C, 0x13, 0xD9, 0xEA, 0xE4, 0x35, 0x4A, 0xB4, 0xEC, 0xF5, 0x68, 0x57,
490 0x6C, 0x24, 0x7B, 0xC1, 0xC7, 0x25, 0xA8, 0xE0, 0xD8, 0x1F, 0xBD, 0xB1,
491 0x9C, 0x06, 0x9B, 0x6E, 0x1A, 0x86, 0xF2, 0x6B, 0xE2, 0xAF, 0x5A, 0x75,
492 0x6B, 0x6A, 0x64, 0x71, 0x08, 0x7A, 0xA5, 0x5A, 0xA7, 0x45, 0x87, 0xF7,
493 0x1C, 0xD5, 0x24, 0x9C, 0x02, 0x7E, 0xCD, 0x43, 0xFC, 0x1E, 0x69, 0xD0,
494 0x38, 0x20, 0x29, 0x93, 0xAB, 0x20, 0xC3, 0x49, 0xE4, 0xDB, 0xB9, 0x4C,
495 0xC2, 0x6B, 0x6C, 0x0E, 0xED, 0x15, 0x82, 0x0F, 0xF1, 0x7E, 0xAD, 0x69,
496 0x1A, 0xB1, 0xD3, 0x02, 0x3A, 0x8B, 0x2A, 0x41, 0xEE, 0xA7, 0x70, 0xE0,
497 0x0F, 0x0D, 0x8D, 0xFD, 0x66, 0x0B, 0x2B, 0xB0, 0x24, 0x92, 0xA4, 0x7D,
498 0xB9, 0x88, 0x61, 0x79, 0x90, 0xB1, 0x57, 0x90, 0x3D, 0xD2, 0x3B, 0xC5,
499 0xE0, 0xB8, 0x48, 0x1F, 0xA8, 0x37, 0xD3, 0x88, 0x43, 0xEF, 0x27, 0x16,
500 0xD8, 0x55, 0xB7, 0x66, 0x5A, 0xAA, 0x7E, 0x02, 0x90, 0x2F, 0x3A, 0x7B,
501 0x10, 0x80, 0x06, 0x24, 0xCC, 0x1C, 0x6C, 0x97, 0xAD, 0x96, 0x61, 0x5B,
502 0xB7, 0xE2, 0x96, 0x12, 0xC0, 0x75, 0x31, 0xA3, 0x0C, 0x91, 0xDD, 0xB4,
503 0xCA, 0xF7, 0xFC, 0xAD, 0x1D, 0x25, 0xD3, 0x09, 0xEF, 0xB9, 0x17, 0x0E,
504 0xA7, 0x68, 0xE1, 0xB3, 0x7B, 0x2F, 0x22, 0x6F, 0x69, 0xE3, 0xB4, 0x8A,
505 0x95, 0x61, 0x1D, 0xEE, 0x26, 0xD6, 0x25, 0x9D, 0xAB, 0x91, 0x08, 0x4E,
506 0x36, 0xCB, 0x1C, 0x24, 0x04, 0x2C, 0xBF, 0x16, 0x8B, 0x2F, 0xE5, 0xF1,
507 0x8F, 0x99, 0x17, 0x31, 0xB8, 0xB3, 0xFE, 0x49, 0x23, 0xFA, 0x72, 0x51,
508 0xC4, 0x31, 0xD5, 0x03, 0xAC, 0xDA, 0x18, 0x0A, 0x35, 0xED, 0x8D, 0x02,
509 0x03, 0x01, 0x00, 0x01, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
510 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20,
511 0x5C, 0x75, 0x51, 0x9F, 0x13, 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20,
512 0xA3, 0xBC, 0x06, 0x30, 0x91, 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64,
513 0xEC, 0xFD, 0xCB, 0x42, 0x80, 0x0A, 0x70, 0xE6, 0x02, 0x21, 0x00, 0x82,
514 0x12, 0xF7, 0xE5, 0xEA, 0x40, 0x27, 0xFD, 0xF7, 0xC0, 0x0E, 0x25, 0xF3,
515 0x3E, 0x34, 0x95, 0x80, 0xB9, 0xA3, 0x38, 0xE0, 0x56, 0x68, 0xDA, 0xE5,
516 0xC1, 0xF5, 0x37, 0xC7, 0xB5, 0xCE, 0x0D};
517
518 struct PasswordPair {
519 const char *mInitialPassword;
520 const char *mSecondPassword;
521 };
522
523 class SoftokenPasswordChangeTest
524 : public SoftokenTest,
525 public ::testing::WithParamInterface<PasswordPair> {};
526
TEST_P(SoftokenPasswordChangeTest,KeepTrustAfterPasswordChange)527 TEST_P(SoftokenPasswordChangeTest, KeepTrustAfterPasswordChange) {
528 const PasswordPair &passwords = GetParam();
529 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
530 ASSERT_TRUE(slot);
531 // Set a password.
532 EXPECT_EQ(SECSuccess,
533 PK11_InitPin(slot.get(), nullptr, passwords.mInitialPassword));
534 SECItem certDERItem = {siBuffer, certDER, sizeof(certDER)};
535 // Import a certificate.
536 ScopedCERTCertificate cert(CERT_NewTempCertificate(
537 CERT_GetDefaultCertDB(), &certDERItem, nullptr, true, true));
538 EXPECT_TRUE(cert);
539 SECStatus result =
540 PK11_ImportCert(slot.get(), cert.get(), CK_INVALID_HANDLE, "test", false);
541 EXPECT_EQ(SECSuccess, result);
542 // Set a trust value.
543 CERTCertTrust trust = {CERTDB_TRUSTED_CLIENT_CA | CERTDB_NS_TRUSTED_CA |
544 CERTDB_TRUSTED_CA | CERTDB_VALID_CA,
545 0, 0};
546 result = CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
547 EXPECT_EQ(SECSuccess, result);
548 // Release the certificate to ensure we get it from the DB rather than an
549 // in-memory cache, below.
550 cert = nullptr;
551 // Change the password.
552 result = PK11_ChangePW(slot.get(), passwords.mInitialPassword,
553 passwords.mSecondPassword);
554 EXPECT_EQ(SECSuccess, result);
555 // Look up the certificate again.
556 ScopedCERTCertificate newCert(
557 PK11_FindCertFromDERCertItem(slot.get(), &certDERItem, nullptr));
558 EXPECT_TRUE(newCert.get());
559 // The trust should be the same as before.
560 CERTCertTrust newTrust = {0, 0, 0};
561 result = CERT_GetCertTrust(newCert.get(), &newTrust);
562 EXPECT_EQ(SECSuccess, result);
563 EXPECT_EQ(trust.sslFlags, newTrust.sslFlags);
564 EXPECT_EQ(trust.emailFlags, newTrust.emailFlags);
565 EXPECT_EQ(trust.objectSigningFlags, newTrust.objectSigningFlags);
566 }
567
568 static const PasswordPair PASSWORD_CHANGE_TESTS[] = {
569 {"password", ""}, // non-empty to empty password
570 {"", "password"}, // empty to non-empty password
571 {"password", "password2"}, // non-empty to non-empty password
572 };
573
574 INSTANTIATE_TEST_SUITE_P(SoftokenPasswordChangeTests,
575 SoftokenPasswordChangeTest,
576 ::testing::ValuesIn(PASSWORD_CHANGE_TESTS));
577
578 class SoftokenNoDBTest : public ::testing::Test {};
579
TEST_F(SoftokenNoDBTest,NeedUserInitNoDB)580 TEST_F(SoftokenNoDBTest, NeedUserInitNoDB) {
581 ASSERT_EQ(SECSuccess, NSS_NoDB_Init("."));
582 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
583 ASSERT_TRUE(slot);
584 EXPECT_EQ(PR_FALSE, PK11_NeedUserInit(slot.get()));
585
586 // When shutting down in here we have to release the slot first.
587 slot = nullptr;
588 ASSERT_EQ(SECSuccess, NSS_Shutdown());
589 }
590
test_dh_value(const PQGParams * params,const SECItem * pub_key_value,PRBool genFailOK,time_t * time)591 SECStatus test_dh_value(const PQGParams *params, const SECItem *pub_key_value,
592 PRBool genFailOK, time_t *time) {
593 SECKEYDHParams dh_params;
594 dh_params.base = params->base;
595 dh_params.prime = params->prime;
596
597 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
598 EXPECT_TRUE(slot);
599 if (!slot) return SECFailure;
600
601 /* create a private/public key pair in with the given params */
602 SECKEYPublicKey *pub_tmp = nullptr;
603 ScopedSECKEYPrivateKey priv_key(
604 PK11_GenerateKeyPair(slot.get(), CKM_DH_PKCS_KEY_PAIR_GEN, &dh_params,
605 &pub_tmp, PR_FALSE, PR_TRUE, nullptr));
606 if ((genFailOK) && ((priv_key.get() == nullptr) || (pub_tmp == nullptr))) {
607 return SECFailure;
608 }
609 EXPECT_NE(nullptr, priv_key.get()) << "PK11_GenerateKeyPair failed: "
610 << PORT_ErrorToName(PORT_GetError());
611 EXPECT_NE(nullptr, pub_tmp);
612 if ((priv_key.get() == nullptr) || (pub_tmp == nullptr)) return SECFailure;
613 ScopedSECKEYPublicKey pub_key(pub_tmp);
614 ScopedSECKEYPublicKey peer_pub_key_manager(nullptr);
615 SECKEYPublicKey *peer_pub_key = pub_key.get();
616
617 /* if a subprime has been given set it on the PKCS #11 key */
618 if (params->subPrime.data != nullptr) {
619 SECStatus rv;
620 EXPECT_EQ(SECSuccess, rv = PK11_WriteRawAttribute(
621 PK11_TypePrivKey, priv_key.get(), CKA_SUBPRIME,
622 (SECItem *)¶ms->subPrime))
623 << "PK11_WriteRawAttribute failed: "
624 << PORT_ErrorToString(PORT_GetError());
625 if (rv != SECSuccess) {
626 return rv;
627 }
628 }
629
630 /* find if we weren't passed a public value in, use the
631 * one we just generated */
632 if (pub_key_value && pub_key_value->data) {
633 peer_pub_key = SECKEY_CopyPublicKey(pub_key.get());
634 EXPECT_NE(nullptr, peer_pub_key);
635 if (peer_pub_key == nullptr) {
636 return SECFailure;
637 }
638 peer_pub_key->u.dh.publicValue = *pub_key_value;
639 peer_pub_key_manager.reset(peer_pub_key);
640 }
641
642 /* now do the derive. time it and return the time if
643 * the caller requested it. */
644 auto start = high_resolution_clock::now();
645 ScopedPK11SymKey derivedKey(PK11_PubDerive(
646 priv_key.get(), peer_pub_key, PR_FALSE, nullptr, nullptr,
647 CKM_DH_PKCS_DERIVE, CKM_HKDF_DERIVE, CKA_DERIVE, 32, nullptr));
648 auto stop = high_resolution_clock::now();
649 if (!derivedKey) {
650 std::cerr << "PK11_PubDerive failed: "
651 << PORT_ErrorToString(PORT_GetError()) << std::endl;
652 }
653
654 if (time) {
655 auto duration = duration_cast<microseconds>(stop - start);
656 *time = duration.count();
657 }
658 return derivedKey ? SECSuccess : SECFailure;
659 }
660
661 class SoftokenDhTest : public SoftokenTest {
662 protected:
SoftokenDhTest()663 SoftokenDhTest() : SoftokenTest("SoftokenDhTest.d-") {}
664 #ifdef NSS_USE_TIMING_CODE
665 time_t reference_time[CLASS_LAST] = {0};
666 #endif
667
SetUp()668 virtual void SetUp() {
669 SoftokenTest::SetUp();
670
671 #ifdef NSS_USE_TIMING_CODE
672 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
673 ASSERT_TRUE(slot);
674
675 time_t time;
676 for (int i = CLASS_FIRST; i < CLASS_LAST; i++) {
677 PQGParams params;
678 params.prime.data = (unsigned char *)reference_prime[i];
679 params.prime.len = reference_prime_len[i];
680 params.base.data = (unsigned char *)g2;
681 params.base.len = sizeof(g2);
682 params.subPrime.data = nullptr;
683 params.subPrime.len = 0;
684 ASSERT_EQ(SECSuccess, test_dh_value(¶ms, nullptr, PR_FALSE, &time));
685 reference_time[i] = time / 2 + 3 * time;
686 }
687 #endif
688 };
689 };
690
param_value(DhParamType param_type)691 const char *param_value(DhParamType param_type) {
692 switch (param_type) {
693 case TLS_APPROVED:
694 return "TLS_APPROVED";
695 case IKE_APPROVED:
696 return "IKE_APPROVED";
697 case SAFE_PRIME:
698 return "SAFE_PRIME";
699 case SAFE_PRIME_WITH_SUBPRIME:
700 return "SAFE_PRIME_WITH_SUBPRIME";
701 case KNOWN_SUBPRIME:
702 return "KNOWN_SUBPRIME";
703 case UNKNOWN_SUBPRIME:
704 return "UNKNOWN_SUBPRIME";
705 case WRONG_SUBPRIME:
706 return "WRONG_SUBPRIME";
707 case BAD_PUB_KEY:
708 return "BAD_PUB_KEY";
709 }
710 return "**Invalid**";
711 }
712
key_value(DhKeyClass key_class)713 const char *key_value(DhKeyClass key_class) {
714 switch (key_class) {
715 case CLASS_1536:
716 return "CLASS_1536";
717 case CLASS_2048:
718 return "CLASS_2048";
719 case CLASS_3072:
720 return "CLASS_3072";
721 case CLASS_4096:
722 return "CLASS_4096";
723 case CLASS_6144:
724 return "CLASS_6144";
725 case CLASS_8192:
726 return "CLASS_8192";
727 case CLASS_LAST:
728 break;
729 }
730 return "**Invalid**";
731 }
732
733 class SoftokenDhValidate : public SoftokenDhTest,
734 public ::testing::WithParamInterface<DhTestVector> {
735 };
736
737 /* test the DH validation process. In non-fips mode, only BAD_PUB_KEY tests
738 * should fail */
TEST_P(SoftokenDhValidate,DhVectors)739 TEST_P(SoftokenDhValidate, DhVectors) {
740 const DhTestVector dhTestValues = GetParam();
741 std::string testId = (char *)(dhTestValues.id);
742 std::string err = "Test(" + testId + ") failed";
743 SECStatus rv;
744 time_t time;
745
746 PQGParams params;
747 params.prime = dhTestValues.p;
748 params.base = dhTestValues.g;
749 params.subPrime = dhTestValues.q;
750
751 std::cerr << "Test: " + testId << std::endl
752 << "param_type: " << param_value(dhTestValues.param_type)
753 << ", key_class: " << key_value(dhTestValues.key_class) << std::endl
754 << "p: " << DataBuffer(dhTestValues.p.data, dhTestValues.p.len)
755 << std::endl
756 << "g: " << DataBuffer(dhTestValues.g.data, dhTestValues.g.len)
757 << std::endl
758 << "q: " << DataBuffer(dhTestValues.q.data, dhTestValues.q.len)
759 << std::endl
760 << "pub_key: "
761 << DataBuffer(dhTestValues.pub_key.data, dhTestValues.pub_key.len)
762 << std::endl;
763 rv = test_dh_value(¶ms, &dhTestValues.pub_key, PR_FALSE, &time);
764
765 switch (dhTestValues.param_type) {
766 case TLS_APPROVED:
767 case IKE_APPROVED:
768 case SAFE_PRIME:
769 case UNKNOWN_SUBPRIME:
770 EXPECT_EQ(SECSuccess, rv) << err;
771 #ifdef NSS_USE_TIMING_CODE
772 EXPECT_LE(time, reference_time[dhTestValues.key_class]) << err;
773 #endif
774 break;
775 case KNOWN_SUBPRIME:
776 case SAFE_PRIME_WITH_SUBPRIME:
777 EXPECT_EQ(SECSuccess, rv) << err;
778 #ifdef NSS_USE_TIMING_CODE
779 EXPECT_GT(time, reference_time[dhTestValues.key_class]) << err;
780 #endif
781 break;
782 case WRONG_SUBPRIME:
783 case BAD_PUB_KEY:
784 EXPECT_EQ(SECFailure, rv) << err;
785 break;
786 }
787 }
788
789 INSTANTIATE_TEST_SUITE_P(DhValidateCases, SoftokenDhValidate,
790 ::testing::ValuesIn(DH_TEST_VECTORS));
791
792 #ifndef NSS_FIPS_DISABLED
793
794 class SoftokenFipsTest : public SoftokenTest {
795 protected:
SoftokenFipsTest()796 SoftokenFipsTest() : SoftokenTest("SoftokenFipsTest.d-") {}
SoftokenFipsTest(const std::string & prefix)797 SoftokenFipsTest(const std::string &prefix) : SoftokenTest(prefix) {}
798
SetUp()799 virtual void SetUp() {
800 SoftokenTest::SetUp();
801
802 // Turn on FIPS mode (code borrowed from FipsMode in modutil/pk11.c)
803 char *internal_name;
804 ASSERT_FALSE(PK11_IsFIPS());
805 internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName);
806 ASSERT_EQ(SECSuccess, SECMOD_DeleteInternalModule(internal_name))
807 << PORT_ErrorToName(PORT_GetError());
808 PR_smprintf_free(internal_name);
809 ASSERT_TRUE(PK11_IsFIPS());
810 }
811 };
812
813 class SoftokenFipsDhTest : public SoftokenFipsTest {
814 protected:
SoftokenFipsDhTest()815 SoftokenFipsDhTest() : SoftokenFipsTest("SoftokenFipsDhTest.d-") {}
816 #ifdef NSS_USE_TIMING_CODE
817 time_t reference_time[CLASS_LAST] = {0};
818 #endif
819
SetUp()820 virtual void SetUp() {
821 SoftokenFipsTest::SetUp();
822
823 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
824 ASSERT_TRUE(slot);
825
826 ASSERT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, ""));
827 ASSERT_EQ(SECSuccess, PK11_Authenticate(slot.get(), PR_FALSE, nullptr));
828
829 #ifdef NSS_USE_TIMING_CODE
830 time_t time;
831 for (int i = CLASS_FIRST; i < CLASS_LAST; i++) {
832 PQGParams params;
833 params.prime.data = (unsigned char *)reference_prime[i];
834 params.prime.len = reference_prime_len[i];
835 params.base.data = (unsigned char *)g2;
836 params.base.len = sizeof(g2);
837 params.subPrime.data = nullptr;
838 params.subPrime.len = 0;
839 ASSERT_EQ(SECSuccess, test_dh_value(¶ms, nullptr, PR_FALSE, &time));
840 reference_time[i] = time / 2 + 3 * time;
841 }
842 #endif
843 };
844 };
845
846 const std::vector<std::string> kFipsPasswordCases[] = {
847 // FIPS level1 -> level1 -> level1
848 {"", "", ""},
849 // FIPS level1 -> level1 -> level2
850 {"", "", "strong-_123"},
851 // FIXME: this should work: FIPS level1 -> level2 -> level2
852 // {"", "strong-_123", "strong-_456"},
853 // FIPS level2 -> level2 -> level2
854 {"strong-_123", "strong-_456", "strong-_123"}};
855
856 const std::vector<std::string> kFipsPasswordBadCases[] = {
857 // FIPS level1 -> level2 -> level1
858 {"", "strong-_123", ""},
859 // FIPS level2 -> level1 -> level1
860 {"strong-_123", ""},
861 // FIPS level2 -> level2 -> level1
862 {"strong-_123", "strong-_456", ""},
863 // initialize with a weak password
864 {"weak"},
865 // FIPS level1 -> weak password
866 {"", "weak"},
867 // FIPS level2 -> weak password
868 {"strong-_123", "weak"}};
869
870 class SoftokenFipsPasswordTest
871 : public SoftokenFipsTest,
872 public ::testing::WithParamInterface<std::vector<std::string>> {};
873
874 class SoftokenFipsBadPasswordTest
875 : public SoftokenFipsTest,
876 public ::testing::WithParamInterface<std::vector<std::string>> {};
877
TEST_P(SoftokenFipsPasswordTest,SetPassword)878 TEST_P(SoftokenFipsPasswordTest, SetPassword) {
879 const std::vector<std::string> &passwords = GetParam();
880 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
881 ASSERT_TRUE(slot);
882
883 auto it = passwords.begin();
884 auto prev_it = it;
885 EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, (*it).c_str()));
886 for (it++; it != passwords.end(); it++, prev_it++) {
887 EXPECT_EQ(SECSuccess,
888 PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str()));
889 }
890 }
891
TEST_P(SoftokenFipsBadPasswordTest,SetBadPassword)892 TEST_P(SoftokenFipsBadPasswordTest, SetBadPassword) {
893 const std::vector<std::string> &passwords = GetParam();
894 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
895 ASSERT_TRUE(slot);
896
897 auto it = passwords.begin();
898 auto prev_it = it;
899 SECStatus rv = PK11_InitPin(slot.get(), nullptr, (*it).c_str());
900 if (it + 1 == passwords.end())
901 EXPECT_EQ(SECFailure, rv);
902 else
903 EXPECT_EQ(SECSuccess, rv);
904 for (it++; it != passwords.end(); it++, prev_it++) {
905 rv = PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str());
906 if (it + 1 == passwords.end())
907 EXPECT_EQ(SECFailure, rv);
908 else
909 EXPECT_EQ(SECSuccess, rv);
910 }
911 }
912
913 class SoftokenFipsDhValidate
914 : public SoftokenFipsDhTest,
915 public ::testing::WithParamInterface<DhTestVector> {};
916
917 /* test the DH validation process. In fips mode, primes with unknown
918 * subprimes, and all sorts of bad public keys should fail */
TEST_P(SoftokenFipsDhValidate,DhVectors)919 TEST_P(SoftokenFipsDhValidate, DhVectors) {
920 const DhTestVector dhTestValues = GetParam();
921 std::string testId = (char *)(dhTestValues.id);
922 std::string err = "Test(" + testId + ") failed";
923 time_t time;
924 PRBool genFailOK = PR_FALSE;
925 SECStatus rv;
926
927 PQGParams params;
928 params.prime = dhTestValues.p;
929 params.base = dhTestValues.g;
930 params.subPrime = dhTestValues.q;
931 std::cerr << "Test:" + testId << std::endl
932 << "param_type: " << param_value(dhTestValues.param_type)
933 << ", key_class: " << key_value(dhTestValues.key_class) << std::endl
934 << "p: " << DataBuffer(dhTestValues.p.data, dhTestValues.p.len)
935 << std::endl
936 << "g: " << DataBuffer(dhTestValues.g.data, dhTestValues.g.len)
937 << std::endl
938 << "q: " << DataBuffer(dhTestValues.q.data, dhTestValues.q.len)
939 << std::endl
940 << "pub_key: "
941 << DataBuffer(dhTestValues.pub_key.data, dhTestValues.pub_key.len)
942 << std::endl;
943
944 if ((dhTestValues.param_type != TLS_APPROVED) &&
945 (dhTestValues.param_type != IKE_APPROVED)) {
946 genFailOK = PR_TRUE;
947 }
948 rv = test_dh_value(¶ms, &dhTestValues.pub_key, genFailOK, &time);
949
950 switch (dhTestValues.param_type) {
951 case TLS_APPROVED:
952 case IKE_APPROVED:
953 EXPECT_EQ(SECSuccess, rv) << err;
954 #ifdef NSS_USE_TIMING_CODE
955 EXPECT_LE(time, reference_time[dhTestValues.key_class]) << err;
956 #endif
957 break;
958 case SAFE_PRIME:
959 case SAFE_PRIME_WITH_SUBPRIME:
960 case KNOWN_SUBPRIME:
961 case UNKNOWN_SUBPRIME:
962 case WRONG_SUBPRIME:
963 case BAD_PUB_KEY:
964 EXPECT_EQ(SECFailure, rv) << err;
965 break;
966 }
967 }
968
969 INSTANTIATE_TEST_SUITE_P(FipsPasswordCases, SoftokenFipsPasswordTest,
970 ::testing::ValuesIn(kFipsPasswordCases));
971
972 INSTANTIATE_TEST_SUITE_P(BadFipsPasswordCases, SoftokenFipsBadPasswordTest,
973 ::testing::ValuesIn(kFipsPasswordBadCases));
974
975 INSTANTIATE_TEST_SUITE_P(FipsDhCases, SoftokenFipsDhValidate,
976 ::testing::ValuesIn(DH_TEST_VECTORS));
977 #endif
978
979 } // namespace nss_test
980
main(int argc,char ** argv)981 int main(int argc, char **argv) {
982 ::testing::InitGoogleTest(&argc, argv);
983
984 return RUN_ALL_TESTS();
985 }
986