OLD | NEW |
1 // Copyright (c) 2008-2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008-2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/nss_util.h" | 5 #include "base/nss_util.h" |
6 #include "base/nss_util_internal.h" | 6 #include "base/nss_util_internal.h" |
7 | 7 |
8 #include <nss.h> | 8 #include <nss.h> |
9 #include <plarena.h> | 9 #include <plarena.h> |
10 #include <prerror.h> | 10 #include <prerror.h> |
11 #include <prinit.h> | 11 #include <prinit.h> |
12 #include <prtime.h> | 12 #include <prtime.h> |
13 #include <pk11pub.h> | 13 #include <pk11pub.h> |
14 #include <secmod.h> | 14 #include <secmod.h> |
15 | 15 |
| 16 #if defined(OS_LINUX) |
| 17 #include <linux/magic.h> |
| 18 #include <sys/vfs.h> |
| 19 #endif |
| 20 |
16 #include "base/file_util.h" | 21 #include "base/file_util.h" |
17 #include "base/logging.h" | 22 #include "base/logging.h" |
18 #include "base/singleton.h" | 23 #include "base/singleton.h" |
19 #include "base/string_util.h" | 24 #include "base/string_util.h" |
20 | 25 |
| 26 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not |
| 27 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't |
| 28 // use NSS for crypto or certificate verification, and we don't use the NSS |
| 29 // certificate and key databases. |
21 #if defined(USE_NSS) | 30 #if defined(USE_NSS) |
| 31 #include "base/env_var.h" |
22 #include "base/lock.h" | 32 #include "base/lock.h" |
23 #include "base/scoped_ptr.h" | 33 #include "base/scoped_ptr.h" |
24 #endif // defined(USE_NSS) | 34 #endif // defined(USE_NSS) |
25 | |
26 // On some platforms, we use NSS for SSL only -- we don't use NSS for crypto | |
27 // or certificate verification, and we don't use the NSS certificate and key | |
28 // databases. | |
29 #if defined(OS_MACOSX) || defined(OS_WIN) | |
30 #define USE_NSS_FOR_SSL_ONLY 1 | |
31 #endif | |
32 | 35 |
33 namespace { | 36 namespace { |
34 | 37 |
35 #if !defined(USE_NSS_FOR_SSL_ONLY) | 38 #if defined(USE_NSS) |
36 std::string GetDefaultConfigDirectory() { | 39 FilePath GetDefaultConfigDirectory() { |
37 FilePath home = file_util::GetHomeDir(); | 40 FilePath dir = file_util::GetHomeDir(); |
38 if (home.empty()) { | 41 if (dir.empty()) { |
39 LOG(ERROR) << "$HOME is not set."; | 42 LOG(ERROR) << "Failed to get home directory."; |
40 return std::string(); | 43 return dir; |
41 } | 44 } |
42 FilePath dir(home); | |
43 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); | 45 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); |
44 if (!file_util::CreateDirectory(dir)) { | 46 if (!file_util::CreateDirectory(dir)) { |
45 LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; | 47 LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; |
46 return std::string(); | 48 dir.clear(); |
47 } | 49 } |
48 return dir.value(); | 50 return dir; |
49 } | 51 } |
50 | 52 |
51 // On non-chromeos platforms, return the default config directory. | 53 // On non-chromeos platforms, return the default config directory. |
52 // On chromeos, return a read-only directory with fake root CA certs for testing | 54 // On chromeos, return a read-only directory with fake root CA certs for testing |
53 // (which will not exist on non-testing images). These root CA certs are used | 55 // (which will not exist on non-testing images). These root CA certs are used |
54 // by the local Google Accounts server mock we use when testing our login code. | 56 // by the local Google Accounts server mock we use when testing our login code. |
55 // If this directory is not present, NSS_Init() will fail. It is up to the | 57 // If this directory is not present, NSS_Init() will fail. It is up to the |
56 // caller to failover to NSS_NoDB_Init() at that point. | 58 // caller to failover to NSS_NoDB_Init() at that point. |
57 std::string GetInitialConfigDirectory() { | 59 FilePath GetInitialConfigDirectory() { |
58 #if defined(OS_CHROMEOS) | 60 #if defined(OS_CHROMEOS) |
59 static const char kReadOnlyCertDB[] = "/etc/fake_root_ca/nssdb"; | 61 static const FilePath::CharType kReadOnlyCertDB[] = |
60 return std::string(kReadOnlyCertDB); | 62 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); |
| 63 return FilePath(kReadOnlyCertDB); |
61 #else | 64 #else |
62 return GetDefaultConfigDirectory(); | 65 return GetDefaultConfigDirectory(); |
63 #endif // defined(OS_CHROMEOS) | 66 #endif // defined(OS_CHROMEOS) |
64 } | 67 } |
65 | 68 |
| 69 // NSS creates a local cache of the sqlite database if it detects that the |
| 70 // filesystem the database is on is much slower than the local disk. The |
| 71 // detection doesn't work with the latest versions of sqlite, such as 3.6.22 |
| 72 // (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set |
| 73 // the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's |
| 74 // detection when database_dir is on NFS. See http://crbug.com/48585. |
| 75 // |
| 76 // TODO(wtc): port this function to other USE_NSS platforms. It is defined |
| 77 // only for OS_LINUX simply because the statfs structure is OS-specific. |
| 78 void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) { |
| 79 #if defined(OS_LINUX) |
| 80 struct statfs buf; |
| 81 if (statfs(database_dir.value().c_str(), &buf) == 0) { |
| 82 if (buf.f_type == NFS_SUPER_MAGIC) { |
| 83 scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); |
| 84 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; |
| 85 if (!env->HasEnv(use_cache_env_var)) |
| 86 env->SetEnv(use_cache_env_var, "yes"); |
| 87 } |
| 88 } |
| 89 #endif // defined(OS_LINUX) |
| 90 } |
| 91 |
66 // Load nss's built-in root certs. | 92 // Load nss's built-in root certs. |
67 SECMODModule *InitDefaultRootCerts() { | 93 SECMODModule *InitDefaultRootCerts() { |
68 const char* kModulePath = "libnssckbi.so"; | 94 const char* kModulePath = "libnssckbi.so"; |
69 char modparams[1024]; | 95 char modparams[1024]; |
70 snprintf(modparams, sizeof(modparams), | 96 snprintf(modparams, sizeof(modparams), |
71 "name=\"Root Certs\" library=\"%s\"", kModulePath); | 97 "name=\"Root Certs\" library=\"%s\"", kModulePath); |
72 SECMODModule *root = SECMOD_LoadUserModule(modparams, NULL, PR_FALSE); | 98 SECMODModule *root = SECMOD_LoadUserModule(modparams, NULL, PR_FALSE); |
73 if (root) | 99 if (root) |
74 return root; | 100 return root; |
75 | 101 |
76 // Aw, snap. Can't find/load root cert shared library. | 102 // Aw, snap. Can't find/load root cert shared library. |
77 // This will make it hard to talk to anybody via https. | 103 // This will make it hard to talk to anybody via https. |
78 NOTREACHED(); | 104 NOTREACHED(); |
79 return NULL; | 105 return NULL; |
80 } | 106 } |
81 #endif // !defined(USE_NSS_FOR_SSL_ONLY) | 107 #endif // defined(USE_NSS) |
82 | 108 |
83 // A singleton to initialize/deinitialize NSPR. | 109 // A singleton to initialize/deinitialize NSPR. |
84 // Separate from the NSS singleton because we initialize NSPR on the UI thread. | 110 // Separate from the NSS singleton because we initialize NSPR on the UI thread. |
85 class NSPRInitSingleton { | 111 class NSPRInitSingleton { |
86 public: | 112 public: |
87 NSPRInitSingleton() { | 113 NSPRInitSingleton() { |
88 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); | 114 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); |
89 } | 115 } |
90 | 116 |
91 ~NSPRInitSingleton() { | 117 ~NSPRInitSingleton() { |
(...skipping 28 matching lines...) Expand all Loading... |
120 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " | 146 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " |
121 "We depend on NSS >= 3.12.3, and this error is not fatal " | 147 "We depend on NSS >= 3.12.3, and this error is not fatal " |
122 "only because many people have busted NSS setups (for " | 148 "only because many people have busted NSS setups (for " |
123 "example, using the wrong version of NSPR). " | 149 "example, using the wrong version of NSPR). " |
124 "Please upgrade to the latest NSS and NSPR, and if you " | 150 "Please upgrade to the latest NSS and NSPR, and if you " |
125 "still get this error, contact your distribution " | 151 "still get this error, contact your distribution " |
126 "maintainer."; | 152 "maintainer."; |
127 } | 153 } |
128 | 154 |
129 SECStatus status = SECFailure; | 155 SECStatus status = SECFailure; |
130 #if defined(USE_NSS_FOR_SSL_ONLY) | 156 #if !defined(USE_NSS) |
131 // Use the system certificate store, so initialize NSS without database. | 157 // Use the system certificate store, so initialize NSS without database. |
132 status = NSS_NoDB_Init(NULL); | 158 status = NSS_NoDB_Init(NULL); |
133 if (status != SECSuccess) { | 159 if (status != SECSuccess) { |
134 LOG(ERROR) << "Error initializing NSS without a persistent " | 160 LOG(ERROR) << "Error initializing NSS without a persistent " |
135 "database: NSS error code " << PR_GetError(); | 161 "database: NSS error code " << PR_GetError(); |
136 } | 162 } |
137 #else | 163 #else |
138 std::string database_dir = GetInitialConfigDirectory(); | 164 FilePath database_dir = GetInitialConfigDirectory(); |
139 if (!database_dir.empty()) { | 165 if (!database_dir.empty()) { |
| 166 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
| 167 |
140 // Initialize with a persistent database (likely, ~/.pki/nssdb). | 168 // Initialize with a persistent database (likely, ~/.pki/nssdb). |
141 // Use "sql:" which can be shared by multiple processes safely. | 169 // Use "sql:" which can be shared by multiple processes safely. |
142 std::string nss_config_dir = | 170 std::string nss_config_dir = |
143 StringPrintf("sql:%s", database_dir.c_str()); | 171 StringPrintf("sql:%s", database_dir.value().c_str()); |
144 #if defined(OS_CHROMEOS) | 172 #if defined(OS_CHROMEOS) |
145 status = NSS_Init(nss_config_dir.c_str()); | 173 status = NSS_Init(nss_config_dir.c_str()); |
146 #else | 174 #else |
147 status = NSS_InitReadWrite(nss_config_dir.c_str()); | 175 status = NSS_InitReadWrite(nss_config_dir.c_str()); |
148 #endif | 176 #endif |
149 if (status != SECSuccess) { | 177 if (status != SECSuccess) { |
150 LOG(ERROR) << "Error initializing NSS with a persistent " | 178 LOG(ERROR) << "Error initializing NSS with a persistent " |
151 "database (" << nss_config_dir | 179 "database (" << nss_config_dir |
152 << "): NSS error code " << PR_GetError(); | 180 << "): NSS error code " << PR_GetError(); |
153 } | 181 } |
(...skipping 20 matching lines...) Expand all Loading... |
174 PK11_InitPin(slot, NULL, NULL); | 202 PK11_InitPin(slot, NULL, NULL); |
175 PK11_FreeSlot(slot); | 203 PK11_FreeSlot(slot); |
176 } | 204 } |
177 | 205 |
178 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 206 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
179 // is fixed, we will no longer need the lock. We should detect this and not | 207 // is fixed, we will no longer need the lock. We should detect this and not |
180 // initialize a Lock here. | 208 // initialize a Lock here. |
181 write_lock_.reset(new Lock()); | 209 write_lock_.reset(new Lock()); |
182 | 210 |
183 root_ = InitDefaultRootCerts(); | 211 root_ = InitDefaultRootCerts(); |
184 #endif // defined(USE_NSS_FOR_SSL_ONLY) | 212 #endif // !defined(USE_NSS) |
185 } | 213 } |
186 | 214 |
187 ~NSSInitSingleton() { | 215 ~NSSInitSingleton() { |
188 if (real_db_slot_) { | 216 if (real_db_slot_) { |
189 SECMOD_CloseUserDB(real_db_slot_); | 217 SECMOD_CloseUserDB(real_db_slot_); |
190 PK11_FreeSlot(real_db_slot_); | 218 PK11_FreeSlot(real_db_slot_); |
191 real_db_slot_ = NULL; | 219 real_db_slot_ = NULL; |
192 } | 220 } |
193 if (root_) { | 221 if (root_) { |
194 SECMOD_UnloadUserModule(root_); | 222 SECMOD_UnloadUserModule(root_); |
(...skipping 10 matching lines...) Expand all Loading... |
205 } | 233 } |
206 } | 234 } |
207 | 235 |
208 #if defined(OS_CHROMEOS) | 236 #if defined(OS_CHROMEOS) |
209 void OpenPersistentNSSDB() { | 237 void OpenPersistentNSSDB() { |
210 if (!chromeos_user_logged_in_) { | 238 if (!chromeos_user_logged_in_) { |
211 chromeos_user_logged_in_ = true; | 239 chromeos_user_logged_in_ = true; |
212 | 240 |
213 const std::string modspec = | 241 const std::string modspec = |
214 StringPrintf("configDir='%s' tokenDescription='Real NSS database'", | 242 StringPrintf("configDir='%s' tokenDescription='Real NSS database'", |
215 GetDefaultConfigDirectory().c_str()); | 243 GetDefaultConfigDirectory().value().c_str()); |
216 real_db_slot_ = SECMOD_OpenUserDB(modspec.c_str()); | 244 real_db_slot_ = SECMOD_OpenUserDB(modspec.c_str()); |
217 if (real_db_slot_ == NULL) { | 245 if (real_db_slot_ == NULL) { |
218 LOG(ERROR) << "Error opening persistent database (" << modspec | 246 LOG(ERROR) << "Error opening persistent database (" << modspec |
219 << "): NSS error code " << PR_GetError(); | 247 << "): NSS error code " << PR_GetError(); |
220 } else { | 248 } else { |
221 if (PK11_NeedUserInit(real_db_slot_)) | 249 if (PK11_NeedUserInit(real_db_slot_)) |
222 PK11_InitPin(real_db_slot_, NULL, NULL); | 250 PK11_InitPin(real_db_slot_, NULL, NULL); |
223 } | 251 } |
224 } | 252 } |
225 } | 253 } |
226 #endif // defined(OS_CHROMEOS) | 254 #endif // defined(OS_CHROMEOS) |
227 | 255 |
228 PK11SlotInfo* GetDefaultKeySlot() { | 256 PK11SlotInfo* GetDefaultKeySlot() { |
229 if (real_db_slot_) | 257 if (real_db_slot_) |
230 return PK11_ReferenceSlot(real_db_slot_); | 258 return PK11_ReferenceSlot(real_db_slot_); |
231 return PK11_GetInternalKeySlot(); | 259 return PK11_GetInternalKeySlot(); |
232 } | 260 } |
233 | 261 |
234 #if defined(USE_NSS) | 262 #if defined(USE_NSS) |
235 Lock* write_lock() { | 263 Lock* write_lock() { |
236 return write_lock_.get(); | 264 return write_lock_.get(); |
237 } | 265 } |
238 #endif // defined(USE_NSS) | 266 #endif // defined(USE_NSS) |
239 | 267 |
240 private: | 268 private: |
241 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. | 269 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. |
242 SECMODModule *root_; | 270 SECMODModule *root_; |
243 bool chromeos_user_logged_in_; | 271 bool chromeos_user_logged_in_; |
244 #if defined(USE_NSS) | 272 #if defined(USE_NSS) |
245 scoped_ptr<Lock> write_lock_; | 273 scoped_ptr<Lock> write_lock_; |
246 #endif // defined(USE_NSS) | 274 #endif // defined(USE_NSS) |
247 }; | 275 }; |
248 | 276 |
249 } // namespace | 277 } // namespace |
250 | 278 |
251 namespace base { | 279 namespace base { |
252 | 280 |
253 void EnsureNSPRInit() { | 281 void EnsureNSPRInit() { |
254 Singleton<NSPRInitSingleton>::get(); | 282 Singleton<NSPRInitSingleton>::get(); |
255 } | 283 } |
256 | 284 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 exploded.millisecond = prxtime.tm_usec / 1000; | 328 exploded.millisecond = prxtime.tm_usec / 1000; |
301 | 329 |
302 return Time::FromUTCExploded(exploded); | 330 return Time::FromUTCExploded(exploded); |
303 } | 331 } |
304 | 332 |
305 PK11SlotInfo* GetDefaultNSSKeySlot() { | 333 PK11SlotInfo* GetDefaultNSSKeySlot() { |
306 return Singleton<NSSInitSingleton>::get()->GetDefaultKeySlot(); | 334 return Singleton<NSSInitSingleton>::get()->GetDefaultKeySlot(); |
307 } | 335 } |
308 | 336 |
309 } // namespace base | 337 } // namespace base |
OLD | NEW |