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.
5 #include "chrome/utility/importer/nss_decryptor_win.h"
7 #include "base/files/file_path.h"
8 #include "base/strings/sys_string_conversions.h"
12 typedef BOOL (WINAPI
* SetDllDirectoryFunc
)(LPCTSTR lpPathName
);
14 // A helper class whose destructor calls SetDllDirectory(NULL) to undo the
15 // effects of a previous SetDllDirectory call.
16 class SetDllDirectoryCaller
{
18 explicit SetDllDirectoryCaller() : func_(NULL
) { }
20 ~SetDllDirectoryCaller() {
25 // Sets the SetDllDirectory function pointer to activates this object.
26 void set_func(SetDllDirectoryFunc func
) { func_
= func
; }
29 SetDllDirectoryFunc func_
;
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";
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
)
48 SetDllDirectoryFunc set_dll_directory
=
49 (SetDllDirectoryFunc
)GetProcAddress(kernel32_dll
, "SetDllDirectoryW");
50 SetDllDirectoryCaller caller
;
52 if (set_dll_directory
!= NULL
) {
53 if (!set_dll_directory(dll_path
.value().c_str()))
55 caller
.set_func(set_dll_directory
);
56 nss3_dll_
= LoadLibrary(kNSS3Library
);
57 if (nss3_dll_
== NULL
)
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
)
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
) {
87 HMODULE plds4_dll
= GetModuleHandle(kPLDS4Library
);
88 HMODULE nspr4_dll
= GetModuleHandle(kNSPR4Library
);
90 // On Firefox 22 and higher, NSPR is part of nss3.dll rather than separate
92 if (plds4_dll
== NULL
) {
93 plds4_dll
= nss3_dll_
;
94 nspr4_dll
= nss3_dll_
;
96 return InitNSS(db_path
, plds4_dll
, nspr4_dll
);
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) {
108 NSSDecryptor::~NSSDecryptor() {
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");
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
) {
145 SECStatus result
= NSS_Init(base::SysWideToNativeMB(db_path
.value()).c_str());
146 if (result
!= SECSuccess
) {
151 is_nss_initialized_
= true;
155 void NSSDecryptor::Free() {
156 if (is_nss_initialized_
) {
160 is_nss_initialized_
= false;
162 if (softokn3_dll_
!= NULL
)
163 base::UnloadNativeLibrary(softokn3_dll_
);
164 if (nss3_dll_
!= NULL
)
165 base::UnloadNativeLibrary(nss3_dll_
);
168 PK11_GetInternalKeySlot
= NULL
;
169 PK11_FreeSlot
= NULL
;
170 PK11_Authenticate
= NULL
;
171 PK11SDR_Decrypt
= NULL
;
172 SECITEM_FreeItem
= NULL
;
173 PL_ArenaFinish
= NULL
;
176 softokn3_dll_
= NULL
;