Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/SecretDecoderRing.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 "SecretDecoderRing.h"
8
9
#include "ScopedNSSTypes.h"
10
#include "mozilla/Base64.h"
11
#include "mozilla/Casting.h"
12
#include "mozilla/Services.h"
13
#include "mozilla/ErrorResult.h"
14
#include "mozilla/dom/Promise.h"
15
#include "nsCOMPtr.h"
16
#include "nsIInterfaceRequestor.h"
17
#include "nsIInterfaceRequestorUtils.h"
18
#include "nsIObserverService.h"
19
#include "nsIServiceManager.h"
20
#include "nsITokenPasswordDialogs.h"
21
#include "nsNSSComponent.h"
22
#include "nsNSSHelper.h"
23
#include "nsPK11TokenDB.h"
24
#include "pk11func.h"
25
#include "pk11sdr.h" // For PK11SDR_Encrypt, PK11SDR_Decrypt
26
#include "ssl.h" // For SSL_ClearSessionCache
27
28
using namespace mozilla;
29
using dom::Promise;
30
31
NS_IMPL_ISUPPORTS(SecretDecoderRing, nsISecretDecoderRing)
32
33
void BackgroundSdrEncryptStrings(const nsTArray<nsCString>& plaintexts,
34
0
                                 RefPtr<Promise>& aPromise) {
35
0
  nsCOMPtr<nsISecretDecoderRing> sdrService =
36
0
    do_GetService(NS_SECRETDECODERRING_CONTRACTID);
37
0
  InfallibleTArray<nsString> cipherTexts(plaintexts.Length());
38
0
39
0
  nsresult rv = NS_ERROR_FAILURE;
40
0
  for (uint32_t i = 0; i < plaintexts.Length(); ++i) {
41
0
    const nsCString& plaintext = plaintexts[i];
42
0
    nsCString cipherText;
43
0
    rv = sdrService->EncryptString(plaintext, cipherText);
44
0
45
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
46
0
      break;
47
0
    }
48
0
49
0
    cipherTexts.AppendElement(NS_ConvertASCIItoUTF16(cipherText));
50
0
  }
51
0
52
0
  nsCOMPtr<nsIRunnable> runnable(
53
0
    NS_NewRunnableFunction("BackgroundSdrEncryptStringsResolve",
54
0
                           [rv, aPromise = std::move(aPromise), cipherTexts = std::move(cipherTexts)]() {
55
0
                             if (NS_FAILED(rv)) {
56
0
                               aPromise->MaybeReject(rv);
57
0
                             } else {
58
0
                               aPromise->MaybeResolve(cipherTexts);
59
0
                             }
60
0
                           }));
61
0
  NS_DispatchToMainThread(runnable.forget());
62
0
}
63
64
nsresult
65
SecretDecoderRing::Encrypt(const nsACString& data, /*out*/ nsACString& result)
66
0
{
67
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
68
0
  if (!slot) {
69
0
    return NS_ERROR_NOT_AVAILABLE;
70
0
  }
71
0
72
0
  /* Make sure token is initialized. */
73
0
  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
74
0
  nsresult rv = setPassword(slot.get(), ctx);
75
0
  if (NS_FAILED(rv)) {
76
0
    return rv;
77
0
  }
78
0
79
0
  /* Force authentication */
80
0
  if (PK11_Authenticate(slot.get(), true, ctx) != SECSuccess) {
81
0
    return NS_ERROR_FAILURE;
82
0
  }
83
0
84
0
  /* Use default key id */
85
0
  SECItem keyid;
86
0
  keyid.data = nullptr;
87
0
  keyid.len = 0;
88
0
  SECItem request;
89
0
  request.data = BitwiseCast<unsigned char*, const char*>(data.BeginReading());
90
0
  request.len = data.Length();
91
0
  ScopedAutoSECItem reply;
92
0
  if (PK11SDR_Encrypt(&keyid, &request, &reply, ctx) != SECSuccess) {
93
0
    return NS_ERROR_FAILURE;
94
0
  }
95
0
96
0
  result.Assign(BitwiseCast<char*, unsigned char*>(reply.data), reply.len);
97
0
  return NS_OK;
98
0
}
99
100
nsresult
101
SecretDecoderRing::Decrypt(const nsACString& data, /*out*/ nsACString& result)
102
0
{
103
0
  /* Find token with SDR key */
104
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
105
0
  if (!slot) {
106
0
    return NS_ERROR_NOT_AVAILABLE;
107
0
  }
108
0
109
0
  /* Force authentication */
110
0
  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
111
0
  if (PK11_Authenticate(slot.get(), true, ctx) != SECSuccess) {
112
0
    return NS_ERROR_NOT_AVAILABLE;
113
0
  }
114
0
115
0
  SECItem request;
116
0
  request.data = BitwiseCast<unsigned char*, const char*>(data.BeginReading());
117
0
  request.len = data.Length();
118
0
  ScopedAutoSECItem reply;
119
0
  if (PK11SDR_Decrypt(&request, &reply, ctx) != SECSuccess) {
120
0
    return NS_ERROR_FAILURE;
121
0
  }
122
0
123
0
  result.Assign(BitwiseCast<char*, unsigned char*>(reply.data), reply.len);
124
0
  return NS_OK;
125
0
}
126
127
NS_IMETHODIMP
128
SecretDecoderRing::EncryptString(const nsACString& text,
129
                         /*out*/ nsACString& encryptedBase64Text)
130
0
{
131
0
  nsAutoCString encryptedText;
132
0
  nsresult rv = Encrypt(text, encryptedText);
133
0
  if (NS_FAILED(rv)) {
134
0
    return rv;
135
0
  }
136
0
137
0
  rv = Base64Encode(encryptedText, encryptedBase64Text);
138
0
  if (NS_FAILED(rv)) {
139
0
    return rv;
140
0
  }
141
0
142
0
  return NS_OK;
143
0
}
144
145
NS_IMETHODIMP
146
SecretDecoderRing::AsyncEncryptStrings(uint32_t plaintextsCount,
147
                                       const char16_t** plaintexts,
148
                                       JSContext* aCx,
149
0
                                       Promise** aPromise) {
150
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
151
0
  NS_ENSURE_ARG(plaintextsCount);
152
0
  NS_ENSURE_ARG_POINTER(plaintexts);
153
0
  NS_ENSURE_ARG_POINTER(aCx);
154
0
155
0
  nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
156
0
  if (NS_WARN_IF(!globalObject)) {
157
0
    return NS_ERROR_UNEXPECTED;
158
0
  }
159
0
160
0
  ErrorResult result;
161
0
  RefPtr<Promise> promise = Promise::Create(globalObject, result);
162
0
  if (NS_WARN_IF(result.Failed())) {
163
0
    return result.StealNSResult();
164
0
  }
165
0
166
0
  InfallibleTArray<nsCString> plaintextsUtf8(plaintextsCount);
167
0
  for (uint32_t i = 0; i < plaintextsCount; ++i) {
168
0
    plaintextsUtf8.AppendElement(NS_ConvertUTF16toUTF8(plaintexts[i]));
169
0
  }
170
0
  nsCOMPtr<nsIRunnable> runnable(
171
0
    NS_NewRunnableFunction("BackgroundSdrEncryptStrings",
172
0
      [promise, plaintextsUtf8 = std::move(plaintextsUtf8)]() mutable {
173
0
        BackgroundSdrEncryptStrings(plaintextsUtf8, promise);
174
0
      }));
175
0
176
0
  nsCOMPtr<nsIThread> encryptionThread;
177
0
  nsresult rv = NS_NewNamedThread("AsyncSDRThread",
178
0
                                  getter_AddRefs(encryptionThread),
179
0
                                  runnable);
180
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
181
0
    return rv;
182
0
  }
183
0
184
0
  promise.forget(aPromise);
185
0
  return NS_OK;
186
0
}
187
188
NS_IMETHODIMP
189
SecretDecoderRing::DecryptString(const nsACString& encryptedBase64Text,
190
                         /*out*/ nsACString& decryptedText)
191
0
{
192
0
  nsAutoCString encryptedText;
193
0
  nsresult rv = Base64Decode(encryptedBase64Text, encryptedText);
194
0
  if (NS_FAILED(rv)) {
195
0
    return rv;
196
0
  }
197
0
198
0
  rv = Decrypt(encryptedText, decryptedText);
199
0
  if (NS_FAILED(rv)) {
200
0
    return rv;
201
0
  }
202
0
203
0
  return NS_OK;
204
0
}
205
206
NS_IMETHODIMP
207
SecretDecoderRing::ChangePassword()
208
0
{
209
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
210
0
  if (!slot) {
211
0
    return NS_ERROR_NOT_AVAILABLE;
212
0
  }
213
0
214
0
  // nsPK11Token::nsPK11Token takes its own reference to slot, so we pass a
215
0
  // non-owning pointer here.
216
0
  nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot.get());
217
0
218
0
  nsCOMPtr<nsITokenPasswordDialogs> dialogs;
219
0
  nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
220
0
                              NS_GET_IID(nsITokenPasswordDialogs),
221
0
                              NS_TOKENPASSWORDSDIALOG_CONTRACTID);
222
0
  if (NS_FAILED(rv)) {
223
0
    return rv;
224
0
  }
225
0
226
0
  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
227
0
  bool canceled; // Ignored
228
0
  return dialogs->SetPassword(ctx, token, &canceled);
229
0
}
230
231
NS_IMETHODIMP
232
SecretDecoderRing::Logout()
233
0
{
234
0
  PK11_LogoutAll();
235
0
  SSL_ClearSessionCache();
236
0
  return NS_OK;
237
0
}
238
239
NS_IMETHODIMP
240
SecretDecoderRing::LogoutAndTeardown()
241
0
{
242
0
  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
243
0
244
0
  PK11_LogoutAll();
245
0
  SSL_ClearSessionCache();
246
0
247
0
  nsresult rv;
248
0
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
249
0
  if (NS_FAILED(rv)) {
250
0
    return rv;
251
0
  }
252
0
253
0
  rv = nssComponent->LogoutAuthenticatedPK11();
254
0
255
0
  // After we just logged out, we need to prune dead connections to make
256
0
  // sure that all connections that should be stopped, are stopped. See
257
0
  // bug 517584.
258
0
  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
259
0
  if (os) {
260
0
    os->NotifyObservers(nullptr, "net:prune-dead-connections", nullptr);
261
0
  }
262
0
263
0
  return rv;
264
0
}