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/browser/importer/nss_decryptor_win.h" 6 7 #include "base/file_path.h" 8 #include "base/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 FilePath& dll_path, const FilePath& db_path) { 41 // We call SetDllDirectory to work around a Purify bug (GetModuleHandle 42 // fails inside Purify under certain conditions). SetDllDirectory only 43 // exists on Windows XP SP1 or later, so we look up its address at run time. 44 HMODULE kernel32_dll = GetModuleHandle(L"kernel32.dll"); 45 if (kernel32_dll == NULL) 46 return false; 47 SetDllDirectoryFunc set_dll_directory = 48 (SetDllDirectoryFunc)GetProcAddress(kernel32_dll, "SetDllDirectoryW"); 49 SetDllDirectoryCaller caller; 50 51 if (set_dll_directory != NULL) { 52 if (!set_dll_directory(dll_path.value().c_str())) 53 return false; 54 caller.set_func(set_dll_directory); 55 nss3_dll_ = LoadLibrary(kNSS3Library); 56 if (nss3_dll_ == NULL) 57 return false; 58 } else { 59 // Fall back on LoadLibraryEx if SetDllDirectory isn't available. We 60 // actually prefer this method because it doesn't change the DLL search 61 // path, which is a process-wide property. 62 FilePath path = dll_path.Append(kNSS3Library); 63 nss3_dll_ = LoadLibraryEx(path.value().c_str(), NULL, 64 LOAD_WITH_ALTERED_SEARCH_PATH); 65 if (nss3_dll_ == NULL) 66 return false; 67 68 // Firefox 2 uses NSS 3.11. Firefox 3 uses NSS 3.12. NSS 3.12 has two 69 // changes in its DLLs: 70 // 1. nss3.dll is not linked with softokn3.dll at build time, but rather 71 // loads softokn3.dll using LoadLibrary in NSS_Init. 72 // 2. softokn3.dll has a new dependency sqlite3.dll. 73 // NSS_Init's LoadLibrary call has trouble finding sqlite3.dll. To help 74 // it out, we preload softokn3.dll using LoadLibraryEx with the 75 // LOAD_WITH_ALTERED_SEARCH_PATH flag. This helps because LoadLibrary 76 // doesn't load a DLL again if it's already loaded. This workaround is 77 // harmless for NSS 3.11. 78 path = FilePath(dll_path).Append(kSoftokn3Library); 79 softokn3_dll_ = LoadLibraryEx(path.value().c_str(), NULL, 80 LOAD_WITH_ALTERED_SEARCH_PATH); 81 if (softokn3_dll_ == NULL) { 82 Free(); 83 return false; 84 } 85 } 86 HMODULE plds4_dll = GetModuleHandle(kPLDS4Library); 87 HMODULE nspr4_dll = GetModuleHandle(kNSPR4Library); 88 89 return InitNSS(db_path, plds4_dll, nspr4_dll); 90 } 91 92 NSSDecryptor::NSSDecryptor() 93 : NSS_Init(NULL), NSS_Shutdown(NULL), PK11_GetInternalKeySlot(NULL), 94 PK11_CheckUserPassword(NULL), PK11_FreeSlot(NULL), 95 PK11_Authenticate(NULL), PK11SDR_Decrypt(NULL), SECITEM_FreeItem(NULL), 96 PL_ArenaFinish(NULL), PR_Cleanup(NULL), 97 nss3_dll_(NULL), softokn3_dll_(NULL), 98 is_nss_initialized_(false) { 99 } 100 101 NSSDecryptor::~NSSDecryptor() { 102 Free(); 103 } 104 105 bool NSSDecryptor::InitNSS(const FilePath& db_path, 106 base::NativeLibrary plds4_dll, 107 base::NativeLibrary nspr4_dll) { 108 // NSPR DLLs are already loaded now. 109 if (plds4_dll == NULL || nspr4_dll == NULL) { 110 Free(); 111 return false; 112 } 113 114 // Gets the function address. 115 NSS_Init = (NSSInitFunc) 116 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Init"); 117 NSS_Shutdown = (NSSShutdownFunc) 118 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Shutdown"); 119 PK11_GetInternalKeySlot = (PK11GetInternalKeySlotFunc) 120 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, 121 "PK11_GetInternalKeySlot"); 122 PK11_FreeSlot = (PK11FreeSlotFunc) 123 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_FreeSlot"); 124 PK11_Authenticate = (PK11AuthenticateFunc) 125 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_Authenticate"); 126 PK11SDR_Decrypt = (PK11SDRDecryptFunc) 127 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11SDR_Decrypt"); 128 SECITEM_FreeItem = (SECITEMFreeItemFunc) 129 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "SECITEM_FreeItem"); 130 PL_ArenaFinish = (PLArenaFinishFunc) 131 base::GetFunctionPointerFromNativeLibrary(plds4_dll, "PL_ArenaFinish"); 132 PR_Cleanup = (PRCleanupFunc) 133 base::GetFunctionPointerFromNativeLibrary(nspr4_dll, "PR_Cleanup"); 134 135 if (NSS_Init == NULL || NSS_Shutdown == NULL || 136 PK11_GetInternalKeySlot == NULL || PK11_FreeSlot == NULL || 137 PK11_Authenticate == NULL || PK11SDR_Decrypt == NULL || 138 SECITEM_FreeItem == NULL || PL_ArenaFinish == NULL || 139 PR_Cleanup == NULL) { 140 Free(); 141 return false; 142 } 143 144 SECStatus result = NSS_Init(base::SysWideToNativeMB(db_path.value()).c_str()); 145 if (result != SECSuccess) { 146 Free(); 147 return false; 148 } 149 150 is_nss_initialized_ = true; 151 return true; 152 } 153 154 void NSSDecryptor::Free() { 155 if (is_nss_initialized_) { 156 NSS_Shutdown(); 157 PL_ArenaFinish(); 158 PR_Cleanup(); 159 is_nss_initialized_ = false; 160 } 161 if (softokn3_dll_ != NULL) 162 base::UnloadNativeLibrary(softokn3_dll_); 163 if (nss3_dll_ != NULL) 164 base::UnloadNativeLibrary(nss3_dll_); 165 NSS_Init = NULL; 166 NSS_Shutdown = NULL; 167 PK11_GetInternalKeySlot = NULL; 168 PK11_FreeSlot = NULL; 169 PK11_Authenticate = NULL; 170 PK11SDR_Decrypt = NULL; 171 SECITEM_FreeItem = NULL; 172 PL_ArenaFinish = NULL; 173 PR_Cleanup = NULL; 174 nss3_dll_ = NULL; 175 softokn3_dll_ = NULL; 176 } 177