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 *)&params->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(&params, 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(&params, &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(&params, 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(&params, &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