pk11_module_unittest.cc (7749B)
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 "nss.h" 9 #include "pk11pub.h" 10 #include "prerror.h" 11 #include "prsystem.h" 12 #include "secoid.h" 13 14 #include "nss_scoped_ptrs.h" 15 #include "gtest/gtest.h" 16 #include "databuffer.h" 17 18 namespace nss_test { 19 20 class Pkcs11ModuleTest : public ::testing::Test { 21 public: 22 Pkcs11ModuleTest() {} 23 24 void SetUp() override { 25 ASSERT_EQ(SECSuccess, SECMOD_AddNewModule( 26 "Pkcs11ModuleTest", 27 DLL_PREFIX "pkcs11testmodule." DLL_SUFFIX, 0, 0)) 28 << PORT_ErrorToName(PORT_GetError()); 29 } 30 31 void TearDown() override { 32 int type; 33 ASSERT_EQ(SECSuccess, SECMOD_DeleteModule("Pkcs11ModuleTest", &type)); 34 ASSERT_EQ(SECMOD_EXTERNAL, type); 35 } 36 }; 37 38 TEST_F(Pkcs11ModuleTest, LoadUnload) { 39 ScopedSECMODModule module(SECMOD_FindModule("Pkcs11ModuleTest")); 40 EXPECT_NE(nullptr, module); 41 } 42 43 TEST_F(Pkcs11ModuleTest, ListSlots) { 44 ScopedPK11SlotList slots( 45 PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, nullptr)); 46 ASSERT_NE(nullptr, slots); 47 48 PK11SlotListElement *element = PK11_GetFirstSafe(slots.get()); 49 ASSERT_NE(nullptr, element); 50 51 // These tokens are always present. 52 const std::vector<std::string> kSlotsWithToken = { 53 "NSS Internal Cryptographic Services", 54 "NSS User Private Key and Certificate Services", 55 "Test PKCS11 Public Certs Slot", "Test PKCS11 Slot 二"}; 56 std::vector<std::string> foundSlots; 57 58 do { 59 std::string name = PK11_GetSlotName(element->slot); 60 foundSlots.push_back(name); 61 std::cerr << "loaded slot: " << name << std::endl; 62 } while ((element = PK11_GetNextSafe(slots.get(), element, PR_FALSE)) != 63 nullptr); 64 65 std::sort(foundSlots.begin(), foundSlots.end()); 66 EXPECT_TRUE(std::equal(kSlotsWithToken.begin(), kSlotsWithToken.end(), 67 foundSlots.begin())); 68 } 69 70 TEST_F(Pkcs11ModuleTest, PublicCertificatesToken) { 71 const std::string kRegularToken = "Test PKCS11 Tokeñ 2 Label"; 72 const std::string kPublicCertificatesToken = "Test PKCS11 Public Certs Token"; 73 74 ScopedPK11SlotInfo slot1(PK11_FindSlotByName(kRegularToken.c_str())); 75 ASSERT_NE(nullptr, slot1); 76 EXPECT_FALSE(PK11_IsFriendly(slot1.get())); 77 78 ScopedPK11SlotInfo slot2( 79 PK11_FindSlotByName(kPublicCertificatesToken.c_str())); 80 ASSERT_NE(nullptr, slot2); 81 EXPECT_TRUE(PK11_IsFriendly(slot2.get())); 82 } 83 84 TEST_F(Pkcs11ModuleTest, PublicCertificatesTokenLookup) { 85 const std::string kCertUrl = 86 "pkcs11:id=%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f"; 87 88 ScopedCERTCertList certsByUrl( 89 PK11_FindCertsFromURI(kCertUrl.c_str(), nullptr)); 90 EXPECT_NE(nullptr, certsByUrl.get()); 91 92 size_t count = 0; 93 CERTCertificate *certByUrl = nullptr; 94 for (CERTCertListNode *node = CERT_LIST_HEAD(certsByUrl); 95 !CERT_LIST_END(node, certsByUrl); node = CERT_LIST_NEXT(node)) { 96 if (count == 0) { 97 certByUrl = node->cert; 98 } 99 count++; 100 } 101 EXPECT_EQ(1UL, count); 102 EXPECT_NE(nullptr, certByUrl); 103 104 EXPECT_EQ( 105 0, strcmp(certByUrl->nickname, "Test PKCS11 Public Certs Token:cert2")); 106 } 107 108 TEST_F(Pkcs11ModuleTest, PublicCertificatesTokenLookupNoMatch) { 109 const std::string kCertUrl = 110 "pkcs11:id=%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0e"; 111 112 ScopedCERTCertList certsByUrl( 113 PK11_FindCertsFromURI(kCertUrl.c_str(), nullptr)); 114 EXPECT_EQ(nullptr, certsByUrl.get()); 115 } 116 117 #if defined(_WIN32) 118 #include <windows.h> 119 120 class Pkcs11NonAsciiTest : public ::testing::Test { 121 WCHAR nonAsciiModuleName[MAX_PATH]; 122 123 public: 124 Pkcs11NonAsciiTest() {} 125 126 void SetUp() override { 127 WCHAR originalModuleName[MAX_PATH]; 128 LPWSTR filePart; 129 DWORD count = SearchPathW(NULL, L"pkcs11testmodule.dll", NULL, MAX_PATH, 130 nonAsciiModuleName, &filePart); 131 ASSERT_TRUE(count); 132 wcscpy(originalModuleName, nonAsciiModuleName); 133 wcscpy(filePart, L"pkcs11testmodule\u2665.dll"); 134 BOOL result = CopyFileW(originalModuleName, nonAsciiModuleName, TRUE); 135 ASSERT_TRUE(result); 136 ASSERT_EQ(SECSuccess, 137 SECMOD_AddNewModule( 138 "Pkcs11NonAsciiTest", 139 DLL_PREFIX "pkcs11testmodule\xE2\x99\xA5." DLL_SUFFIX, 0, 0)) 140 << PORT_ErrorToName(PORT_GetError()); 141 } 142 143 void TearDown() override { 144 int type; 145 ASSERT_EQ(SECSuccess, SECMOD_DeleteModule("Pkcs11NonAsciiTest", &type)); 146 ASSERT_EQ(SECMOD_EXTERNAL, type); 147 BOOL result = DeleteFileW(nonAsciiModuleName); 148 ASSERT_TRUE(result); 149 } 150 }; 151 152 TEST_F(Pkcs11NonAsciiTest, LoadUnload) { 153 ScopedSECMODModule module(SECMOD_FindModule("Pkcs11NonAsciiTest")); 154 EXPECT_NE(nullptr, module); 155 } 156 #endif // defined(_WIN32) 157 158 class Pkcs11ModuleLoadFunctionTest : public ::testing::Test { 159 public: 160 Pkcs11ModuleLoadFunctionTest() { library = NULL; }; 161 162 void TearDown() override { 163 if (library != NULL) { 164 PR_UnloadLibrary(library); 165 } 166 } 167 PRLibrary *library; 168 }; 169 170 CK_RV NotSuppoted_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { 171 return CKR_FUNCTION_NOT_SUPPORTED; 172 } 173 174 CK_RV SupportedButNull(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { 175 ppFunctionList = NULL; 176 return CKR_OK; 177 } 178 179 TEST_F(Pkcs11ModuleLoadFunctionTest, LoadModuleWithNullFunc) { 180 ScopedSECMODModule userModule( 181 SECMOD_LoadUserModuleWithFunction("LoadFunctionModule", NULL)); 182 EXPECT_NE(userModule, nullptr); 183 EXPECT_FALSE(userModule->loaded); 184 } 185 186 TEST_F(Pkcs11ModuleLoadFunctionTest, LoadModuleWithUnsupportedFunc) { 187 ScopedSECMODModule userModule(SECMOD_LoadUserModuleWithFunction( 188 "LoadFunctionModule", &NotSuppoted_GetFunctionList)); 189 EXPECT_FALSE(userModule->loaded); 190 } 191 192 TEST_F(Pkcs11ModuleLoadFunctionTest, LoadModuleWithEmptyFunctionList) { 193 ScopedSECMODModule userModule(SECMOD_LoadUserModuleWithFunction( 194 "LoadFunctionModule", &SupportedButNull)); 195 EXPECT_NE(userModule, nullptr); 196 EXPECT_FALSE(userModule->loaded); 197 } 198 199 TEST_F(Pkcs11ModuleLoadFunctionTest, SuccessLoadModuleWithFunction) { 200 library = PR_LoadLibrary(DLL_PREFIX "pkcs11testmodule." DLL_SUFFIX); 201 EXPECT_NE(nullptr, library); 202 203 CK_C_GetFunctionList fentry = NULL; 204 fentry = (CK_C_GetFunctionList)PR_FindSymbol(library, "C_GetFunctionList"); 205 EXPECT_NE(nullptr, fentry); 206 207 ScopedSECMODModule userModule( 208 SECMOD_LoadUserModuleWithFunction("LoadFunctionModule", fentry)); 209 EXPECT_NE(nullptr, userModule); 210 EXPECT_EQ(userModule->loaded, PR_TRUE); 211 212 /* We can find the module*/ 213 ScopedSECMODModule module(SECMOD_FindModule("LoadFunctionModule")); 214 EXPECT_NE(nullptr, module); 215 216 CK_INFO info; 217 EXPECT_EQ(SECSuccess, PK11_GetModInfo(userModule.get(), &info)); 218 /* See pkcs11testmodule.cpp */ 219 CK_VERSION expectedCryptokiVersion = {2, 2}; 220 CK_VERSION expectedLibraryVersion = {0, 0}; 221 EXPECT_EQ(info.cryptokiVersion.minor, expectedCryptokiVersion.minor); 222 EXPECT_EQ(info.cryptokiVersion.major, expectedCryptokiVersion.major); 223 224 EXPECT_EQ( 225 0, PORT_Memcmp((char *)info.manufacturerID, "Test PKCS11 Manufacturer ID", 226 sizeof("Test PKCS11 Manufacturer ID") - 1)); 227 EXPECT_EQ(info.flags, 0UL); 228 229 EXPECT_EQ(0, 230 PORT_Memcmp((char *)info.libraryDescription, "Test PKCS11 Library", 231 sizeof("Test PKCS11 Library") - 1)); 232 EXPECT_EQ(info.libraryVersion.minor, expectedLibraryVersion.minor); 233 EXPECT_EQ(info.libraryVersion.major, expectedLibraryVersion.major); 234 235 EXPECT_EQ(SECSuccess, SECMOD_UnloadUserModule(userModule.get())); 236 } 237 238 } // namespace nss_test