1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/utility/importer/nss_decryptor_win.h" 6 7 #include "base/files/file_path.h" 8 #include "base/strings/sys_string_conversions.h" 9 10 namespace { 11 12 typedef BOOL (WINAPI* SetDllDirectoryFunc)(LPCTSTR lpPathName); 13 14 // A helper class whose destructor calls SetDllDirectory(NULL) to undo the 15 // effects of a previous SetDllDirectory call. 16 class SetDllDirectoryCaller { 17 public: 18 explicit SetDllDirectoryCaller() : func_(NULL) { } 19 20 ~SetDllDirectoryCaller() { 21 if (func_) 22 func_(NULL); 23 } 24 25 // Sets the SetDllDirectory function pointer to activates this object. 26 void set_func(SetDllDirectoryFunc func) { func_ = func; } 27 28 private: 29 SetDllDirectoryFunc func_; 30 }; 31 32 } // namespace 33 34 // static 35 const wchar_t NSSDecryptor::kNSS3Library[] = L"nss3.dll"; 36 const wchar_t NSSDecryptor::kSoftokn3Library[] = L"softokn3.dll"; 37 const wchar_t NSSDecryptor::kPLDS4Library[] = L"plds4.dll"; 38 const wchar_t NSSDecryptor::kNSPR4Library[] = L"nspr4.dll"; 39 40 bool NSSDecryptor::Init(const base::FilePath& dll_path, 41 const base::FilePath& db_path) { 42 // We call SetDllDirectory to work around a Purify bug (GetModuleHandle 43 // fails inside Purify under certain conditions). SetDllDirectory only 44 // exists on Windows XP SP1 or later, so we look up its address at run time. 45 HMODULE kernel32_dll = GetModuleHandle(L"kernel32.dll"); 46 if (kernel32_dll == NULL) 47 return false; 48 SetDllDirectoryFunc set_dll_directory = 49 (SetDllDirectoryFunc)GetProcAddress(kernel32_dll, "SetDllDirectoryW"); 50 SetDllDirectoryCaller caller; 51 52 if (set_dll_directory != NULL) { 53 if (!set_dll_directory(dll_path.value().c_str())) 54 return false; 55 caller.set_func(set_dll_directory); 56 nss3_dll_ = LoadLibrary(kNSS3Library); 57 if (nss3_dll_ == NULL) 58 return false; 59 } else { 60 // Fall back on LoadLibraryEx if SetDllDirectory isn't available. We 61 // actually prefer this method because it doesn't change the DLL search 62 // path, which is a process-wide property. 63 base::FilePath path = dll_path.Append(kNSS3Library); 64 nss3_dll_ = LoadLibraryEx(path.value().c_str(), NULL, 65 LOAD_WITH_ALTERED_SEARCH_PATH); 66 if (nss3_dll_ == NULL) 67 return false; 68 69 // Firefox 2 uses NSS 3.11. Firefox 3 uses NSS 3.12. NSS 3.12 has two 70 // changes in its DLLs: 71 // 1. nss3.dll is not linked with softokn3.dll at build time, but rather 72 // loads softokn3.dll using LoadLibrary in NSS_Init. 73 // 2. softokn3.dll has a new dependency sqlite3.dll. 74 // NSS_Init's LoadLibrary call has trouble finding sqlite3.dll. To help 75 // it out, we preload softokn3.dll using LoadLibraryEx with the 76 // LOAD_WITH_ALTERED_SEARCH_PATH flag. This helps because LoadLibrary 77 // doesn't load a DLL again if it's already loaded. This workaround is 78 // harmless for NSS 3.11. 79 path = base::FilePath(dll_path).Append(kSoftokn3Library); 80 softokn3_dll_ = LoadLibraryEx(path.value().c_str(), NULL, 81 LOAD_WITH_ALTERED_SEARCH_PATH); 82 if (softokn3_dll_ == NULL) { 83 Free(); 84 return false; 85 } 86 } 87 HMODULE plds4_dll = GetModuleHandle(kPLDS4Library); 88 HMODULE nspr4_dll = GetModuleHandle(kNSPR4Library); 89 90 // On Firefox 22 and higher, NSPR is part of nss3.dll rather than separate 91 // DLLs. 92 if (plds4_dll == NULL) { 93 plds4_dll = nss3_dll_; 94 nspr4_dll = nss3_dll_; 95 } 96 return InitNSS(db_path, plds4_dll, nspr4_dll); 97 } 98 99 NSSDecryptor::NSSDecryptor() 100 : NSS_Init(NULL), NSS_Shutdown(NULL), PK11_GetInternalKeySlot(NULL), 101 PK11_CheckUserPassword(NULL), PK11_FreeSlot(NULL), 102 PK11_Authenticate(NULL), PK11SDR_Decrypt(NULL), SECITEM_FreeItem(NULL), 103 PL_ArenaFinish(NULL), PR_Cleanup(NULL), 104 nss3_dll_(NULL), softokn3_dll_(NULL), 105 is_nss_initialized_(false) { 106 } 107 108 NSSDecryptor::~NSSDecryptor() { 109 Free(); 110 } 111 112 bool NSSDecryptor::InitNSS(const base::FilePath& db_path, 113 base::NativeLibrary plds4_dll, 114 base::NativeLibrary nspr4_dll) { 115 // Gets the function address. 116 NSS_Init = (NSSInitFunc) 117 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Init"); 118 NSS_Shutdown = (NSSShutdownFunc) 119 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Shutdown"); 120 PK11_GetInternalKeySlot = (PK11GetInternalKeySlotFunc) 121 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, 122 "PK11_GetInternalKeySlot"); 123 PK11_FreeSlot = (PK11FreeSlotFunc) 124 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_FreeSlot"); 125 PK11_Authenticate = (PK11AuthenticateFunc) 126 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_Authenticate"); 127 PK11SDR_Decrypt = (PK11SDRDecryptFunc) 128 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11SDR_Decrypt"); 129 SECITEM_FreeItem = (SECITEMFreeItemFunc) 130 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "SECITEM_FreeItem"); 131 PL_ArenaFinish = (PLArenaFinishFunc) 132 base::GetFunctionPointerFromNativeLibrary(plds4_dll, "PL_ArenaFinish"); 133 PR_Cleanup = (PRCleanupFunc) 134 base::GetFunctionPointerFromNativeLibrary(nspr4_dll, "PR_Cleanup"); 135 136 if (NSS_Init == NULL || NSS_Shutdown == NULL || 137 PK11_GetInternalKeySlot == NULL || PK11_FreeSlot == NULL || 138 PK11_Authenticate == NULL || PK11SDR_Decrypt == NULL || 139 SECITEM_FreeItem == NULL || PL_ArenaFinish == NULL || 140 PR_Cleanup == NULL) { 141 Free(); 142 return false; 143 } 144 145 SECStatus result = NSS_Init(base::SysWideToNativeMB(db_path.value()).c_str()); 146 if (result != SECSuccess) { 147 Free(); 148 return false; 149 } 150 151 is_nss_initialized_ = true; 152 return true; 153 } 154 155 void NSSDecryptor::Free() { 156 if (is_nss_initialized_) { 157 NSS_Shutdown(); 158 PL_ArenaFinish(); 159 PR_Cleanup(); 160 is_nss_initialized_ = false; 161 } 162 if (softokn3_dll_ != NULL) 163 base::UnloadNativeLibrary(softokn3_dll_); 164 if (nss3_dll_ != NULL) 165 base::UnloadNativeLibrary(nss3_dll_); 166 NSS_Init = NULL; 167 NSS_Shutdown = NULL; 168 PK11_GetInternalKeySlot = NULL; 169 PK11_FreeSlot = NULL; 170 PK11_Authenticate = NULL; 171 PK11SDR_Decrypt = NULL; 172 SECITEM_FreeItem = NULL; 173 PL_ArenaFinish = NULL; 174 PR_Cleanup = NULL; 175 nss3_dll_ = NULL; 176 softokn3_dll_ = NULL; 177 } 178