Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsNSSComponent.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 *
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
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsNSSComponent.h"
8
9
#include "EnterpriseRoots.h"
10
#include "ExtendedValidation.h"
11
#include "NSSCertDBTrustDomain.h"
12
#include "PKCS11ModuleDB.h"
13
#include "ScopedNSSTypes.h"
14
#include "SharedSSLState.h"
15
#include "cert.h"
16
#include "certdb.h"
17
#include "mozilla/ArrayUtils.h"
18
#include "mozilla/Assertions.h"
19
#include "mozilla/Casting.h"
20
#include "mozilla/Preferences.h"
21
#include "mozilla/PodOperations.h"
22
#include "mozilla/PublicSSL.h"
23
#include "mozilla/Services.h"
24
#include "mozilla/StaticPtr.h"
25
#include "mozilla/SyncRunnable.h"
26
#include "mozilla/Telemetry.h"
27
#include "mozilla/TimeStamp.h"
28
#include "mozilla/Unused.h"
29
#include "mozilla/Vector.h"
30
#include "nsAppDirectoryServiceDefs.h"
31
#include "nsCRT.h"
32
#include "nsClientAuthRemember.h"
33
#include "nsComponentManagerUtils.h"
34
#include "nsDirectoryServiceDefs.h"
35
#include "nsICertOverrideService.h"
36
#include "nsIFile.h"
37
#include "nsILocalFileWin.h"
38
#include "nsIObserverService.h"
39
#include "nsIPrompt.h"
40
#include "nsIProperties.h"
41
#include "nsISiteSecurityService.h"
42
#include "nsITokenPasswordDialogs.h"
43
#include "nsIWindowWatcher.h"
44
#include "nsIXULRuntime.h"
45
#include "nsLiteralString.h"
46
#include "nsNSSCertificateDB.h"
47
#include "nsNSSHelper.h"
48
#include "nsPK11TokenDB.h"
49
#include "nsPrintfCString.h"
50
#include "nsServiceManagerUtils.h"
51
#include "nsThreadUtils.h"
52
#include "nsXULAppAPI.h"
53
#include "nss.h"
54
#include "p12plcy.h"
55
#include "pkix/pkixnss.h"
56
#include "secerr.h"
57
#include "secmod.h"
58
#include "ssl.h"
59
#include "sslerr.h"
60
#include "sslproto.h"
61
#include "prmem.h"
62
63
#if defined(XP_LINUX) && !defined(ANDROID)
64
#include <linux/magic.h>
65
#include <sys/vfs.h>
66
#endif
67
68
#ifdef XP_WIN
69
#include "mozilla/WindowsVersion.h"
70
#include "nsILocalFileWin.h"
71
72
#include "windows.h" // this needs to be before the following includes
73
#include "lmcons.h"
74
#include "sddl.h"
75
#include "wincrypt.h"
76
#include "nsIWindowsRegKey.h"
77
#endif
78
79
using namespace mozilla;
80
using namespace mozilla::psm;
81
82
LazyLogModule gPIPNSSLog("pipnss");
83
84
int nsNSSComponent::mInstanceCount = 0;
85
86
// This function can be called from chrome or content processes
87
// to ensure that NSS is initialized.
88
bool EnsureNSSInitializedChromeOrContent()
89
0
{
90
0
  static Atomic<bool> initialized(false);
91
0
92
0
  if (initialized) {
93
0
    return true;
94
0
  }
95
0
96
0
  // If this is not the main thread (i.e. probably a worker) then forward this
97
0
  // call to the main thread.
98
0
  if (!NS_IsMainThread()) {
99
0
    nsCOMPtr<nsIThread> mainThread;
100
0
    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
101
0
    if (NS_FAILED(rv)) {
102
0
      return false;
103
0
    }
104
0
105
0
    // Forward to the main thread synchronously.
106
0
    mozilla::SyncRunnable::DispatchToThread(
107
0
      mainThread,
108
0
      new SyncRunnable(
109
0
        NS_NewRunnableFunction("EnsureNSSInitializedChromeOrContent", []() {
110
0
          EnsureNSSInitializedChromeOrContent();
111
0
        })));
112
0
113
0
    return initialized;
114
0
  }
115
0
116
0
  if (XRE_IsParentProcess()) {
117
0
    nsCOMPtr<nsISupports> nss = do_GetService(PSM_COMPONENT_CONTRACTID);
118
0
    if (!nss) {
119
0
      return false;
120
0
    }
121
0
    initialized = true;
122
0
    return true;
123
0
  }
124
0
125
0
  if (NSS_IsInitialized()) {
126
0
    initialized = true;
127
0
    return true;
128
0
  }
129
0
130
0
  if (NSS_NoDB_Init(nullptr) != SECSuccess) {
131
0
    return false;
132
0
  }
133
0
134
0
  if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) {
135
0
    return false;
136
0
  }
137
0
138
0
  mozilla::psm::DisableMD5();
139
0
  mozilla::pkix::RegisterErrorTable();
140
0
  initialized = true;
141
0
  return true;
142
0
}
143
144
static const uint32_t OCSP_TIMEOUT_MILLISECONDS_SOFT_DEFAULT = 2000;
145
static const uint32_t OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX = 5000;
146
static const uint32_t OCSP_TIMEOUT_MILLISECONDS_HARD_DEFAULT = 10000;
147
static const uint32_t OCSP_TIMEOUT_MILLISECONDS_HARD_MAX = 20000;
148
149
static void
150
GetRevocationBehaviorFromPrefs(/*out*/ CertVerifier::OcspDownloadConfig* odc,
151
                               /*out*/ CertVerifier::OcspStrictConfig* osc,
152
                               /*out*/ uint32_t* certShortLifetimeInDays,
153
                               /*out*/ TimeDuration& softTimeout,
154
                               /*out*/ TimeDuration& hardTimeout,
155
                               const MutexAutoLock& /*proofOfLock*/)
156
0
{
157
0
  MOZ_ASSERT(NS_IsMainThread());
158
0
  MOZ_ASSERT(odc);
159
0
  MOZ_ASSERT(osc);
160
0
  MOZ_ASSERT(certShortLifetimeInDays);
161
0
162
0
  // 0 = disabled
163
0
  // 1 = enabled for everything (default)
164
0
  // 2 = enabled for EV certificates only
165
0
  int32_t ocspLevel = Preferences::GetInt("security.OCSP.enabled", 1);
166
0
  switch (ocspLevel) {
167
0
    case 0: *odc = CertVerifier::ocspOff; break;
168
0
    case 2: *odc = CertVerifier::ocspEVOnly; break;
169
0
    default: *odc = CertVerifier::ocspOn; break;
170
0
  }
171
0
172
0
  *osc = Preferences::GetBool("security.OCSP.require", false)
173
0
       ? CertVerifier::ocspStrict
174
0
       : CertVerifier::ocspRelaxed;
175
0
176
0
  // If we pass in just 0 as the second argument to Preferences::GetUint, there
177
0
  // are two function signatures that match (given that 0 can be intepreted as
178
0
  // a null pointer). Thus the compiler will complain without the cast.
179
0
  *certShortLifetimeInDays =
180
0
    Preferences::GetUint("security.pki.cert_short_lifetime_in_days",
181
0
                         static_cast<uint32_t>(0));
182
0
183
0
  uint32_t softTimeoutMillis =
184
0
    Preferences::GetUint("security.OCSP.timeoutMilliseconds.soft",
185
0
                         OCSP_TIMEOUT_MILLISECONDS_SOFT_DEFAULT);
186
0
  softTimeoutMillis = std::min(softTimeoutMillis,
187
0
                               OCSP_TIMEOUT_MILLISECONDS_SOFT_MAX);
188
0
  softTimeout = TimeDuration::FromMilliseconds(softTimeoutMillis);
189
0
190
0
  uint32_t hardTimeoutMillis =
191
0
    Preferences::GetUint("security.OCSP.timeoutMilliseconds.hard",
192
0
                         OCSP_TIMEOUT_MILLISECONDS_HARD_DEFAULT);
193
0
  hardTimeoutMillis = std::min(hardTimeoutMillis,
194
0
                               OCSP_TIMEOUT_MILLISECONDS_HARD_MAX);
195
0
  hardTimeout = TimeDuration::FromMilliseconds(hardTimeoutMillis);
196
0
197
0
  SSL_ClearSessionCache();
198
0
}
199
200
nsNSSComponent::nsNSSComponent()
201
  : mLoadableRootsLoadedMonitor("nsNSSComponent.mLoadableRootsLoadedMonitor")
202
  , mLoadableRootsLoaded(false)
203
  , mLoadableRootsLoadedResult(NS_ERROR_FAILURE)
204
  , mMutex("nsNSSComponent.mMutex")
205
  , mMitmDetecionEnabled(false)
206
  , mLoadLoadableRootsTaskDispatched(false)
207
0
{
208
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ctor\n"));
209
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
210
0
211
0
  MOZ_ASSERT(mInstanceCount == 0,
212
0
             "nsNSSComponent is a singleton, but instantiated multiple times!");
213
0
  ++mInstanceCount;
214
0
}
215
216
nsNSSComponent::~nsNSSComponent()
217
0
{
218
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor\n"));
219
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
220
0
221
0
  // All cleanup code requiring services needs to happen in xpcom_shutdown
222
0
223
0
  ShutdownNSS();
224
0
  SharedSSLState::GlobalCleanup();
225
0
  RememberCertErrorsTable::Cleanup();
226
0
  --mInstanceCount;
227
0
228
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor finished\n"));
229
0
}
230
231
#ifdef XP_WIN
232
static bool
233
GetUserSid(nsAString& sidString)
234
{
235
  // UNLEN is the maximum user name length (see Lmcons.h). +1 for the null
236
  // terminator.
237
  WCHAR lpAccountName[UNLEN + 1];
238
  DWORD lcAccountName = sizeof(lpAccountName) / sizeof(lpAccountName[0]);
239
  BOOL success = GetUserName(lpAccountName, &lcAccountName);
240
  if (!success) {
241
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("GetUserName failed"));
242
    return false;
243
  }
244
  char sid_buffer[SECURITY_MAX_SID_SIZE];
245
  SID* sid = BitwiseCast<SID*, char*>(sid_buffer);
246
  DWORD cbSid = ArrayLength(sid_buffer);
247
  SID_NAME_USE eUse;
248
  // There doesn't appear to be a defined maximum length for the domain name
249
  // here. To deal with this, we start with a reasonable buffer length and
250
  // see if that works. If it fails and the error indicates insufficient length,
251
  // we use the indicated required length and try again.
252
  DWORD cchReferencedDomainName = 128;
253
  auto ReferencedDomainName(MakeUnique<WCHAR[]>(cchReferencedDomainName));
254
  success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
255
                              ReferencedDomainName.get(),
256
                              &cchReferencedDomainName, &eUse);
257
  if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
258
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("LookupAccountName failed"));
259
    return false;
260
  }
261
  if (!success) {
262
    ReferencedDomainName = MakeUnique<WCHAR[]>(cchReferencedDomainName);
263
    success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
264
                                ReferencedDomainName.get(),
265
                                &cchReferencedDomainName, &eUse);
266
  }
267
  if (!success) {
268
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("LookupAccountName failed"));
269
    return false;
270
  }
271
  LPTSTR StringSid;
272
  success = ConvertSidToStringSid(sid, &StringSid);
273
  if (!success) {
274
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("ConvertSidToStringSid failed"));
275
    return false;
276
  }
277
  sidString.Assign(StringSid);
278
  LocalFree(StringSid);
279
  return true;
280
}
281
282
// This is a specialized helper function to read the value of a registry key
283
// that might not be present. If it is present, returns (via the output
284
// parameter) its value. Otherwise, returns the given default value.
285
// This function handles one level of nesting. That is, if the desired value
286
// is actually in a direct child of the given registry key (where the child
287
// and/or the value being sought may not actually be present), this function
288
// will handle that. In the normal case, though, optionalChildName will be
289
// null.
290
static nsresult
291
ReadRegKeyValueWithDefault(nsCOMPtr<nsIWindowsRegKey> regKey,
292
                           uint32_t flags,
293
                           wchar_t* optionalChildName,
294
                           wchar_t* valueName,
295
                           uint32_t defaultValue,
296
                           uint32_t& valueOut)
297
{
298
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("ReadRegKeyValueWithDefault"));
299
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
300
          ("attempting to read '%S%s%S' with default '%u'",
301
           optionalChildName ? optionalChildName : L"",
302
           optionalChildName ? "\\" : "", valueName, defaultValue));
303
  if (optionalChildName) {
304
    nsDependentString childNameString(optionalChildName);
305
    bool hasChild;
306
    nsresult rv = regKey->HasChild(childNameString, &hasChild);
307
    if (NS_FAILED(rv)) {
308
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
309
              ("failed to determine if child key is present"));
310
      return rv;
311
    }
312
    if (!hasChild) {
313
      valueOut = defaultValue;
314
      return NS_OK;
315
    }
316
    nsCOMPtr<nsIWindowsRegKey> childRegKey;
317
    rv = regKey->OpenChild(childNameString, flags,
318
                           getter_AddRefs(childRegKey));
319
    if (NS_FAILED(rv)) {
320
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open child key"));
321
      return rv;
322
    }
323
    return ReadRegKeyValueWithDefault(childRegKey, flags, nullptr, valueName,
324
                                      defaultValue, valueOut);
325
  }
326
  nsDependentString valueNameString(valueName);
327
  bool hasValue;
328
  nsresult rv = regKey->HasValue(valueNameString, &hasValue);
329
  if (NS_FAILED(rv)) {
330
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
331
            ("failed to determine if value is present"));
332
    return rv;
333
  }
334
  if (!hasValue) {
335
    valueOut = defaultValue;
336
    return NS_OK;
337
  }
338
  rv = regKey->ReadIntValue(valueNameString, &valueOut);
339
  if (NS_FAILED(rv)) {
340
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to read value"));
341
    return rv;
342
  }
343
  return NS_OK;
344
}
345
346
static nsresult
347
AccountHasFamilySafetyEnabled(bool& enabled)
348
{
349
  enabled = false;
350
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("AccountHasFamilySafetyEnabled?"));
351
  nsCOMPtr<nsIWindowsRegKey> parentalControlsKey(
352
    do_CreateInstance("@mozilla.org/windows-registry-key;1"));
353
  if (!parentalControlsKey) {
354
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't create nsIWindowsRegKey"));
355
    return NS_ERROR_FAILURE;
356
  }
357
  uint32_t flags = nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::WOW64_64;
358
  NS_NAMED_LITERAL_STRING(familySafetyPath,
359
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Parental Controls");
360
  nsresult rv = parentalControlsKey->Open(
361
    nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, familySafetyPath, flags);
362
  if (NS_FAILED(rv)) {
363
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open parentalControlsKey"));
364
    return rv;
365
  }
366
  NS_NAMED_LITERAL_STRING(usersString, "Users");
367
  bool hasUsers;
368
  rv = parentalControlsKey->HasChild(usersString, &hasUsers);
369
  if (NS_FAILED(rv)) {
370
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HasChild(Users) failed"));
371
    return rv;
372
  }
373
  if (!hasUsers) {
374
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
375
            ("Users subkey not present - Parental Controls not enabled"));
376
    return NS_OK;
377
  }
378
  nsCOMPtr<nsIWindowsRegKey> usersKey;
379
  rv = parentalControlsKey->OpenChild(usersString, flags,
380
                                      getter_AddRefs(usersKey));
381
  if (NS_FAILED(rv)) {
382
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to open Users subkey"));
383
    return rv;
384
  }
385
  nsAutoString sid;
386
  if (!GetUserSid(sid)) {
387
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get sid"));
388
    return NS_ERROR_FAILURE;
389
  }
390
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("our sid is '%S'", sid.get()));
391
  bool hasSid;
392
  rv = usersKey->HasChild(sid, &hasSid);
393
  if (NS_FAILED(rv)) {
394
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("HasChild(sid) failed"));
395
    return rv;
396
  }
397
  if (!hasSid) {
398
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
399
            ("sid not present in Family Safety Users"));
400
    return NS_OK;
401
  }
402
  nsCOMPtr<nsIWindowsRegKey> sidKey;
403
  rv = usersKey->OpenChild(sid, flags, getter_AddRefs(sidKey));
404
  if (NS_FAILED(rv)) {
405
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't open sid key"));
406
    return rv;
407
  }
408
  // There are three keys we're interested in: "Parental Controls On",
409
  // "Logging Required", and "Web\\Filter On". These keys will have value 0
410
  // or 1, indicating a particular feature is disabled or enabled,
411
  // respectively. So, if "Parental Controls On" is not 1, Family Safety is
412
  // disabled and we don't care about anything else. If both "Logging
413
  // Required" and "Web\\Filter On" are 0, the proxy will not be running,
414
  // so for our purposes we can consider Family Safety disabled in that
415
  // case.
416
  // By default, "Logging Required" is 1 and "Web\\Filter On" is 0,
417
  // reflecting the initial settings when Family Safety is enabled for an
418
  // account for the first time, However, these sub-keys are not created
419
  // unless they are switched away from the default value.
420
  uint32_t parentalControlsOn;
421
  rv = sidKey->ReadIntValue(NS_LITERAL_STRING("Parental Controls On"),
422
                            &parentalControlsOn);
423
  if (NS_FAILED(rv)) {
424
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
425
            ("couldn't read Parental Controls On"));
426
    return rv;
427
  }
428
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
429
          ("Parental Controls On: %u", parentalControlsOn));
430
  if (parentalControlsOn != 1) {
431
    return NS_OK;
432
  }
433
  uint32_t loggingRequired;
434
  rv = ReadRegKeyValueWithDefault(sidKey, flags, nullptr, L"Logging Required",
435
                                  1, loggingRequired);
436
  if (NS_FAILED(rv)) {
437
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
438
            ("failed to read value of Logging Required"));
439
    return rv;
440
  }
441
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
442
          ("Logging Required: %u", loggingRequired));
443
  uint32_t webFilterOn;
444
  rv = ReadRegKeyValueWithDefault(sidKey, flags, L"Web", L"Filter On", 0,
445
                                  webFilterOn);
446
  if (NS_FAILED(rv)) {
447
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
448
            ("failed to read value of Web\\Filter On"));
449
    return rv;
450
  }
451
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Web\\Filter On: %u", webFilterOn));
452
  enabled = loggingRequired == 1 || webFilterOn == 1;
453
  return NS_OK;
454
}
455
456
nsresult
457
nsNSSComponent::MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
458
                                            bool& wasFamilySafetyRoot)
459
{
460
  MutexAutoLock lock(mMutex);
461
  MOZ_ASSERT(NS_IsMainThread());
462
  if (!NS_IsMainThread()) {
463
    return NS_ERROR_NOT_SAME_THREAD;
464
  }
465
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("MaybeImportFamilySafetyRoot"));
466
  wasFamilySafetyRoot = false;
467
468
  UniqueCERTCertificate nssCertificate(
469
    PCCERT_CONTEXTToCERTCertificate(certificate));
470
  if (!nssCertificate) {
471
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't decode certificate"));
472
    return NS_ERROR_FAILURE;
473
  }
474
  // Looking for a certificate with the common name 'Microsoft Family Safety'
475
  UniquePORTString subjectName(CERT_GetCommonName(&nssCertificate->subject));
476
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
477
          ("subject name is '%s'", subjectName.get()));
478
  if (kMicrosoftFamilySafetyCN.Equals(subjectName.get())) {
479
    wasFamilySafetyRoot = true;
480
    MOZ_ASSERT(!mFamilySafetyRoot);
481
    mFamilySafetyRoot = std::move(nssCertificate);
482
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("added Family Safety root"));
483
  }
484
  return NS_OK;
485
}
486
487
nsresult
488
nsNSSComponent::LoadFamilySafetyRoot()
489
{
490
  ScopedCertStore certstore(
491
    CertOpenSystemStore(0, kWindowsDefaultRootStoreName));
492
  if (!certstore.get()) {
493
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
494
            ("couldn't get certstore '%S'", kWindowsDefaultRootStoreName));
495
    return NS_ERROR_FAILURE;
496
  }
497
  // Any resources held by the certificate are released by the next call to
498
  // CertFindCertificateInStore.
499
  PCCERT_CONTEXT certificate = nullptr;
500
  while ((certificate = CertFindCertificateInStore(certstore.get(),
501
                                                   X509_ASN_ENCODING, 0,
502
                                                   CERT_FIND_ANY, nullptr,
503
                                                   certificate))) {
504
    bool wasFamilySafetyRoot = false;
505
    nsresult rv = MaybeImportFamilySafetyRoot(certificate,
506
                                              wasFamilySafetyRoot);
507
    if (NS_SUCCEEDED(rv) && wasFamilySafetyRoot) {
508
      return NS_OK; // We're done (we're only expecting one root).
509
    }
510
  }
511
  return NS_ERROR_FAILURE;
512
}
513
#endif // XP_WIN
514
515
void
516
nsNSSComponent::UnloadFamilySafetyRoot()
517
0
{
518
0
  MOZ_ASSERT(NS_IsMainThread());
519
0
  if (!NS_IsMainThread()) {
520
0
    return;
521
0
  }
522
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadFamilySafetyRoot"));
523
0
524
0
  // We can't call ChangeCertTrustWithPossibleAuthentication while holding
525
0
  // mMutex (because it could potentially call back in to nsNSSComponent and
526
0
  // attempt to acquire mMutex), so we move mFamilySafetyRoot out of
527
0
  // nsNSSComponent into a local handle. This has the side-effect of clearing
528
0
  // mFamilySafetyRoot, which is what we want anyway.
529
0
  UniqueCERTCertificate familySafetyRoot;
530
0
  {
531
0
    MutexAutoLock lock(mMutex);
532
0
    if (!mFamilySafetyRoot) {
533
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
534
0
              ("Family Safety Root wasn't present"));
535
0
      return;
536
0
    }
537
0
    familySafetyRoot = std::move(mFamilySafetyRoot);
538
0
    MOZ_ASSERT(!mFamilySafetyRoot);
539
0
  }
540
0
  MOZ_ASSERT(familySafetyRoot);
541
0
  // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
542
0
  // doesn't work for temporary certificates because CERT_ChangeCertTrust first
543
0
  // looks up the current trust settings in the permanent cert database, finds
544
0
  // that such trust doesn't exist, considers the current trust to be
545
0
  // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
546
0
  // they're the same. To work around this, we set a non-zero flag to ensure
547
0
  // that the trust will get updated.
548
0
  CERTCertTrust trust = { CERTDB_USER, 0, 0 };
549
0
  if (ChangeCertTrustWithPossibleAuthentication(familySafetyRoot, trust,
550
0
                                                nullptr) != SECSuccess) {
551
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
552
0
            ("couldn't untrust certificate for TLS server auth"));
553
0
  }
554
0
}
555
556
// The supported values of this pref are:
557
// 0: disable detecting Family Safety mode and importing the root
558
// 1: only attempt to detect Family Safety mode (don't import the root)
559
// 2: detect Family Safety mode and import the root
560
const char* kFamilySafetyModePref = "security.family_safety.mode";
561
const uint32_t kFamilySafetyModeDefault = 0;
562
563
// The telemetry gathered by this function is as follows:
564
// 0-2: the value of the Family Safety mode pref
565
// 3: detecting Family Safety mode failed
566
// 4: Family Safety was not enabled
567
// 5: Family Safety was enabled
568
// 6: failed to import the Family Safety root
569
// 7: successfully imported the root
570
void
571
nsNSSComponent::MaybeEnableFamilySafetyCompatibility(uint32_t familySafetyMode)
572
0
{
573
#ifdef XP_WIN
574
  if (!(IsWin8Point1OrLater() && !IsWin10OrLater())) {
575
    return;
576
  }
577
  if (familySafetyMode > 2) {
578
    familySafetyMode = 0;
579
  }
580
  if (familySafetyMode == 0) {
581
    return;
582
  }
583
  bool familySafetyEnabled;
584
  nsresult rv = AccountHasFamilySafetyEnabled(familySafetyEnabled);
585
  if (NS_FAILED(rv)) {
586
    return;
587
  }
588
  if (!familySafetyEnabled) {
589
    return;
590
  }
591
  if (familySafetyMode == 2) {
592
    rv = LoadFamilySafetyRoot();
593
    if (NS_FAILED(rv)) {
594
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
595
              ("failed to load Family Safety root"));
596
    }
597
  }
598
#endif // XP_WIN
599
}
600
601
602
void
603
nsNSSComponent::UnloadEnterpriseRoots()
604
0
{
605
0
  MOZ_ASSERT(NS_IsMainThread());
606
0
  if (!NS_IsMainThread()) {
607
0
    return;
608
0
  }
609
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadEnterpriseRoots"));
610
0
611
0
  // We can't call ChangeCertTrustWithPossibleAuthentication while holding
612
0
  // mMutex (because it could potentially call back in to nsNSSComponent and
613
0
  // attempt to acquire mMutex), so we move mEnterpriseRoots out of
614
0
  // nsNSSComponent into a local handle. This has the side-effect of clearing
615
0
  // mEnterpriseRoots, which is what we want anyway.
616
0
  UniqueCERTCertList enterpriseRoots;
617
0
  {
618
0
    MutexAutoLock lock(mMutex);
619
0
    if (!mEnterpriseRoots) {
620
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
621
0
              ("no enterprise roots were present"));
622
0
      return;
623
0
    }
624
0
    enterpriseRoots = std::move(mEnterpriseRoots);
625
0
    MOZ_ASSERT(!mEnterpriseRoots);
626
0
  }
627
0
  MOZ_ASSERT(enterpriseRoots);
628
0
  // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
629
0
  // doesn't work for temporary certificates because CERT_ChangeCertTrust first
630
0
  // looks up the current trust settings in the permanent cert database, finds
631
0
  // that such trust doesn't exist, considers the current trust to be
632
0
  // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
633
0
  // they're the same. To work around this, we set a non-zero flag to ensure
634
0
  // that the trust will get updated.
635
0
  CERTCertTrust trust = { CERTDB_USER, 0, 0 };
636
0
  for (CERTCertListNode* n = CERT_LIST_HEAD(enterpriseRoots.get());
637
0
       !CERT_LIST_END(n, enterpriseRoots.get()); n = CERT_LIST_NEXT(n)) {
638
0
    if (!n) {
639
0
      break;
640
0
    }
641
0
    if (!n->cert) {
642
0
      continue;
643
0
    }
644
0
    UniqueCERTCertificate cert(CERT_DupCertificate(n->cert));
645
0
    if (ChangeCertTrustWithPossibleAuthentication(cert, trust, nullptr)
646
0
          != SECSuccess) {
647
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
648
0
              ("couldn't untrust certificate for TLS server auth"));
649
0
    }
650
0
  }
651
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("unloaded enterprise roots"));
652
0
}
653
654
static const char* kEnterpriseRootModePref = "security.enterprise_roots.enabled";
655
656
void
657
nsNSSComponent::MaybeImportEnterpriseRoots()
658
0
{
659
0
  MOZ_ASSERT(NS_IsMainThread());
660
0
  if (!NS_IsMainThread()) {
661
0
    return;
662
0
  }
663
0
  bool importEnterpriseRoots = Preferences::GetBool(kEnterpriseRootModePref,
664
0
                                                    false);
665
0
  if (!importEnterpriseRoots) {
666
0
    return;
667
0
  }
668
0
  ImportEnterpriseRoots();
669
0
}
670
671
void
672
nsNSSComponent::ImportEnterpriseRoots()
673
0
{
674
0
  UniqueCERTCertList roots;
675
0
  nsresult rv = GatherEnterpriseRoots(roots);
676
0
  if (NS_FAILED(rv)) {
677
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed gathering enterprise roots"));
678
0
    return;
679
0
  }
680
0
681
0
  {
682
0
    MutexAutoLock lock(mMutex);
683
0
    mEnterpriseRoots = std::move(roots);
684
0
  }
685
0
}
686
687
nsresult
688
nsNSSComponent::TrustLoaded3rdPartyRoots()
689
0
{
690
0
  // We can't call ChangeCertTrustWithPossibleAuthentication while holding
691
0
  // mMutex (because it could potentially call back in to nsNSSComponent and
692
0
  // attempt to acquire mMutex), so we copy mEnterpriseRoots.
693
0
  UniqueCERTCertList enterpriseRoots;
694
0
  {
695
0
    MutexAutoLock lock(mMutex);
696
0
    if (mEnterpriseRoots) {
697
0
      enterpriseRoots = nsNSSCertList::DupCertList(mEnterpriseRoots);
698
0
      if (!enterpriseRoots) {
699
0
        return NS_ERROR_OUT_OF_MEMORY;
700
0
      }
701
0
    }
702
0
  }
703
0
704
0
  CERTCertTrust trust = {
705
0
    CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER,
706
0
    0,
707
0
    0
708
0
  };
709
0
  if (enterpriseRoots) {
710
0
    for (CERTCertListNode* n = CERT_LIST_HEAD(enterpriseRoots.get());
711
0
         !CERT_LIST_END(n, enterpriseRoots.get()); n = CERT_LIST_NEXT(n)) {
712
0
      if (!n) {
713
0
        break;
714
0
      }
715
0
      if (!n->cert) {
716
0
        continue;
717
0
      }
718
0
      UniqueCERTCertificate cert(CERT_DupCertificate(n->cert));
719
0
      if (ChangeCertTrustWithPossibleAuthentication(cert, trust, nullptr)
720
0
            != SECSuccess) {
721
0
        MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
722
0
                ("couldn't trust enterprise certificate for TLS server auth"));
723
0
      }
724
0
    }
725
0
  }
726
#ifdef XP_WIN
727
  // Again copy mFamilySafetyRoot so we don't hold mMutex while calling
728
  // ChangeCertTrustWithPossibleAuthentication.
729
  UniqueCERTCertificate familySafetyRoot;
730
  {
731
    MutexAutoLock lock(mMutex);
732
    if (mFamilySafetyRoot) {
733
      familySafetyRoot.reset(CERT_DupCertificate(mFamilySafetyRoot.get()));
734
      if (!familySafetyRoot) {
735
        return NS_ERROR_OUT_OF_MEMORY;
736
      }
737
    }
738
  }
739
  if (familySafetyRoot &&
740
      ChangeCertTrustWithPossibleAuthentication(familySafetyRoot, trust,
741
                                                nullptr) != SECSuccess) {
742
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
743
            ("couldn't trust family safety certificate for TLS server auth"));
744
  }
745
#endif
746
  return NS_OK;
747
0
}
748
749
NS_IMETHODIMP
750
nsNSSComponent::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
751
0
{
752
0
  MutexAutoLock nsNSSComponentLock(mMutex);
753
0
  MOZ_ASSERT(NS_IsMainThread());
754
0
  if (!NS_IsMainThread()) {
755
0
    return NS_ERROR_NOT_SAME_THREAD;
756
0
  }
757
0
  NS_ENSURE_ARG_POINTER(enterpriseRoots);
758
0
759
0
  if (!mEnterpriseRoots) {
760
0
    *enterpriseRoots = nullptr;
761
0
    return NS_OK;
762
0
  }
763
0
  UniqueCERTCertList enterpriseRootsCopy(
764
0
    nsNSSCertList::DupCertList(mEnterpriseRoots));
765
0
  if (!enterpriseRootsCopy) {
766
0
    return NS_ERROR_FAILURE;
767
0
  }
768
0
  nsCOMPtr<nsIX509CertList> enterpriseRootsCertList(
769
0
    new nsNSSCertList(std::move(enterpriseRootsCopy)));
770
0
  if (!enterpriseRootsCertList) {
771
0
    return NS_ERROR_FAILURE;
772
0
  }
773
0
  enterpriseRootsCertList.forget(enterpriseRoots);
774
0
  return NS_OK;
775
0
}
776
777
class LoadLoadableRootsTask final : public Runnable
778
{
779
public:
780
  explicit LoadLoadableRootsTask(nsNSSComponent* nssComponent,
781
                                 bool importEnterpriseRoots,
782
                                 uint32_t familySafetyMode)
783
    : Runnable("LoadLoadableRootsTask")
784
    , mNSSComponent(nssComponent)
785
    , mImportEnterpriseRoots(importEnterpriseRoots)
786
    , mFamilySafetyMode(familySafetyMode)
787
0
  {
788
0
    MOZ_ASSERT(nssComponent);
789
0
  }
790
791
0
  ~LoadLoadableRootsTask() = default;
792
793
  nsresult Dispatch();
794
795
private:
796
  NS_IMETHOD Run() override;
797
  nsresult LoadLoadableRoots();
798
  RefPtr<nsNSSComponent> mNSSComponent;
799
  bool mImportEnterpriseRoots;
800
  uint32_t mFamilySafetyMode;
801
  nsCOMPtr<nsIThread> mThread;
802
};
803
804
nsresult
805
LoadLoadableRootsTask::Dispatch()
806
0
{
807
0
  // Can't add 'this' as the event to run, since mThread may not be set yet
808
0
  nsresult rv = NS_NewNamedThread("LoadRoots", getter_AddRefs(mThread),
809
0
                                  nullptr,
810
0
                                  nsIThreadManager::DEFAULT_STACK_SIZE);
811
0
  if (NS_FAILED(rv)) {
812
0
    return rv;
813
0
  }
814
0
815
0
  // Note: event must not null out mThread!
816
0
  return mThread->Dispatch(this, NS_DISPATCH_NORMAL);
817
0
}
818
819
NS_IMETHODIMP
820
LoadLoadableRootsTask::Run()
821
0
{
822
0
  // First we Run() on the "LoadRoots" thread, do our work, and then we Run()
823
0
  // again on the main thread so we can shut down the thread (since we don't
824
0
  // need it any more). We can't shut down the thread while we're *on* the
825
0
  // thread, which is why we do the dispatch to the main thread. CryptoTask.cpp
826
0
  // (which informs this code) says that we can't null out mThread. This appears
827
0
  // to be because its refcount could be decreased while this dispatch is being
828
0
  // processed, so it might get prematurely destroyed. I'm not sure this makes
829
0
  // sense but it'll get cleaned up in our destructor anyway, so it's fine to
830
0
  // not null it out here (as long as we don't run twice on the main thread,
831
0
  // which shouldn't be possible).
832
0
  if (NS_IsMainThread()) {
833
0
    if (mThread) {
834
0
      mThread->Shutdown();
835
0
    }
836
0
    return NS_OK;
837
0
  }
838
0
839
0
  nsresult loadLoadableRootsResult = LoadLoadableRoots();
840
0
  if (NS_WARN_IF(NS_FAILED(loadLoadableRootsResult))) {
841
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("LoadLoadableRoots failed"));
842
0
    // We don't return loadLoadableRootsResult here because then
843
0
    // BlockUntilLoadableRootsLoaded will just wait forever. Instead we'll save
844
0
    // its value (below) so we can inform code that relies on the roots module
845
0
    // being present that loading it failed.
846
0
  }
847
0
848
0
  // Loading EV information will only succeed if we've successfully loaded the
849
0
  // loadable roots module.
850
0
  if (NS_SUCCEEDED(loadLoadableRootsResult)) {
851
0
    if (NS_FAILED(LoadExtendedValidationInfo())) {
852
0
      // This isn't a show-stopper in the same way that failing to load the
853
0
      // roots module is.
854
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("failed to load EV info"));
855
0
    }
856
0
  }
857
0
858
0
  if (mImportEnterpriseRoots) {
859
0
    mNSSComponent->ImportEnterpriseRoots();
860
0
  }
861
0
  mNSSComponent->MaybeEnableFamilySafetyCompatibility(mFamilySafetyMode);
862
0
  nsresult rv = mNSSComponent->TrustLoaded3rdPartyRoots();
863
0
  if (NS_FAILED(rv)) {
864
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
865
0
            ("failed to trust loaded 3rd party roots"));
866
0
  }
867
0
868
0
  {
869
0
    MonitorAutoLock rootsLoadedLock(mNSSComponent->mLoadableRootsLoadedMonitor);
870
0
    mNSSComponent->mLoadableRootsLoaded = true;
871
0
    // Cache the result of LoadLoadableRoots so BlockUntilLoadableRootsLoaded
872
0
    // can return it to all callers later.
873
0
    mNSSComponent->mLoadableRootsLoadedResult = loadLoadableRootsResult;
874
0
    rv = mNSSComponent->mLoadableRootsLoadedMonitor.NotifyAll();
875
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
876
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Error,
877
0
              ("failed to notify loadable roots loaded monitor"));
878
0
    }
879
0
  }
880
0
881
0
  // Go back to the main thread to clean up this worker thread.
882
0
  return NS_DispatchToMainThread(this);
883
0
}
884
885
NS_IMETHODIMP
886
nsNSSComponent::HasActiveSmartCards(bool* result)
887
0
{
888
0
  NS_ENSURE_ARG_POINTER(result);
889
0
  MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
890
0
  if (!NS_IsMainThread()) {
891
0
    return NS_ERROR_NOT_SAME_THREAD;
892
0
  }
893
0
894
0
#ifndef MOZ_NO_SMART_CARDS
895
0
  MutexAutoLock nsNSSComponentLock(mMutex);
896
0
897
0
  AutoSECMODListReadLock secmodLock;
898
0
  SECMODModuleList* list = SECMOD_GetDefaultModuleList();
899
0
  while (list) {
900
0
    if (SECMOD_HasRemovableSlots(list->module)) {
901
0
      *result = true;
902
0
      return NS_OK;
903
0
    }
904
0
    list = list->next;
905
0
  }
906
0
#endif
907
0
  *result = false;
908
0
  return NS_OK;
909
0
}
910
911
NS_IMETHODIMP
912
nsNSSComponent::HasUserCertsInstalled(bool* result)
913
0
{
914
0
  NS_ENSURE_ARG_POINTER(result);
915
0
  MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
916
0
  if (!NS_IsMainThread()) {
917
0
    return NS_ERROR_NOT_SAME_THREAD;
918
0
  }
919
0
920
0
  *result = false;
921
0
  UniqueCERTCertList certList(
922
0
    CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
923
0
                              false, true, nullptr));
924
0
  if (!certList) {
925
0
    return NS_OK;
926
0
  }
927
0
928
0
  // check if the list is empty
929
0
  if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
930
0
    return NS_OK;
931
0
  }
932
0
933
0
  // The list is not empty, meaning at least one cert is installed
934
0
  *result = true;
935
0
  return NS_OK;
936
0
}
937
938
nsresult
939
nsNSSComponent::BlockUntilLoadableRootsLoaded()
940
0
{
941
0
  MonitorAutoLock rootsLoadedLock(mLoadableRootsLoadedMonitor);
942
0
  while (!mLoadableRootsLoaded) {
943
0
    rootsLoadedLock.Wait();
944
0
  }
945
0
  MOZ_ASSERT(mLoadableRootsLoaded);
946
0
947
0
  return mLoadableRootsLoadedResult;
948
0
}
949
950
nsresult
951
nsNSSComponent::CheckForSmartCardChanges()
952
0
{
953
0
#ifndef MOZ_NO_SMART_CARDS
954
0
  // SECMOD_UpdateSlotList attempts to acquire the list lock as well,
955
0
  // so we have to do this in two steps. The lock protects the list itself, so
956
0
  // if we get our own owned references to the modules we're interested in,
957
0
  // there's no thread safety concern here.
958
0
  Vector<UniqueSECMODModule> modulesWithRemovableSlots;
959
0
  {
960
0
    AutoSECMODListReadLock secmodLock;
961
0
    SECMODModuleList* list = SECMOD_GetDefaultModuleList();
962
0
    while (list) {
963
0
      if (SECMOD_HasRemovableSlots(list->module)) {
964
0
        UniqueSECMODModule module(SECMOD_ReferenceModule(list->module));
965
0
        if (!modulesWithRemovableSlots.append(std::move(module))) {
966
0
          return NS_ERROR_OUT_OF_MEMORY;
967
0
        }
968
0
      }
969
0
      list = list->next;
970
0
    }
971
0
  }
972
0
  for (auto& module : modulesWithRemovableSlots) {
973
0
    // Best-effort.
974
0
    Unused << SECMOD_UpdateSlotList(module.get());
975
0
    for (int i = 0; i < module->slotCount; i++) {
976
0
      // We actually don't care about the return value here - we just need to
977
0
      // call this to get NSS to update its view of this slot.
978
0
      Unused << PK11_IsPresent(module->slots[i]);
979
0
    }
980
0
  }
981
0
#endif
982
0
983
0
  return NS_OK;
984
0
}
985
986
// Returns by reference the path to the directory containing the file that has
987
// been loaded as MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX.
988
static nsresult
989
GetNSS3Directory(nsCString& result)
990
0
{
991
0
  UniquePRString nss3Path(
992
0
    PR_GetLibraryFilePathname(MOZ_DLL_PREFIX "nss3" MOZ_DLL_SUFFIX,
993
0
                              reinterpret_cast<PRFuncPtr>(NSS_Initialize)));
994
0
  if (!nss3Path) {
995
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nss not loaded?"));
996
0
    return NS_ERROR_FAILURE;
997
0
  }
998
0
  nsCOMPtr<nsIFile> nss3File(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
999
0
  if (!nss3File) {
1000
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't create a file?"));
1001
0
    return NS_ERROR_FAILURE;
1002
0
  }
1003
0
  nsAutoCString nss3PathAsString(nss3Path.get());
1004
0
  nsresult rv = nss3File->InitWithNativePath(nss3PathAsString);
1005
0
  if (NS_FAILED(rv)) {
1006
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1007
0
            ("couldn't initialize file with path '%s'", nss3Path.get()));
1008
0
    return rv;
1009
0
  }
1010
0
  nsCOMPtr<nsIFile> nss3Directory;
1011
0
  rv = nss3File->GetParent(getter_AddRefs(nss3Directory));
1012
0
  if (NS_FAILED(rv)) {
1013
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get parent directory?"));
1014
0
    return rv;
1015
0
  }
1016
#ifdef XP_WIN
1017
  // Native path will drop Unicode characters that cannot be mapped to system's
1018
  // codepage, using short (canonical) path as workaround.
1019
  nsCOMPtr<nsILocalFileWin> nss3DirectoryWin = do_QueryInterface(nss3Directory);
1020
  if (NS_FAILED(rv)) {
1021
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
1022
    return rv;
1023
  }
1024
  return nss3DirectoryWin->GetNativeCanonicalPath(result);
1025
#else
1026
0
  return nss3Directory->GetNativePath(result);
1027
0
#endif
1028
0
}
1029
1030
// Returns by reference the path to the desired directory, based on the current
1031
// settings in the directory service.
1032
static nsresult
1033
GetDirectoryPath(const char* directoryKey, nsCString& result)
1034
0
{
1035
0
  nsCOMPtr<nsIProperties> directoryService(
1036
0
    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
1037
0
  if (!directoryService) {
1038
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not get directory service"));
1039
0
    return NS_ERROR_FAILURE;
1040
0
  }
1041
0
  nsCOMPtr<nsIFile> directory;
1042
0
  nsresult rv = directoryService->Get(directoryKey, NS_GET_IID(nsIFile),
1043
0
                                      getter_AddRefs(directory));
1044
0
  if (NS_FAILED(rv)) {
1045
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1046
0
            ("could not get '%s' from directory service", directoryKey));
1047
0
    return rv;
1048
0
  }
1049
#ifdef XP_WIN
1050
  // Native path will drop Unicode characters that cannot be mapped to system's
1051
  // codepage, using short (canonical) path as workaround.
1052
  nsCOMPtr<nsILocalFileWin> directoryWin = do_QueryInterface(directory);
1053
  if (NS_FAILED(rv)) {
1054
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
1055
    return rv;
1056
  }
1057
  return directoryWin->GetNativeCanonicalPath(result);
1058
#else
1059
0
  return directory->GetNativePath(result);
1060
0
#endif
1061
0
}
1062
1063
1064
nsresult
1065
LoadLoadableRootsTask::LoadLoadableRoots()
1066
0
{
1067
0
  // Find the best Roots module for our purposes.
1068
0
  // Prefer the application's installation directory,
1069
0
  // but also ensure the library is at least the version we expect.
1070
0
  Vector<nsCString> possibleCKBILocations;
1071
0
  // First try in the directory where we've already loaded
1072
0
  // MOZ_DLL_PREFIX nss3 MOZ_DLL_SUFFIX, since that's likely to be correct.
1073
0
  nsAutoCString nss3Dir;
1074
0
  nsresult rv = GetNSS3Directory(nss3Dir);
1075
0
  if (NS_SUCCEEDED(rv)) {
1076
0
    if (!possibleCKBILocations.append(std::move(nss3Dir))) {
1077
0
      return NS_ERROR_OUT_OF_MEMORY;
1078
0
    }
1079
0
  } else {
1080
0
    // For some reason this fails on android. In any case, we should try with
1081
0
    // the other potential locations we have.
1082
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1083
0
            ("could not determine where nss was loaded from"));
1084
0
  }
1085
0
  nsAutoCString currentProcessDir;
1086
0
  rv = GetDirectoryPath(NS_XPCOM_CURRENT_PROCESS_DIR, currentProcessDir);
1087
0
  if (NS_SUCCEEDED(rv)) {
1088
0
    if (!possibleCKBILocations.append(std::move(currentProcessDir))) {
1089
0
      return NS_ERROR_OUT_OF_MEMORY;
1090
0
    }
1091
0
  } else {
1092
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1093
0
            ("could not get current process directory"));
1094
0
  }
1095
0
  nsAutoCString greDir;
1096
0
  rv = GetDirectoryPath(NS_GRE_DIR, greDir);
1097
0
  if (NS_SUCCEEDED(rv)) {
1098
0
    if (!possibleCKBILocations.append(std::move(greDir))) {
1099
0
      return NS_ERROR_OUT_OF_MEMORY;
1100
0
    }
1101
0
  } else {
1102
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not get gre directory"));
1103
0
  }
1104
0
  // As a last resort, this will cause the library loading code to use the OS'
1105
0
  // default library search path.
1106
0
  nsAutoCString emptyString;
1107
0
  if (!possibleCKBILocations.append(std::move(emptyString))) {
1108
0
    return NS_ERROR_OUT_OF_MEMORY;
1109
0
  }
1110
0
1111
0
  for (const auto& possibleCKBILocation : possibleCKBILocations) {
1112
0
    if (mozilla::psm::LoadLoadableRoots(possibleCKBILocation)) {
1113
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("loaded CKBI from %s",
1114
0
                                            possibleCKBILocation.get()));
1115
0
      return NS_OK;
1116
0
    }
1117
0
  }
1118
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("could not load loadable roots"));
1119
0
  return NS_ERROR_FAILURE;
1120
0
}
1121
1122
// Table of pref names and SSL cipher ID
1123
typedef struct {
1124
  const char* pref;
1125
  long id;
1126
  bool enabledByDefault;
1127
} CipherPref;
1128
1129
// Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp
1130
// when you add/remove cipher suites here.
1131
static const CipherPref sCipherPrefs[] = {
1132
 { "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
1133
   TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, true },
1134
 { "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",
1135
   TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, true },
1136
1137
 { "security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256",
1138
   TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, true },
1139
 { "security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256",
1140
   TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, true },
1141
1142
 { "security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384",
1143
   TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, true },
1144
 { "security.ssl3.ecdhe_rsa_aes_256_gcm_sha384",
1145
   TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, true },
1146
1147
 { "security.ssl3.ecdhe_rsa_aes_128_sha",
1148
   TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, true },
1149
 { "security.ssl3.ecdhe_ecdsa_aes_128_sha",
1150
   TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, true },
1151
1152
 { "security.ssl3.ecdhe_rsa_aes_256_sha",
1153
   TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, true },
1154
 { "security.ssl3.ecdhe_ecdsa_aes_256_sha",
1155
   TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, true },
1156
1157
 { "security.ssl3.dhe_rsa_aes_128_sha",
1158
   TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true },
1159
1160
 { "security.ssl3.dhe_rsa_aes_256_sha",
1161
   TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true },
1162
1163
 { "security.tls13.aes_128_gcm_sha256",
1164
   TLS_AES_128_GCM_SHA256, true },
1165
 { "security.tls13.chacha20_poly1305_sha256",
1166
   TLS_CHACHA20_POLY1305_SHA256, true },
1167
 { "security.tls13.aes_256_gcm_sha384",
1168
   TLS_AES_256_GCM_SHA384, true },
1169
1170
 { "security.ssl3.rsa_aes_128_sha",
1171
   TLS_RSA_WITH_AES_128_CBC_SHA, true }, // deprecated (RSA key exchange)
1172
 { "security.ssl3.rsa_aes_256_sha",
1173
   TLS_RSA_WITH_AES_256_CBC_SHA, true }, // deprecated (RSA key exchange)
1174
 { "security.ssl3.rsa_des_ede3_sha",
1175
   TLS_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (RSA key exchange, 3DES)
1176
1177
 // All the rest are disabled
1178
1179
 { nullptr, 0 } // end marker
1180
};
1181
1182
// This function will convert from pref values like 1, 2, ...
1183
// to the internal values of SSL_LIBRARY_VERSION_TLS_1_0,
1184
// SSL_LIBRARY_VERSION_TLS_1_1, ...
1185
/*static*/ void
1186
nsNSSComponent::FillTLSVersionRange(SSLVersionRange& rangeOut,
1187
                                    uint32_t minFromPrefs,
1188
                                    uint32_t maxFromPrefs,
1189
                                    SSLVersionRange defaults)
1190
0
{
1191
0
  rangeOut = defaults;
1192
0
  // determine what versions are supported
1193
0
  SSLVersionRange supported;
1194
0
  if (SSL_VersionRangeGetSupported(ssl_variant_stream, &supported)
1195
0
        != SECSuccess) {
1196
0
    return;
1197
0
  }
1198
0
1199
0
  // Clip the defaults by what NSS actually supports to enable
1200
0
  // working with a system NSS with different ranges.
1201
0
  rangeOut.min = std::max(rangeOut.min, supported.min);
1202
0
  rangeOut.max = std::min(rangeOut.max, supported.max);
1203
0
1204
0
  // convert min/maxFromPrefs to the internal representation
1205
0
  minFromPrefs += SSL_LIBRARY_VERSION_3_0;
1206
0
  maxFromPrefs += SSL_LIBRARY_VERSION_3_0;
1207
0
  // if min/maxFromPrefs are invalid, use defaults
1208
0
  if (minFromPrefs > maxFromPrefs ||
1209
0
      minFromPrefs < supported.min || maxFromPrefs > supported.max ||
1210
0
      minFromPrefs < SSL_LIBRARY_VERSION_TLS_1_0) {
1211
0
    return;
1212
0
  }
1213
0
1214
0
  // fill out rangeOut
1215
0
  rangeOut.min = (uint16_t) minFromPrefs;
1216
0
  rangeOut.max = (uint16_t) maxFromPrefs;
1217
0
}
1218
1219
static const int32_t OCSP_ENABLED_DEFAULT = 1;
1220
static const bool REQUIRE_SAFE_NEGOTIATION_DEFAULT = false;
1221
static const bool FALSE_START_ENABLED_DEFAULT = true;
1222
static const bool ALPN_ENABLED_DEFAULT = false;
1223
static const bool ENABLED_0RTT_DATA_DEFAULT = false;
1224
static const bool HELLO_DOWNGRADE_CHECK_DEFAULT = false;
1225
1226
static void
1227
ConfigureTLSSessionIdentifiers()
1228
0
{
1229
0
  bool disableSessionIdentifiers =
1230
0
    Preferences::GetBool("security.ssl.disable_session_identifiers", false);
1231
0
  SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, !disableSessionIdentifiers);
1232
0
  SSL_OptionSetDefault(SSL_NO_CACHE, disableSessionIdentifiers);
1233
0
}
1234
1235
namespace {
1236
1237
class CipherSuiteChangeObserver : public nsIObserver
1238
{
1239
public:
1240
  NS_DECL_ISUPPORTS
1241
  NS_DECL_NSIOBSERVER
1242
1243
  static nsresult StartObserve();
1244
1245
protected:
1246
0
  virtual ~CipherSuiteChangeObserver() {}
1247
1248
private:
1249
  static StaticRefPtr<CipherSuiteChangeObserver> sObserver;
1250
0
  CipherSuiteChangeObserver() {}
1251
};
1252
1253
NS_IMPL_ISUPPORTS(CipherSuiteChangeObserver, nsIObserver)
1254
1255
// static
1256
StaticRefPtr<CipherSuiteChangeObserver> CipherSuiteChangeObserver::sObserver;
1257
1258
// static
1259
nsresult
1260
CipherSuiteChangeObserver::StartObserve()
1261
0
{
1262
0
  MOZ_ASSERT(NS_IsMainThread(),
1263
0
             "CipherSuiteChangeObserver::StartObserve() can only be accessed "
1264
0
             "on the main thread");
1265
0
  if (!sObserver) {
1266
0
    RefPtr<CipherSuiteChangeObserver> observer = new CipherSuiteChangeObserver();
1267
0
    nsresult rv = Preferences::AddStrongObserver(observer.get(), "security.");
1268
0
    if (NS_FAILED(rv)) {
1269
0
      sObserver = nullptr;
1270
0
      return rv;
1271
0
    }
1272
0
1273
0
    nsCOMPtr<nsIObserverService> observerService =
1274
0
      mozilla::services::GetObserverService();
1275
0
    observerService->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
1276
0
                                 false);
1277
0
1278
0
    sObserver = observer;
1279
0
  }
1280
0
  return NS_OK;
1281
0
}
1282
1283
nsresult
1284
CipherSuiteChangeObserver::Observe(nsISupports* /*aSubject*/,
1285
                                   const char* aTopic,
1286
                                   const char16_t* someData)
1287
0
{
1288
0
  MOZ_ASSERT(NS_IsMainThread(),
1289
0
             "CipherSuiteChangeObserver::Observe can only be accessed on main "
1290
0
             "thread");
1291
0
  if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1292
0
    NS_ConvertUTF16toUTF8  prefName(someData);
1293
0
    // Look through the cipher table and set according to pref setting
1294
0
    const CipherPref* const cp = sCipherPrefs;
1295
0
    for (size_t i = 0; cp[i].pref; ++i) {
1296
0
      if (prefName.Equals(cp[i].pref)) {
1297
0
        bool cipherEnabled = Preferences::GetBool(cp[i].pref,
1298
0
                                                  cp[i].enabledByDefault);
1299
0
        SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
1300
0
        SSL_ClearSessionCache();
1301
0
        break;
1302
0
      }
1303
0
    }
1304
0
  } else if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
1305
0
    Preferences::RemoveObserver(this, "security.");
1306
0
    MOZ_ASSERT(sObserver.get() == this);
1307
0
    sObserver = nullptr;
1308
0
    nsCOMPtr<nsIObserverService> observerService =
1309
0
      mozilla::services::GetObserverService();
1310
0
    observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
1311
0
  }
1312
0
  return NS_OK;
1313
0
}
1314
1315
} // namespace
1316
1317
void nsNSSComponent::setValidationOptions(
1318
  bool isInitialSetting, const mozilla::MutexAutoLock& proofOfLock)
1319
0
{
1320
0
  // This preference controls whether we do OCSP fetching and does not affect
1321
0
  // OCSP stapling.
1322
0
  // 0 = disabled, 1 = enabled
1323
0
  int32_t ocspEnabled = Preferences::GetInt("security.OCSP.enabled",
1324
0
                                            OCSP_ENABLED_DEFAULT);
1325
0
1326
0
  bool ocspRequired = ocspEnabled &&
1327
0
    Preferences::GetBool("security.OCSP.require", false);
1328
0
1329
0
  // We measure the setting of the pref at startup only to minimize noise by
1330
0
  // addons that may muck with the settings, though it probably doesn't matter.
1331
0
  if (isInitialSetting) {
1332
0
    Telemetry::Accumulate(Telemetry::CERT_OCSP_ENABLED, ocspEnabled);
1333
0
    Telemetry::Accumulate(Telemetry::CERT_OCSP_REQUIRED, ocspRequired);
1334
0
  }
1335
0
1336
0
  bool ocspStaplingEnabled = Preferences::GetBool("security.ssl.enable_ocsp_stapling",
1337
0
                                                  true);
1338
0
  PublicSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
1339
0
  PrivateSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
1340
0
1341
0
  bool ocspMustStapleEnabled = Preferences::GetBool("security.ssl.enable_ocsp_must_staple",
1342
0
                                                    true);
1343
0
  PublicSSLState()->SetOCSPMustStapleEnabled(ocspMustStapleEnabled);
1344
0
  PrivateSSLState()->SetOCSPMustStapleEnabled(ocspMustStapleEnabled);
1345
0
1346
0
  const CertVerifier::CertificateTransparencyMode defaultCTMode =
1347
0
    CertVerifier::CertificateTransparencyMode::TelemetryOnly;
1348
0
  CertVerifier::CertificateTransparencyMode ctMode =
1349
0
    static_cast<CertVerifier::CertificateTransparencyMode>
1350
0
      (Preferences::GetInt("security.pki.certificate_transparency.mode",
1351
0
                           static_cast<int32_t>(defaultCTMode)));
1352
0
  switch (ctMode) {
1353
0
    case CertVerifier::CertificateTransparencyMode::Disabled:
1354
0
    case CertVerifier::CertificateTransparencyMode::TelemetryOnly:
1355
0
      break;
1356
0
    default:
1357
0
      ctMode = defaultCTMode;
1358
0
      break;
1359
0
  }
1360
0
  bool sctsEnabled =
1361
0
    ctMode != CertVerifier::CertificateTransparencyMode::Disabled;
1362
0
  PublicSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);
1363
0
  PrivateSSLState()->SetSignedCertTimestampsEnabled(sctsEnabled);
1364
0
1365
0
  CertVerifier::PinningMode pinningMode =
1366
0
    static_cast<CertVerifier::PinningMode>
1367
0
      (Preferences::GetInt("security.cert_pinning.enforcement_level",
1368
0
                           CertVerifier::pinningDisabled));
1369
0
  if (pinningMode > CertVerifier::pinningEnforceTestMode) {
1370
0
    pinningMode = CertVerifier::pinningDisabled;
1371
0
  }
1372
0
1373
0
  CertVerifier::SHA1Mode sha1Mode = static_cast<CertVerifier::SHA1Mode>
1374
0
      (Preferences::GetInt("security.pki.sha1_enforcement_level",
1375
0
                           static_cast<int32_t>(CertVerifier::SHA1Mode::Allowed)));
1376
0
  switch (sha1Mode) {
1377
0
    case CertVerifier::SHA1Mode::Allowed:
1378
0
    case CertVerifier::SHA1Mode::Forbidden:
1379
0
    case CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
1380
0
    case CertVerifier::SHA1Mode::ImportedRoot:
1381
0
    case CertVerifier::SHA1Mode::ImportedRootOrBefore2016:
1382
0
      break;
1383
0
    default:
1384
0
      sha1Mode = CertVerifier::SHA1Mode::Allowed;
1385
0
      break;
1386
0
  }
1387
0
1388
0
  // Convert a previously-available setting to a safe one.
1389
0
  if (sha1Mode == CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden) {
1390
0
    sha1Mode = CertVerifier::SHA1Mode::Forbidden;
1391
0
  }
1392
0
1393
0
  BRNameMatchingPolicy::Mode nameMatchingMode =
1394
0
    static_cast<BRNameMatchingPolicy::Mode>
1395
0
      (Preferences::GetInt("security.pki.name_matching_mode",
1396
0
                           static_cast<int32_t>(BRNameMatchingPolicy::Mode::DoNotEnforce)));
1397
0
  switch (nameMatchingMode) {
1398
0
    case BRNameMatchingPolicy::Mode::Enforce:
1399
0
    case BRNameMatchingPolicy::Mode::EnforceAfter23August2015:
1400
0
    case BRNameMatchingPolicy::Mode::EnforceAfter23August2016:
1401
0
    case BRNameMatchingPolicy::Mode::DoNotEnforce:
1402
0
      break;
1403
0
    default:
1404
0
      nameMatchingMode = BRNameMatchingPolicy::Mode::DoNotEnforce;
1405
0
      break;
1406
0
  }
1407
0
1408
0
  NetscapeStepUpPolicy netscapeStepUpPolicy =
1409
0
    static_cast<NetscapeStepUpPolicy>
1410
0
      (Preferences::GetUint("security.pki.netscape_step_up_policy",
1411
0
                            static_cast<uint32_t>(NetscapeStepUpPolicy::AlwaysMatch)));
1412
0
  switch (netscapeStepUpPolicy) {
1413
0
    case NetscapeStepUpPolicy::AlwaysMatch:
1414
0
    case NetscapeStepUpPolicy::MatchBefore23August2016:
1415
0
    case NetscapeStepUpPolicy::MatchBefore23August2015:
1416
0
    case NetscapeStepUpPolicy::NeverMatch:
1417
0
      break;
1418
0
    default:
1419
0
      netscapeStepUpPolicy = NetscapeStepUpPolicy::AlwaysMatch;
1420
0
      break;
1421
0
  }
1422
0
1423
0
  DistrustedCAPolicy defaultCAPolicyMode =
1424
0
    DistrustedCAPolicy::DistrustSymantecRoots;
1425
0
  DistrustedCAPolicy distrustedCAPolicy =
1426
0
    static_cast<DistrustedCAPolicy>
1427
0
      (Preferences::GetUint("security.pki.distrust_ca_policy",
1428
0
                            static_cast<uint32_t>(defaultCAPolicyMode)));
1429
0
  // If distrustedCAPolicy sets any bits larger than the maximum mask, fall back
1430
0
  // to the default.
1431
0
  if (distrustedCAPolicy & ~DistrustedCAPolicyMaxAllowedValueMask) {
1432
0
    distrustedCAPolicy = defaultCAPolicyMode;
1433
0
  }
1434
0
1435
0
  CertVerifier::OcspDownloadConfig odc;
1436
0
  CertVerifier::OcspStrictConfig osc;
1437
0
  uint32_t certShortLifetimeInDays;
1438
0
  TimeDuration softTimeout;
1439
0
  TimeDuration hardTimeout;
1440
0
1441
0
  GetRevocationBehaviorFromPrefs(&odc, &osc, &certShortLifetimeInDays,
1442
0
                                 softTimeout, hardTimeout, proofOfLock);
1443
0
  mDefaultCertVerifier = new SharedCertVerifier(odc, osc, softTimeout,
1444
0
                                                hardTimeout,
1445
0
                                                certShortLifetimeInDays,
1446
0
                                                pinningMode, sha1Mode,
1447
0
                                                nameMatchingMode,
1448
0
                                                netscapeStepUpPolicy,
1449
0
                                                ctMode, distrustedCAPolicy);
1450
0
}
1451
1452
// Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and
1453
// TLS 1.2 (max) when the prefs aren't set or set to invalid values.
1454
nsresult
1455
nsNSSComponent::setEnabledTLSVersions()
1456
0
{
1457
0
  // keep these values in sync with security-prefs.js
1458
0
  // 1 means TLS 1.0, 2 means TLS 1.1, etc.
1459
0
  static const uint32_t PSM_DEFAULT_MIN_TLS_VERSION = 1;
1460
0
  static const uint32_t PSM_DEFAULT_MAX_TLS_VERSION = 4;
1461
0
1462
0
  uint32_t minFromPrefs = Preferences::GetUint("security.tls.version.min",
1463
0
                                               PSM_DEFAULT_MIN_TLS_VERSION);
1464
0
  uint32_t maxFromPrefs = Preferences::GetUint("security.tls.version.max",
1465
0
                                               PSM_DEFAULT_MAX_TLS_VERSION);
1466
0
1467
0
  SSLVersionRange defaults = {
1468
0
    SSL_LIBRARY_VERSION_3_0 + PSM_DEFAULT_MIN_TLS_VERSION,
1469
0
    SSL_LIBRARY_VERSION_3_0 + PSM_DEFAULT_MAX_TLS_VERSION
1470
0
  };
1471
0
  SSLVersionRange filledInRange;
1472
0
  FillTLSVersionRange(filledInRange, minFromPrefs, maxFromPrefs, defaults);
1473
0
1474
0
  SECStatus srv =
1475
0
    SSL_VersionRangeSetDefault(ssl_variant_stream, &filledInRange);
1476
0
  if (srv != SECSuccess) {
1477
0
    return NS_ERROR_FAILURE;
1478
0
  }
1479
0
1480
0
  return NS_OK;
1481
0
}
1482
1483
#if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
1484
// If the profile directory is on a networked drive, we want to set the
1485
// environment variable NSS_SDB_USE_CACHE to yes (as long as it hasn't been set
1486
// before).
1487
static void
1488
SetNSSDatabaseCacheModeAsAppropriate()
1489
0
{
1490
0
  nsCOMPtr<nsIFile> profileFile;
1491
0
  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
1492
0
                                       getter_AddRefs(profileFile));
1493
0
  if (NS_FAILED(rv)) {
1494
0
    // We're probably running without a profile directory, so this is
1495
0
    // irrelevant.
1496
0
    return;
1497
0
  }
1498
0
1499
0
  static const char sNSS_SDB_USE_CACHE[] = "NSS_SDB_USE_CACHE";
1500
0
  static const char sNSS_SDB_USE_CACHE_WITH_VALUE[] = "NSS_SDB_USE_CACHE=yes";
1501
0
  auto profilePath = profileFile->NativePath();
1502
0
1503
0
#if defined(XP_LINUX) && !defined(ANDROID)
1504
0
  struct statfs statfs_s;
1505
0
  if (statfs(profilePath.get(), &statfs_s) == 0 &&
1506
0
      statfs_s.f_type == NFS_SUPER_MAGIC &&
1507
0
      !PR_GetEnv(sNSS_SDB_USE_CACHE)) {
1508
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1509
0
            ("profile is remote (and NSS_SDB_USE_CACHE wasn't set): "
1510
0
             "setting NSS_SDB_USE_CACHE"));
1511
0
    PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);
1512
0
  } else {
1513
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("not setting NSS_SDB_USE_CACHE"));
1514
0
  }
1515
0
#endif // defined(XP_LINUX) && !defined(ANDROID)
1516
0
1517
#ifdef XP_WIN
1518
  wchar_t volPath[MAX_PATH];
1519
  if (::GetVolumePathNameW(profilePath.get(), volPath, MAX_PATH) &&
1520
      ::GetDriveTypeW(volPath) == DRIVE_REMOTE &&
1521
      !PR_GetEnv(sNSS_SDB_USE_CACHE)) {
1522
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1523
            ("profile is remote (and NSS_SDB_USE_CACHE wasn't set): "
1524
             "setting NSS_SDB_USE_CACHE"));
1525
    PR_SetEnv(sNSS_SDB_USE_CACHE_WITH_VALUE);
1526
  } else {
1527
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("not setting NSS_SDB_USE_CACHE"));
1528
  }
1529
#endif // XP_WIN
1530
}
1531
#endif // defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
1532
1533
static nsresult
1534
GetNSSProfilePath(nsAutoCString& aProfilePath)
1535
0
{
1536
0
  aProfilePath.Truncate();
1537
0
  nsCOMPtr<nsIFile> profileFile;
1538
0
  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
1539
0
                                       getter_AddRefs(profileFile));
1540
0
  if (NS_FAILED(rv)) {
1541
0
    NS_WARNING("NSS will be initialized without a profile directory. "
1542
0
               "Some things may not work as expected.");
1543
0
    return NS_OK;
1544
0
  }
1545
0
1546
#if defined(XP_WIN)
1547
  // SQLite always takes UTF-8 file paths regardless of the current system
1548
  // code page.
1549
  nsCOMPtr<nsILocalFileWin> profileFileWin(do_QueryInterface(profileFile));
1550
  if (!profileFileWin) {
1551
    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
1552
           ("Could not get nsILocalFileWin for profile directory.\n"));
1553
    return NS_ERROR_FAILURE;
1554
  }
1555
  nsAutoString u16ProfilePath;
1556
  rv = profileFileWin->GetCanonicalPath(u16ProfilePath);
1557
  CopyUTF16toUTF8(u16ProfilePath, aProfilePath);
1558
#else
1559
0
  rv = profileFile->GetNativePath(aProfilePath);
1560
0
#endif
1561
0
  if (NS_FAILED(rv)) {
1562
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
1563
0
           ("Could not get native path for profile directory.\n"));
1564
0
    return rv;
1565
0
  }
1566
0
1567
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1568
0
          ("NSS profile at '%s'\n", aProfilePath.get()));
1569
0
  return NS_OK;
1570
0
}
1571
1572
#ifndef ANDROID
1573
// Given a profile path, attempt to rename the PKCS#11 module DB to
1574
// "<original name>.fips". In the case of a catastrophic failure (e.g. out of
1575
// memory), returns a failing nsresult. If execution could conceivably proceed,
1576
// returns NS_OK even if renaming the file didn't work. This simplifies the
1577
// logic of the calling code.
1578
static nsresult
1579
AttemptToRenamePKCS11ModuleDB(const nsACString& profilePath,
1580
                              const nsACString& moduleDBFilename)
1581
0
{
1582
0
  nsAutoCString destModuleDBFilename(moduleDBFilename);
1583
0
  destModuleDBFilename.Append(".fips");
1584
0
  nsCOMPtr<nsIFile> dbFile = do_CreateInstance("@mozilla.org/file/local;1");
1585
0
  if (!dbFile) {
1586
0
    return NS_ERROR_FAILURE;
1587
0
  }
1588
0
  nsresult rv = dbFile->InitWithNativePath(profilePath);
1589
0
  if (NS_FAILED(rv)) {
1590
0
    return rv;
1591
0
  }
1592
0
  rv = dbFile->AppendNative(moduleDBFilename);
1593
0
  if (NS_FAILED(rv)) {
1594
0
    return rv;
1595
0
  }
1596
0
  // If the PKCS#11 module DB doesn't exist, renaming it won't help.
1597
0
  bool exists;
1598
0
  rv = dbFile->Exists(&exists);
1599
0
  if (NS_FAILED(rv)) {
1600
0
    return rv;
1601
0
  }
1602
0
  // This is strange, but not a catastrophic failure.
1603
0
  if (!exists) {
1604
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1605
0
            ("%s doesn't exist?", PromiseFlatCString(moduleDBFilename).get()));
1606
0
    return NS_OK;
1607
0
  }
1608
0
  nsCOMPtr<nsIFile> destDBFile = do_CreateInstance("@mozilla.org/file/local;1");
1609
0
  if (!destDBFile) {
1610
0
    return NS_ERROR_FAILURE;
1611
0
  }
1612
0
  rv = destDBFile->InitWithNativePath(profilePath);
1613
0
  if (NS_FAILED(rv)) {
1614
0
    return rv;
1615
0
  }
1616
0
  rv = destDBFile->AppendNative(destModuleDBFilename);
1617
0
  if (NS_FAILED(rv)) {
1618
0
    return rv;
1619
0
  }
1620
0
  // If the destination exists, presumably we've already tried this. Doing it
1621
0
  // again won't help.
1622
0
  rv = destDBFile->Exists(&exists);
1623
0
  if (NS_FAILED(rv)) {
1624
0
    return rv;
1625
0
  }
1626
0
  // Unfortunate, but not a catastrophic failure.
1627
0
  if (exists) {
1628
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1629
0
            ("%s already exists - not overwriting",
1630
0
             destModuleDBFilename.get()));
1631
0
    return NS_OK;
1632
0
  }
1633
0
  // Now do the actual move.
1634
0
  nsCOMPtr<nsIFile> profileDir = do_CreateInstance("@mozilla.org/file/local;1");
1635
0
  if (!profileDir) {
1636
0
    return NS_ERROR_FAILURE;
1637
0
  }
1638
0
  rv = profileDir->InitWithNativePath(profilePath);
1639
0
  if (NS_FAILED(rv)) {
1640
0
    return rv;
1641
0
  }
1642
0
  // This may fail on, e.g., a read-only file system. This would be unfortunate,
1643
0
  // but again it isn't catastropic and we would want to fall back to
1644
0
  // initializing NSS in no-DB mode.
1645
0
  Unused << dbFile->MoveToNative(profileDir, destModuleDBFilename);
1646
0
  return NS_OK;
1647
0
}
1648
1649
// The platform now only uses the sqlite-backed databases, so we'll try to
1650
// rename "pkcs11.txt". However, if we're upgrading from a version that used the
1651
// old format, we need to try to rename the old "secmod.db" as well (if we were
1652
// to only rename "pkcs11.txt", initializing NSS will still fail due to the old
1653
// database being in FIPS mode).
1654
static nsresult
1655
AttemptToRenameBothPKCS11ModuleDBVersions(const nsACString& profilePath)
1656
0
{
1657
0
  NS_NAMED_LITERAL_CSTRING(legacyModuleDBFilename, "secmod.db");
1658
0
  NS_NAMED_LITERAL_CSTRING(sqlModuleDBFilename, "pkcs11.txt");
1659
0
  nsresult rv = AttemptToRenamePKCS11ModuleDB(profilePath,
1660
0
                                              legacyModuleDBFilename);
1661
0
  if (NS_FAILED(rv)) {
1662
0
    return rv;
1663
0
  }
1664
0
  return AttemptToRenamePKCS11ModuleDB(profilePath, sqlModuleDBFilename);
1665
0
}
1666
1667
// When we changed from the old dbm database format to the newer sqlite
1668
// implementation, the upgrade process left behind the existing files. Suppose a
1669
// user had not set a password for the old key3.db (which is about 99% of
1670
// users). After upgrading, both the old database and the new database are
1671
// unprotected. If the user then sets a password for the new database, the old
1672
// one will not be protected. In this scenario, we should probably just remove
1673
// the old database (it would only be relevant if the user downgraded to a
1674
// version of Firefox before 58, but we have to trade this off against the
1675
// user's old private keys being unexpectedly unprotected after setting a
1676
// password).
1677
// This was never an issue on Android because we always used the new
1678
// implementation.
1679
static void
1680
MaybeCleanUpOldNSSFiles(const nsACString& profilePath)
1681
0
{
1682
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
1683
0
  if (!slot) {
1684
0
    return;
1685
0
  }
1686
0
  // Unfortunately we can't now tell the difference between "there already was a
1687
0
  // password when the upgrade happened" and "there was not a password but then
1688
0
  // the user added one after upgrading".
1689
0
  bool hasPassword = PK11_NeedLogin(slot.get()) &&
1690
0
                     !PK11_NeedUserInit(slot.get());
1691
0
  if (!hasPassword) {
1692
0
    return;
1693
0
  }
1694
0
  nsCOMPtr<nsIFile> dbFile = do_CreateInstance("@mozilla.org/file/local;1");
1695
0
  if (!dbFile) {
1696
0
    return;
1697
0
  }
1698
0
  nsresult rv = dbFile->InitWithNativePath(profilePath);
1699
0
  if (NS_FAILED(rv)) {
1700
0
    return;
1701
0
  }
1702
0
  NS_NAMED_LITERAL_CSTRING(keyDBFilename, "key3.db");
1703
0
  rv = dbFile->AppendNative(keyDBFilename);
1704
0
  if (NS_FAILED(rv)) {
1705
0
    return;
1706
0
  }
1707
0
  // Since this isn't a directory, the `recursive` argument to `Remove` is
1708
0
  // irrelevant.
1709
0
  Unused << dbFile->Remove(false);
1710
0
}
1711
#endif // ifndef ANDROID
1712
1713
// Given a profile directory, attempt to initialize NSS. If nocertdb is true,
1714
// (or if we don't have a profile directory) simply initialize NSS in no DB mode
1715
// and return. Otherwise, first attempt to initialize in read/write mode, and
1716
// then read-only mode if that fails. If both attempts fail, we may be failing
1717
// to initialize an NSS DB collection that has FIPS mode enabled. Attempt to
1718
// ascertain if this is the case, and if so, rename the offending PKCS#11 module
1719
// DB so we can (hopefully) initialize NSS in read-write mode. Again attempt
1720
// read-only mode if that fails. Finally, fall back to no DB mode. On Android
1721
// we can skip the FIPS workaround since it was never possible to enable FIPS
1722
// there anyway.
1723
static nsresult
1724
InitializeNSSWithFallbacks(const nsACString& profilePath, bool nocertdb,
1725
                           bool safeMode)
1726
0
{
1727
0
  if (nocertdb || profilePath.IsEmpty()) {
1728
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1729
0
            ("nocertdb mode or empty profile path -> NSS_NoDB_Init"));
1730
0
    SECStatus srv = NSS_NoDB_Init(nullptr);
1731
0
    return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
1732
0
  }
1733
0
1734
0
1735
0
  // Try read/write mode. If we're in safeMode, we won't load PKCS#11 modules.
1736
0
#ifndef ANDROID
1737
0
  PRErrorCode savedPRErrorCode1;
1738
0
#endif // ifndef ANDROID
1739
0
  SECStatus srv = ::mozilla::psm::InitializeNSS(profilePath, false, !safeMode);
1740
0
  if (srv == SECSuccess) {
1741
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r/w mode"));
1742
0
#ifndef ANDROID
1743
0
    MaybeCleanUpOldNSSFiles(profilePath);
1744
0
#endif // ifndef ANDROID
1745
0
    return NS_OK;
1746
0
  }
1747
0
#ifndef ANDROID
1748
0
  savedPRErrorCode1 = PR_GetError();
1749
0
  PRErrorCode savedPRErrorCode2;
1750
0
#endif // ifndef ANDROID
1751
0
  // That failed. Try read-only mode.
1752
0
  srv = ::mozilla::psm::InitializeNSS(profilePath, true, !safeMode);
1753
0
  if (srv == SECSuccess) {
1754
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized NSS in r-o mode"));
1755
0
    return NS_OK;
1756
0
  }
1757
0
#ifndef ANDROID
1758
0
  savedPRErrorCode2 = PR_GetError();
1759
0
1760
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1761
0
          ("failed to initialize NSS with codes %d %d", savedPRErrorCode1,
1762
0
           savedPRErrorCode2));
1763
0
#endif // ifndef ANDROID
1764
0
1765
0
#ifndef ANDROID
1766
0
  // That failed as well. Maybe we're trying to load a PKCS#11 module DB that is
1767
0
  // in FIPS mode, but we don't support FIPS? Test load NSS without PKCS#11
1768
0
  // modules. If that succeeds, that's probably what's going on.
1769
0
  if (!safeMode && (savedPRErrorCode1 == SEC_ERROR_LEGACY_DATABASE ||
1770
0
                    savedPRErrorCode2 == SEC_ERROR_LEGACY_DATABASE ||
1771
0
                    savedPRErrorCode1 == SEC_ERROR_PKCS11_DEVICE_ERROR ||
1772
0
                    savedPRErrorCode2 == SEC_ERROR_PKCS11_DEVICE_ERROR)) {
1773
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("attempting no-module db init"));
1774
0
    // It would make sense to initialize NSS in read-only mode here since this
1775
0
    // is just a test to see if the PKCS#11 module DB being in FIPS mode is the
1776
0
    // problem, but for some reason the combination of read-only and no-moddb
1777
0
    // flags causes NSS initialization to fail, so unfortunately we have to use
1778
0
    // read-write mode.
1779
0
    srv = ::mozilla::psm::InitializeNSS(profilePath, false, false);
1780
0
    if (srv == SECSuccess) {
1781
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("FIPS may be the problem"));
1782
0
      // Unload NSS so we can attempt to fix this situation for the user.
1783
0
      srv = NSS_Shutdown();
1784
0
      if (srv != SECSuccess) {
1785
0
        return NS_ERROR_FAILURE;
1786
0
      }
1787
0
      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trying to rename module db"));
1788
0
      // If this fails non-catastrophically, we'll attempt to initialize NSS
1789
0
      // again in r/w then r-o mode (both of which will fail), and then we'll
1790
0
      // fall back to NSS_NoDB_Init, which is the behavior we want.
1791
0
      nsresult rv = AttemptToRenameBothPKCS11ModuleDBVersions(profilePath);
1792
0
      if (NS_FAILED(rv)) {
1793
0
        return rv;
1794
0
      }
1795
0
      srv = ::mozilla::psm::InitializeNSS(profilePath, false, true);
1796
0
      if (srv == SECSuccess) {
1797
0
        MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r/w mode"));
1798
0
        return NS_OK;
1799
0
      }
1800
0
      srv = ::mozilla::psm::InitializeNSS(profilePath, true, true);
1801
0
      if (srv == SECSuccess) {
1802
0
        MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("initialized in r-o mode"));
1803
0
        return NS_OK;
1804
0
      }
1805
0
    }
1806
0
  }
1807
0
#endif
1808
0
1809
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("last-resort NSS_NoDB_Init"));
1810
0
  srv = NSS_NoDB_Init(nullptr);
1811
0
  return srv == SECSuccess ? NS_OK : NS_ERROR_FAILURE;
1812
0
}
1813
1814
nsresult
1815
nsNSSComponent::InitializeNSS()
1816
0
{
1817
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::InitializeNSS\n"));
1818
0
1819
0
  static_assert(nsINSSErrorsService::NSS_SEC_ERROR_BASE == SEC_ERROR_BASE &&
1820
0
                nsINSSErrorsService::NSS_SEC_ERROR_LIMIT == SEC_ERROR_LIMIT &&
1821
0
                nsINSSErrorsService::NSS_SSL_ERROR_BASE == SSL_ERROR_BASE &&
1822
0
                nsINSSErrorsService::NSS_SSL_ERROR_LIMIT == SSL_ERROR_LIMIT,
1823
0
                "You must update the values in nsINSSErrorsService.idl");
1824
0
1825
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization beginning\n"));
1826
0
1827
0
  nsAutoCString profileStr;
1828
0
  nsresult rv = GetNSSProfilePath(profileStr);
1829
0
  if (NS_FAILED(rv)) {
1830
0
    return NS_ERROR_NOT_AVAILABLE;
1831
0
  }
1832
0
1833
0
#if defined(XP_WIN) || (defined(XP_LINUX) && !defined(ANDROID))
1834
0
  SetNSSDatabaseCacheModeAsAppropriate();
1835
0
#endif
1836
0
1837
0
  bool nocertdb = Preferences::GetBool("security.nocertdb", false);
1838
0
  bool inSafeMode = true;
1839
0
  nsCOMPtr<nsIXULRuntime> runtime(do_GetService("@mozilla.org/xre/runtime;1"));
1840
0
  // There might not be an nsIXULRuntime in embedded situations. This will
1841
0
  // default to assuming we are in safe mode (as a result, no external PKCS11
1842
0
  // modules will be loaded).
1843
0
  if (runtime) {
1844
0
    rv = runtime->GetInSafeMode(&inSafeMode);
1845
0
    if (NS_FAILED(rv)) {
1846
0
      return rv;
1847
0
    }
1848
0
  }
1849
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("inSafeMode: %u\n", inSafeMode));
1850
0
1851
0
  rv = InitializeNSSWithFallbacks(profileStr, nocertdb, inSafeMode);
1852
0
  if (NS_FAILED(rv)) {
1853
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to initialize NSS"));
1854
0
    return rv;
1855
0
  }
1856
0
1857
0
  PK11_SetPasswordFunc(PK11PasswordPrompt);
1858
0
1859
0
  SharedSSLState::GlobalInit();
1860
0
1861
0
  // Register an observer so we can inform NSS when these prefs change
1862
0
  Preferences::AddStrongObserver(this, "security.");
1863
0
1864
0
  SSL_OptionSetDefault(SSL_ENABLE_SSL2, false);
1865
0
  SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, false);
1866
0
1867
0
  rv = setEnabledTLSVersions();
1868
0
  if (NS_FAILED(rv)) {
1869
0
    return NS_ERROR_UNEXPECTED;
1870
0
  }
1871
0
1872
0
  DisableMD5();
1873
0
1874
0
  ConfigureTLSSessionIdentifiers();
1875
0
1876
0
  bool requireSafeNegotiation =
1877
0
    Preferences::GetBool("security.ssl.require_safe_negotiation",
1878
0
                         REQUIRE_SAFE_NEGOTIATION_DEFAULT);
1879
0
  SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
1880
0
1881
0
  SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_REQUIRES_XTN);
1882
0
1883
0
  SSL_OptionSetDefault(SSL_ENABLE_EXTENDED_MASTER_SECRET, true);
1884
0
1885
0
  bool enableDowngradeCheck =
1886
0
      Preferences::GetBool("security.tls.hello_downgrade_check",
1887
0
                           HELLO_DOWNGRADE_CHECK_DEFAULT);
1888
0
  SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, enableDowngradeCheck);
1889
0
1890
0
  SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,
1891
0
                       Preferences::GetBool("security.ssl.enable_false_start",
1892
0
                                            FALSE_START_ENABLED_DEFAULT));
1893
0
1894
0
  // SSL_ENABLE_ALPN also requires calling SSL_SetNextProtoNego in order for
1895
0
  // the extensions to be negotiated.
1896
0
  // WebRTC does not do that so it will not use ALPN even when this preference
1897
0
  // is true.
1898
0
  SSL_OptionSetDefault(SSL_ENABLE_ALPN,
1899
0
                       Preferences::GetBool("security.ssl.enable_alpn",
1900
0
                                            ALPN_ENABLED_DEFAULT));
1901
0
1902
0
  SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
1903
0
                       Preferences::GetBool("security.tls.enable_0rtt_data",
1904
0
                                            ENABLED_0RTT_DATA_DEFAULT));
1905
0
1906
0
  if (NS_FAILED(InitializeCipherSuite())) {
1907
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to initialize cipher suite settings\n"));
1908
0
    return NS_ERROR_FAILURE;
1909
0
  }
1910
0
1911
0
  mozilla::pkix::RegisterErrorTable();
1912
0
1913
0
  if (PK11_IsFIPS()) {
1914
0
    Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
1915
0
  }
1916
0
1917
0
  // Gather telemetry on any PKCS#11 modules we have loaded. Note that because
1918
0
  // we load the built-in root module asynchronously after this, the telemetry
1919
0
  // will not include it.
1920
0
  { // Introduce scope for the AutoSECMODListReadLock.
1921
0
    AutoSECMODListReadLock lock;
1922
0
    for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
1923
0
         list = list->next) {
1924
0
      nsAutoString scalarKey;
1925
0
      GetModuleNameForTelemetry(list->module, scalarKey);
1926
0
      // Scalar keys must be between 0 and 70 characters (exclusive).
1927
0
      // GetModuleNameForTelemetry takes care of keys that are too long. If for
1928
0
      // some reason it couldn't come up with an appropriate name and returned
1929
0
      // an empty result, however, we need to not attempt to record this (it
1930
0
      // wouldn't give us anything useful anyway).
1931
0
      if (scalarKey.Length() > 0) {
1932
0
        Telemetry::ScalarSet(
1933
0
          Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED, scalarKey, true);
1934
0
      }
1935
0
    }
1936
0
  }
1937
0
1938
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
1939
0
1940
0
  {
1941
0
    MutexAutoLock lock(mMutex);
1942
0
1943
0
    // ensure we have initial values for various root hashes
1944
#ifdef DEBUG
1945
    mTestBuiltInRootHash.Truncate();
1946
    Preferences::GetString("security.test.built_in_root_hash",
1947
                           mTestBuiltInRootHash);
1948
#endif
1949
    mContentSigningRootHash.Truncate();
1950
0
    Preferences::GetString("security.content.signature.root_hash",
1951
0
                           mContentSigningRootHash);
1952
0
1953
0
    mMitmCanaryIssuer.Truncate();
1954
0
    Preferences::GetString("security.pki.mitm_canary_issuer",
1955
0
                           mMitmCanaryIssuer);
1956
0
    mMitmDetecionEnabled =
1957
0
      Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true);
1958
0
1959
0
    // Set dynamic options from prefs. This has to run after
1960
0
    // SSL_ConfigServerSessionIDCache.
1961
0
    setValidationOptions(true, lock);
1962
0
1963
0
    bool importEnterpriseRoots = Preferences::GetBool(kEnterpriseRootModePref,
1964
0
                                                      false);
1965
0
    uint32_t familySafetyMode = Preferences::GetUint(kFamilySafetyModePref,
1966
0
                                                     kFamilySafetyModeDefault);
1967
0
    RefPtr<LoadLoadableRootsTask> loadLoadableRootsTask(
1968
0
      new LoadLoadableRootsTask(this, importEnterpriseRoots, familySafetyMode));
1969
0
    rv = loadLoadableRootsTask->Dispatch();
1970
0
    if (NS_FAILED(rv)) {
1971
0
      return rv;
1972
0
    }
1973
0
1974
0
    mLoadLoadableRootsTaskDispatched = true;
1975
0
    return NS_OK;
1976
0
  }
1977
0
}
1978
1979
void
1980
nsNSSComponent::ShutdownNSS()
1981
0
{
1982
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ShutdownNSS\n"));
1983
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
1984
0
1985
0
  bool loadLoadableRootsTaskDispatched;
1986
0
  {
1987
0
    MutexAutoLock lock(mMutex);
1988
0
    loadLoadableRootsTaskDispatched = mLoadLoadableRootsTaskDispatched;
1989
0
  }
1990
0
  // We have to block until the load loadable roots task has completed, because
1991
0
  // otherwise we might try to unload the loadable roots while the loadable
1992
0
  // roots loading thread is setting up EV information, which can cause
1993
0
  // it to fail to find the roots it is expecting. However, if initialization
1994
0
  // failed, we won't have dispatched the load loadable roots background task.
1995
0
  // In that case, we don't want to block on an event that will never happen.
1996
0
  if (loadLoadableRootsTaskDispatched) {
1997
0
    Unused << BlockUntilLoadableRootsLoaded();
1998
0
  }
1999
0
2000
0
  ::mozilla::psm::UnloadLoadableRoots();
2001
0
2002
0
  MutexAutoLock lock(mMutex);
2003
#ifdef XP_WIN
2004
  mFamilySafetyRoot = nullptr;
2005
  mEnterpriseRoots = nullptr;
2006
#endif
2007
2008
0
  PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);
2009
0
2010
0
  Preferences::RemoveObserver(this, "security.");
2011
0
2012
0
  // Release the default CertVerifier. This will cause any held NSS resources
2013
0
  // to be released.
2014
0
  mDefaultCertVerifier = nullptr;
2015
0
  // We don't actually shut down NSS - XPCOM does, after all threads have been
2016
0
  // joined and the component manager has been shut down (and so there shouldn't
2017
0
  // be any XPCOM objects holding NSS resources).
2018
0
}
2019
2020
nsresult
2021
nsNSSComponent::Init()
2022
0
{
2023
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
2024
0
  if (!NS_IsMainThread()) {
2025
0
    return NS_ERROR_NOT_SAME_THREAD;
2026
0
  }
2027
0
2028
0
  MOZ_ASSERT(XRE_IsParentProcess());
2029
0
  if (!XRE_IsParentProcess()) {
2030
0
    return NS_ERROR_NOT_AVAILABLE;
2031
0
  }
2032
0
2033
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));
2034
0
2035
0
  nsresult rv = InitializeNSS();
2036
0
  if (NS_FAILED(rv)) {
2037
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
2038
0
            ("nsNSSComponent::InitializeNSS() failed\n"));
2039
0
    return rv;
2040
0
  }
2041
0
2042
0
  RememberCertErrorsTable::Init();
2043
0
2044
0
  return RegisterObservers();
2045
0
}
2046
2047
// nsISupports Implementation for the class
2048
NS_IMPL_ISUPPORTS(nsNSSComponent,
2049
                  nsINSSComponent,
2050
                  nsIObserver)
2051
2052
static const char* const PROFILE_BEFORE_CHANGE_TOPIC = "profile-before-change";
2053
2054
NS_IMETHODIMP
2055
nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
2056
                        const char16_t* someData)
2057
0
{
2058
0
  // In some tests, we don't receive a "profile-before-change" topic. However,
2059
0
  // we still have to shut down before the storage service shuts down, because
2060
0
  // closing the sql-backed softoken requires sqlite still be available. Thus,
2061
0
  // we observe "xpcom-shutdown" just in case.
2062
0
  if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0 ||
2063
0
      nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
2064
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2065
0
            ("receiving profile change or XPCOM shutdown notification"));
2066
0
    ShutdownNSS();
2067
0
  } else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
2068
0
    bool clearSessionCache = true;
2069
0
    NS_ConvertUTF16toUTF8  prefName(someData);
2070
0
2071
0
    if (prefName.EqualsLiteral("security.tls.version.min") ||
2072
0
        prefName.EqualsLiteral("security.tls.version.max")) {
2073
0
      (void) setEnabledTLSVersions();
2074
0
    } else if (prefName.EqualsLiteral("security.tls.hello_downgrade_check")) {
2075
0
      bool enableDowngradeCheck =
2076
0
        Preferences::GetBool("security.tls.hello_downgrade_check",
2077
0
                             HELLO_DOWNGRADE_CHECK_DEFAULT);
2078
0
      SSL_OptionSetDefault(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, enableDowngradeCheck);
2079
0
    } else if (prefName.EqualsLiteral("security.ssl.require_safe_negotiation")) {
2080
0
      bool requireSafeNegotiation =
2081
0
        Preferences::GetBool("security.ssl.require_safe_negotiation",
2082
0
                             REQUIRE_SAFE_NEGOTIATION_DEFAULT);
2083
0
      SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
2084
0
    } else if (prefName.EqualsLiteral("security.ssl.enable_false_start")) {
2085
0
      SSL_OptionSetDefault(SSL_ENABLE_FALSE_START,
2086
0
                           Preferences::GetBool("security.ssl.enable_false_start",
2087
0
                                                FALSE_START_ENABLED_DEFAULT));
2088
0
    } else if (prefName.EqualsLiteral("security.ssl.enable_alpn")) {
2089
0
      SSL_OptionSetDefault(SSL_ENABLE_ALPN,
2090
0
                           Preferences::GetBool("security.ssl.enable_alpn",
2091
0
                                                ALPN_ENABLED_DEFAULT));
2092
0
    } else if (prefName.EqualsLiteral("security.tls.enable_0rtt_data")) {
2093
0
      SSL_OptionSetDefault(SSL_ENABLE_0RTT_DATA,
2094
0
                           Preferences::GetBool("security.tls.enable_0rtt_data",
2095
0
                                                ENABLED_0RTT_DATA_DEFAULT));
2096
0
    } else if (prefName.EqualsLiteral("security.ssl.disable_session_identifiers")) {
2097
0
      ConfigureTLSSessionIdentifiers();
2098
0
    } else if (prefName.EqualsLiteral("security.OCSP.enabled") ||
2099
0
               prefName.EqualsLiteral("security.OCSP.require") ||
2100
0
               prefName.EqualsLiteral("security.pki.cert_short_lifetime_in_days") ||
2101
0
               prefName.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
2102
0
               prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
2103
0
               prefName.EqualsLiteral("security.pki.certificate_transparency.mode") ||
2104
0
               prefName.EqualsLiteral("security.cert_pinning.enforcement_level") ||
2105
0
               prefName.EqualsLiteral("security.pki.sha1_enforcement_level") ||
2106
0
               prefName.EqualsLiteral("security.pki.name_matching_mode") ||
2107
0
               prefName.EqualsLiteral("security.pki.netscape_step_up_policy") ||
2108
0
               prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.soft") ||
2109
0
               prefName.EqualsLiteral("security.OCSP.timeoutMilliseconds.hard") ||
2110
0
               prefName.EqualsLiteral("security.pki.distrust_ca_policy")) {
2111
0
      MutexAutoLock lock(mMutex);
2112
0
      setValidationOptions(false, lock);
2113
#ifdef DEBUG
2114
    } else if (prefName.EqualsLiteral("security.test.built_in_root_hash")) {
2115
      MutexAutoLock lock(mMutex);
2116
      mTestBuiltInRootHash.Truncate();
2117
      Preferences::GetString("security.test.built_in_root_hash",
2118
                             mTestBuiltInRootHash);
2119
#endif // DEBUG
2120
0
    } else if (prefName.Equals(kFamilySafetyModePref)) {
2121
0
      // When the pref changes, it is safe to change the trust of 3rd party
2122
0
      // roots in the same event tick that they're loaded.
2123
0
      UnloadFamilySafetyRoot();
2124
0
      uint32_t familySafetyMode = Preferences::GetUint(
2125
0
        kFamilySafetyModePref, kFamilySafetyModeDefault);
2126
0
      MaybeEnableFamilySafetyCompatibility(familySafetyMode);
2127
0
      TrustLoaded3rdPartyRoots();
2128
0
    } else if (prefName.EqualsLiteral("security.content.signature.root_hash")) {
2129
0
      MutexAutoLock lock(mMutex);
2130
0
      mContentSigningRootHash.Truncate();
2131
0
      Preferences::GetString("security.content.signature.root_hash",
2132
0
                             mContentSigningRootHash);
2133
0
    } else if (prefName.Equals(kEnterpriseRootModePref)) {
2134
0
      // When the pref changes, it is safe to change the trust of 3rd party
2135
0
      // roots in the same event tick that they're loaded.
2136
0
      UnloadEnterpriseRoots();
2137
0
      MaybeImportEnterpriseRoots();
2138
0
      TrustLoaded3rdPartyRoots();
2139
0
    } else if (prefName.EqualsLiteral("security.pki.mitm_canary_issuer")) {
2140
0
      MutexAutoLock lock(mMutex);
2141
0
      mMitmCanaryIssuer.Truncate();
2142
0
      Preferences::GetString("security.pki.mitm_canary_issuer",
2143
0
                             mMitmCanaryIssuer);
2144
0
    } else if (prefName.EqualsLiteral(
2145
0
                 "security.pki.mitm_canary_issuer.enabled")) {
2146
0
      MutexAutoLock lock(mMutex);
2147
0
      mMitmDetecionEnabled =
2148
0
        Preferences::GetBool("security.pki.mitm_canary_issuer.enabled", true);
2149
0
    } else {
2150
0
      clearSessionCache = false;
2151
0
    }
2152
0
    if (clearSessionCache)
2153
0
      SSL_ClearSessionCache();
2154
0
  }
2155
0
2156
0
  return NS_OK;
2157
0
}
2158
2159
/*static*/ nsresult
2160
nsNSSComponent::GetNewPrompter(nsIPrompt** result)
2161
0
{
2162
0
  NS_ENSURE_ARG_POINTER(result);
2163
0
  *result = nullptr;
2164
0
2165
0
  if (!NS_IsMainThread()) {
2166
0
    NS_ERROR("nsSDRContext::GetNewPrompter called off the main thread");
2167
0
    return NS_ERROR_NOT_SAME_THREAD;
2168
0
  }
2169
0
2170
0
  nsresult rv;
2171
0
  nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
2172
0
  NS_ENSURE_SUCCESS(rv, rv);
2173
0
2174
0
  rv = wwatch->GetNewPrompter(0, result);
2175
0
  NS_ENSURE_SUCCESS(rv, rv);
2176
0
2177
0
  return rv;
2178
0
}
2179
2180
nsresult nsNSSComponent::LogoutAuthenticatedPK11()
2181
0
{
2182
0
  nsCOMPtr<nsICertOverrideService> icos =
2183
0
    do_GetService("@mozilla.org/security/certoverride;1");
2184
0
  if (icos) {
2185
0
    icos->ClearValidityOverride(
2186
0
            NS_LITERAL_CSTRING("all:temporary-certificates"),
2187
0
            0);
2188
0
  }
2189
0
2190
0
  nsClientAuthRememberService::ClearAllRememberedDecisions();
2191
0
2192
0
  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
2193
0
  if (os) {
2194
0
    os->NotifyObservers(nullptr, "net:cancel-all-connections", nullptr);
2195
0
  }
2196
0
2197
0
  return NS_OK;
2198
0
}
2199
2200
nsresult
2201
nsNSSComponent::RegisterObservers()
2202
0
{
2203
0
  nsCOMPtr<nsIObserverService> observerService(
2204
0
    do_GetService("@mozilla.org/observer-service;1"));
2205
0
  if (!observerService) {
2206
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2207
0
            ("nsNSSComponent: couldn't get observer service\n"));
2208
0
    return NS_ERROR_FAILURE;
2209
0
  }
2210
0
2211
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent: adding observers\n"));
2212
0
  // Using false for the ownsweak parameter means the observer service will
2213
0
  // keep a strong reference to this component. As a result, this will live at
2214
0
  // least as long as the observer service.
2215
0
  observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
2216
0
  observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
2217
0
2218
0
  return NS_OK;
2219
0
}
2220
2221
NS_IMETHODIMP
2222
nsNSSComponent::IsCertTestBuiltInRoot(CERTCertificate* cert, bool* result)
2223
0
{
2224
0
  NS_ENSURE_ARG_POINTER(cert);
2225
0
  NS_ENSURE_ARG_POINTER(result);
2226
0
  *result = false;
2227
0
2228
#ifdef DEBUG
2229
  RefPtr<nsNSSCertificate> nsc = nsNSSCertificate::Create(cert);
2230
  if (!nsc) {
2231
    return NS_ERROR_FAILURE;
2232
  }
2233
  nsAutoString certHash;
2234
  nsresult rv = nsc->GetSha256Fingerprint(certHash);
2235
  if (NS_FAILED(rv)) {
2236
    return rv;
2237
  }
2238
2239
  MutexAutoLock lock(mMutex);
2240
  if (mTestBuiltInRootHash.IsEmpty()) {
2241
    return NS_OK;
2242
  }
2243
2244
  *result = mTestBuiltInRootHash.Equals(certHash);
2245
#endif // DEBUG
2246
2247
0
  return NS_OK;
2248
0
}
2249
2250
NS_IMETHODIMP
2251
nsNSSComponent::IsCertContentSigningRoot(CERTCertificate* cert, bool* result)
2252
0
{
2253
0
  NS_ENSURE_ARG_POINTER(result);
2254
0
  *result = false;
2255
0
2256
0
  RefPtr<nsNSSCertificate> nsc = nsNSSCertificate::Create(cert);
2257
0
  if (!nsc) {
2258
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("creating nsNSSCertificate failed"));
2259
0
    return NS_ERROR_FAILURE;
2260
0
  }
2261
0
  nsAutoString certHash;
2262
0
  nsresult rv = nsc->GetSha256Fingerprint(certHash);
2263
0
  if (NS_FAILED(rv)) {
2264
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("getting cert fingerprint failed"));
2265
0
    return rv;
2266
0
  }
2267
0
2268
0
  MutexAutoLock lock(mMutex);
2269
0
2270
0
  if (mContentSigningRootHash.IsEmpty()) {
2271
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("mContentSigningRootHash is empty"));
2272
0
    return NS_ERROR_FAILURE;
2273
0
  }
2274
0
2275
0
  *result = mContentSigningRootHash.Equals(certHash);
2276
0
  return NS_OK;
2277
0
}
2278
2279
NS_IMETHODIMP
2280
nsNSSComponent::IssuerMatchesMitmCanary(const char* aCertIssuer)
2281
0
{
2282
0
  MutexAutoLock lock(mMutex);
2283
0
  if (mMitmDetecionEnabled && !mMitmCanaryIssuer.IsEmpty()) {
2284
0
    nsString certIssuer = NS_ConvertUTF8toUTF16(aCertIssuer);
2285
0
    if (mMitmCanaryIssuer.Equals(certIssuer)) {
2286
0
      return NS_OK;
2287
0
    }
2288
0
  }
2289
0
2290
0
  return NS_ERROR_FAILURE;
2291
0
}
2292
2293
0
SharedCertVerifier::~SharedCertVerifier() { }
2294
2295
NS_IMETHODIMP
2296
nsNSSComponent::GetDefaultCertVerifier(SharedCertVerifier** result)
2297
0
{
2298
0
  MutexAutoLock lock(mMutex);
2299
0
  NS_ENSURE_ARG_POINTER(result);
2300
0
  RefPtr<SharedCertVerifier> certVerifier(mDefaultCertVerifier);
2301
0
  certVerifier.forget(result);
2302
0
  return NS_OK;
2303
0
}
2304
2305
namespace mozilla { namespace psm {
2306
2307
already_AddRefed<SharedCertVerifier>
2308
GetDefaultCertVerifier()
2309
0
{
2310
0
  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
2311
0
2312
0
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID));
2313
0
  if (!nssComponent) {
2314
0
    return nullptr;
2315
0
  }
2316
0
  RefPtr<SharedCertVerifier> result;
2317
0
  nsresult rv = nssComponent->GetDefaultCertVerifier(getter_AddRefs(result));
2318
0
  if (NS_FAILED(rv)) {
2319
0
    return nullptr;
2320
0
  }
2321
0
  return result.forget();
2322
0
}
2323
2324
} } // namespace mozilla::psm
2325
2326
NS_IMPL_ISUPPORTS(PipUIContext, nsIInterfaceRequestor)
2327
2328
PipUIContext::PipUIContext()
2329
0
{
2330
0
}
2331
2332
PipUIContext::~PipUIContext()
2333
0
{
2334
0
}
2335
2336
NS_IMETHODIMP
2337
PipUIContext::GetInterface(const nsIID& uuid, void** result)
2338
0
{
2339
0
  NS_ENSURE_ARG_POINTER(result);
2340
0
  *result = nullptr;
2341
0
2342
0
  if (!NS_IsMainThread()) {
2343
0
    NS_ERROR("PipUIContext::GetInterface called off the main thread");
2344
0
    return NS_ERROR_NOT_SAME_THREAD;
2345
0
  }
2346
0
2347
0
  if (!uuid.Equals(NS_GET_IID(nsIPrompt)))
2348
0
    return NS_ERROR_NO_INTERFACE;
2349
0
2350
0
  nsIPrompt* prompt = nullptr;
2351
0
  nsresult rv = nsNSSComponent::GetNewPrompter(&prompt);
2352
0
  *result = prompt;
2353
0
  return rv;
2354
0
}
2355
2356
nsresult
2357
getNSSDialogs(void** _result, REFNSIID aIID, const char* contract)
2358
0
{
2359
0
  if (!NS_IsMainThread()) {
2360
0
    NS_ERROR("getNSSDialogs called off the main thread");
2361
0
    return NS_ERROR_NOT_SAME_THREAD;
2362
0
  }
2363
0
2364
0
  nsresult rv;
2365
0
2366
0
  nsCOMPtr<nsISupports> svc = do_GetService(contract, &rv);
2367
0
  if (NS_FAILED(rv)) {
2368
0
    return rv;
2369
0
  }
2370
0
2371
0
  rv = svc->QueryInterface(aIID, _result);
2372
0
2373
0
  return rv;
2374
0
}
2375
2376
nsresult
2377
setPassword(PK11SlotInfo* slot, nsIInterfaceRequestor* ctx)
2378
0
{
2379
0
  MOZ_ASSERT(slot);
2380
0
  MOZ_ASSERT(ctx);
2381
0
  NS_ENSURE_ARG_POINTER(slot);
2382
0
  NS_ENSURE_ARG_POINTER(ctx);
2383
0
2384
0
  if (PK11_NeedUserInit(slot)) {
2385
0
    nsCOMPtr<nsITokenPasswordDialogs> dialogs;
2386
0
    nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
2387
0
                                NS_GET_IID(nsITokenPasswordDialogs),
2388
0
                                NS_TOKENPASSWORDSDIALOG_CONTRACTID);
2389
0
    if (NS_FAILED(rv)) {
2390
0
      return rv;
2391
0
    }
2392
0
2393
0
    bool canceled;
2394
0
    nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot);
2395
0
    rv = dialogs->SetPassword(ctx, token, &canceled);
2396
0
    if (NS_FAILED(rv)) {
2397
0
      return rv;
2398
0
    }
2399
0
2400
0
    if (canceled) {
2401
0
      return NS_ERROR_NOT_AVAILABLE;
2402
0
    }
2403
0
  }
2404
0
2405
0
  return NS_OK;
2406
0
}
2407
2408
// NSS will call this during PKCS12 export to potentially switch the endianness
2409
// of the characters of `inBuf` to big (network) endian. Since we already did
2410
// that in nsPKCS12Blob::stringToBigEndianBytes, we just perform a memcpy here.
2411
extern "C" {
2412
PRBool
2413
pkcs12StringEndiannessConversion(PRBool, unsigned char* inBuf,
2414
                                 unsigned int inBufLen, unsigned char* outBuf,
2415
                                 unsigned int, unsigned int* outBufLen, PRBool)
2416
0
{
2417
0
  *outBufLen = inBufLen;
2418
0
  memcpy(outBuf, inBuf, inBufLen);
2419
0
  return true;
2420
0
}
2421
}
2422
2423
namespace mozilla {
2424
namespace psm {
2425
2426
nsresult
2427
InitializeCipherSuite()
2428
0
{
2429
0
  MOZ_ASSERT(NS_IsMainThread(),
2430
0
             "InitializeCipherSuite() can only be accessed on the main thread");
2431
0
2432
0
  if (NSS_SetDomesticPolicy() != SECSuccess) {
2433
0
    return NS_ERROR_FAILURE;
2434
0
  }
2435
0
2436
0
  // Disable any ciphers that NSS might have enabled by default
2437
0
  for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
2438
0
    uint16_t cipher_id = SSL_ImplementedCiphers[i];
2439
0
    SSL_CipherPrefSetDefault(cipher_id, false);
2440
0
  }
2441
0
2442
0
  // Now only set SSL/TLS ciphers we knew about at compile time
2443
0
  const CipherPref* const cp = sCipherPrefs;
2444
0
  for (size_t i = 0; cp[i].pref; ++i) {
2445
0
    bool cipherEnabled = Preferences::GetBool(cp[i].pref,
2446
0
                                              cp[i].enabledByDefault);
2447
0
    SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
2448
0
  }
2449
0
2450
0
  // Enable ciphers for PKCS#12
2451
0
  SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
2452
0
  SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
2453
0
  SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
2454
0
  SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
2455
0
  SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
2456
0
  SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
2457
0
  SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
2458
0
  PORT_SetUCS2_ASCIIConversionFunction(pkcs12StringEndiannessConversion);
2459
0
2460
0
  // PSM enforces a minimum RSA key size of 1024 bits, which is overridable.
2461
0
  // NSS has its own minimum, which is not overridable (the default is 1023
2462
0
  // bits). This sets the NSS minimum to 512 bits so users can still connect to
2463
0
  // devices like wifi routers with woefully small keys (they would have to add
2464
0
  // an override to do so, but they already do for such devices).
2465
0
  NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 512);
2466
0
2467
0
  // Observe preference change around cipher suite setting.
2468
0
  return CipherSuiteChangeObserver::StartObserve();
2469
0
}
2470
2471
} // namespace psm
2472
} // namespace mozilla