Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/OSKeyStore.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 "OSKeyStore.h"
8
9
#include "mozilla/Base64.h"
10
#include "mozilla/dom/Promise.h"
11
#include "nsIRandomGenerator.h"
12
#include "pk11pub.h"
13
14
#ifdef MOZ_LIB_SECRET
15
#include "LibSecret.h"
16
#elif defined(XP_MACOSX)
17
#include "KeychainSecret.h"
18
#elif defined(XP_WIN)
19
#include "CredentialManagerSecret.h"
20
#else
21
#include "NSSKeyStore.h"
22
#endif
23
24
NS_IMPL_ISUPPORTS(OSKeyStore, nsIOSKeyStore)
25
26
using namespace mozilla;
27
using dom::Promise;
28
29
mozilla::LazyLogModule gOSKeyStoreLog("oskeystore");
30
31
OSKeyStore::OSKeyStore()
32
  : mMutex("OSKeyStore-mutex")
33
0
{
34
#ifdef MOZ_LIB_SECRET
35
  mKs.reset(new LibSecret());
36
#elif defined(XP_MACOSX)
37
  mKs.reset(new KeychainSecret());
38
#elif defined(XP_WIN)
39
  mKs.reset(new CredentialManagerSecret());
40
#else
41
  mKs.reset(new NSSKeyStore());
42
0
#endif
43
0
}
44
0
OSKeyStore::~OSKeyStore() {}
45
46
static nsresult
47
GenerateRandom(std::vector<uint8_t>& r)
48
0
{
49
0
  if (r.size() < 1) {
50
0
    return NS_ERROR_INVALID_ARG;
51
0
  }
52
0
  UniquePK11SlotInfo slot(PK11_GetInternalSlot());
53
0
  if (!slot) {
54
0
    return NS_ERROR_FAILURE;
55
0
  }
56
0
57
0
  SECStatus srv = PK11_GenerateRandomOnSlot(slot.get(), r.data(), r.size());
58
0
  if (srv != SECSuccess) {
59
0
    r.clear();
60
0
    return NS_ERROR_FAILURE;
61
0
  }
62
0
63
0
  return NS_OK;
64
0
}
65
66
nsresult
67
OSKeyStore::SecretAvailable(const nsACString& aLabel,
68
                            /* out */ bool* aAvailable)
69
0
{
70
0
  MutexAutoLock lock(mMutex);
71
0
  NS_ENSURE_STATE(mKs);
72
0
  nsAutoCString label = mLabelPrefix + aLabel;
73
0
  *aAvailable = mKs->SecretAvailable(label);
74
0
  return NS_OK;
75
0
}
76
77
nsresult
78
OSKeyStore::GenerateSecret(const nsACString& aLabel,
79
                           /* out */ nsACString& aRecoveryPhrase)
80
0
{
81
0
  MutexAutoLock lock(mMutex);
82
0
  NS_ENSURE_STATE(mKs);
83
0
  size_t keyByteLength = mKs->GetKeyByteLength();
84
0
  std::vector<uint8_t> secret(keyByteLength);
85
0
  nsresult rv = GenerateRandom(secret);
86
0
  if (NS_FAILED(rv) || secret.size() != keyByteLength) {
87
0
    return NS_ERROR_FAILURE;
88
0
  }
89
0
  nsAutoCString secretString;
90
0
  secretString.Assign(BitwiseCast<char*, uint8_t*>(secret.data()),
91
0
                      secret.size());
92
0
93
0
  nsAutoCString base64;
94
0
  rv = Base64Encode(secretString, base64);
95
0
  if (NS_FAILED(rv)) {
96
0
    return rv;
97
0
  }
98
0
99
0
  nsAutoCString label = mLabelPrefix + aLabel;
100
0
  rv = mKs->StoreSecret(secretString, label);
101
0
  if (NS_FAILED(rv)) {
102
0
    return rv;
103
0
  }
104
0
105
0
  aRecoveryPhrase = base64;
106
0
  return NS_OK;
107
0
}
108
109
nsresult
110
OSKeyStore::RecoverSecret(const nsACString& aLabel,
111
                          const nsACString& aRecoveryPhrase)
112
0
{
113
0
  MutexAutoLock lock(mMutex);
114
0
  NS_ENSURE_STATE(mKs);
115
0
  nsAutoCString secret;
116
0
  nsresult rv = Base64Decode(aRecoveryPhrase, secret);
117
0
  if (NS_FAILED(rv)) {
118
0
    return rv;
119
0
  }
120
0
  nsAutoCString label = mLabelPrefix + aLabel;
121
0
  rv = mKs->StoreSecret(secret, label);
122
0
  if (NS_FAILED(rv)) {
123
0
    return rv;
124
0
  }
125
0
126
0
  return NS_OK;
127
0
}
128
129
nsresult
130
OSKeyStore::DeleteSecret(const nsACString& aLabel)
131
0
{
132
0
  MutexAutoLock lock(mMutex);
133
0
  NS_ENSURE_STATE(mKs);
134
0
  nsAutoCString label = mLabelPrefix + aLabel;
135
0
  return mKs->DeleteSecret(label);
136
0
}
137
138
enum Cipher
139
{
140
  Encrypt = true,
141
  Decrypt = false
142
};
143
144
nsresult
145
OSKeyStore::EncryptBytes(const nsACString& aLabel,
146
                         uint32_t inLen,
147
                         uint8_t* inBytes,
148
                         /*out*/ nsACString& aEncryptedBase64Text)
149
0
{
150
0
  MutexAutoLock lock(mMutex);
151
0
  NS_ENSURE_STATE(mKs);
152
0
  NS_ENSURE_ARG_POINTER(inBytes);
153
0
154
0
  nsAutoCString label = mLabelPrefix + aLabel;
155
0
  aEncryptedBase64Text.Truncate();
156
0
  const std::vector<uint8_t> in(inBytes, inBytes + inLen);
157
0
  std::vector<uint8_t> outBytes;
158
0
  nsresult rv = mKs->EncryptDecrypt(label, in, outBytes, Cipher::Encrypt);
159
0
  if (NS_FAILED(rv)) {
160
0
    return rv;
161
0
  }
162
0
  nsAutoCString ciphertext;
163
0
  ciphertext.Assign(BitwiseCast<char*, uint8_t*>(outBytes.data()),
164
0
                    outBytes.size());
165
0
166
0
  nsAutoCString base64ciphertext;
167
0
  rv = Base64Encode(ciphertext, base64ciphertext);
168
0
  if (NS_FAILED(rv)) {
169
0
    return rv;
170
0
  }
171
0
  aEncryptedBase64Text.Assign(base64ciphertext);
172
0
  return NS_OK;
173
0
}
174
175
nsresult
176
OSKeyStore::DecryptBytes(const nsACString& aLabel,
177
                         const nsACString& aEncryptedBase64Text,
178
                         /*out*/ uint32_t* outLen,
179
                         /*out*/ uint8_t** outBytes)
180
0
{
181
0
  MutexAutoLock lock(mMutex);
182
0
  NS_ENSURE_STATE(mKs);
183
0
  NS_ENSURE_ARG_POINTER(outLen);
184
0
  NS_ENSURE_ARG_POINTER(outBytes);
185
0
  *outLen = 0;
186
0
  *outBytes = nullptr;
187
0
188
0
  nsAutoCString ciphertext;
189
0
  nsresult rv = Base64Decode(aEncryptedBase64Text, ciphertext);
190
0
  if (NS_FAILED(rv)) {
191
0
    return rv;
192
0
  }
193
0
  nsAutoCString label = mLabelPrefix + aLabel;
194
0
  uint8_t* tmp = BitwiseCast<uint8_t*, const char*>(ciphertext.BeginReading());
195
0
  const std::vector<uint8_t> ciphertextBytes(tmp, tmp + ciphertext.Length());
196
0
  std::vector<uint8_t> plaintextBytes;
197
0
  rv = mKs->EncryptDecrypt(
198
0
    label, ciphertextBytes, plaintextBytes, Cipher::Decrypt);
199
0
  if (NS_FAILED(rv)) {
200
0
    return rv;
201
0
  }
202
0
203
0
  *outBytes = (uint8_t*)moz_xmalloc(plaintextBytes.size());
204
0
  memcpy(*outBytes, plaintextBytes.data(), plaintextBytes.size());
205
0
  *outLen = plaintextBytes.size();
206
0
  return NS_OK;
207
0
}
208
209
nsresult
210
OSKeyStore::Lock()
211
0
{
212
0
  MutexAutoLock lock(mMutex);
213
0
  NS_ENSURE_STATE(mKs);
214
0
  return mKs->Lock();
215
0
}
216
217
nsresult
218
OSKeyStore::Unlock()
219
0
{
220
0
  MutexAutoLock lock(mMutex);
221
0
  NS_ENSURE_STATE(mKs);
222
0
  return mKs->Unlock();
223
0
}
224
225
NS_IMETHODIMP
226
OSKeyStore::GetIsNSSKeyStore(bool* aNSSKeyStore)
227
0
{
228
0
  MutexAutoLock lock(mMutex);
229
0
  NS_ENSURE_ARG_POINTER(aNSSKeyStore);
230
0
  NS_ENSURE_STATE(mKs);
231
0
  *aNSSKeyStore = mKs->IsNSSKeyStore();
232
0
  return NS_OK;
233
0
}
234
235
// Async interfaces that return promises because the key store implementation
236
// might block, e.g. asking for a password.
237
238
static nsresult
239
GetPromise(JSContext* aCx, /* out */ RefPtr<Promise>& aPromise)
240
0
{
241
0
  nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
242
0
  if (NS_WARN_IF(!globalObject)) {
243
0
    return NS_ERROR_UNEXPECTED;
244
0
  }
245
0
  ErrorResult result;
246
0
  aPromise = Promise::Create(globalObject, result);
247
0
  if (NS_WARN_IF(result.Failed())) {
248
0
    return result.StealNSResult();
249
0
  }
250
0
  return NS_OK;
251
0
}
252
253
nsresult
254
OSKeyStore::FinishAsync(RefPtr<Promise>& aPromiseHandle,
255
                        /* out*/ Promise** promiseOut,
256
                        const nsACString& aName,
257
                        nsCOMPtr<nsIRunnable> aRunnable)
258
0
{
259
0
  // Note that if the NSS PK11 token is handling the key store, locking and
260
0
  // unlocking functions will be pushed to the main thread again.
261
0
  nsCOMPtr<nsIThread> thread;
262
0
  nsresult rv = NS_NewNamedThread(aName, getter_AddRefs(thread), aRunnable);
263
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
264
0
    return rv;
265
0
  }
266
0
267
0
  aPromiseHandle.forget(promiseOut);
268
0
  return NS_OK;
269
0
}
270
271
void
272
BackgroundUnlock(RefPtr<Promise>& aPromise, RefPtr<OSKeyStore> self)
273
0
{
274
0
  nsAutoCString recovery;
275
0
  nsresult rv = self->Unlock();
276
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
277
0
    "BackgroundUnlockOSKSResolve", [rv, aPromise = std::move(aPromise)]() {
278
0
      if (NS_FAILED(rv)) {
279
0
        aPromise->MaybeReject(rv);
280
0
      } else {
281
0
        aPromise->MaybeResolveWithUndefined();
282
0
      }
283
0
    }));
284
0
  NS_DispatchToMainThread(runnable.forget());
285
0
}
286
287
NS_IMETHODIMP
288
OSKeyStore::AsyncUnlock(JSContext* aCx, Promise** promiseOut)
289
0
{
290
0
  NS_ENSURE_ARG_POINTER(aCx);
291
0
292
0
  RefPtr<Promise> promiseHandle;
293
0
  nsresult rv = GetPromise(aCx, promiseHandle);
294
0
  if (NS_FAILED(rv)) {
295
0
    return rv;
296
0
  }
297
0
298
0
  RefPtr<OSKeyStore> self = this;
299
0
  nsCOMPtr<nsIRunnable> runnable(
300
0
    NS_NewRunnableFunction("BackgroundUnlock", [self, promiseHandle]() mutable {
301
0
      BackgroundUnlock(promiseHandle, self);
302
0
    }));
303
0
304
0
  return FinishAsync(
305
0
    promiseHandle, promiseOut, NS_LITERAL_CSTRING("UnlockKSThread"), runnable);
306
0
}
307
308
void
309
BackgroundLock(RefPtr<Promise>& aPromise, RefPtr<OSKeyStore> self)
310
0
{
311
0
  nsresult rv = self->Lock();
312
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
313
0
    "BackgroundLockOSKSResolve", [rv, aPromise = std::move(aPromise)]() {
314
0
      if (NS_FAILED(rv)) {
315
0
        aPromise->MaybeReject(rv);
316
0
      } else {
317
0
        aPromise->MaybeResolveWithUndefined();
318
0
      }
319
0
    }));
320
0
  NS_DispatchToMainThread(runnable.forget());
321
0
}
322
323
NS_IMETHODIMP
324
OSKeyStore::AsyncLock(JSContext* aCx, Promise** promiseOut)
325
0
{
326
0
  NS_ENSURE_ARG_POINTER(aCx);
327
0
328
0
  RefPtr<Promise> promiseHandle;
329
0
  nsresult rv = GetPromise(aCx, promiseHandle);
330
0
  if (NS_FAILED(rv)) {
331
0
    return rv;
332
0
  }
333
0
334
0
  RefPtr<OSKeyStore> self = this;
335
0
  nsCOMPtr<nsIRunnable> runnable(
336
0
    NS_NewRunnableFunction("BackgroundLock", [self, promiseHandle]() mutable {
337
0
      BackgroundLock(promiseHandle, self);
338
0
    }));
339
0
340
0
  return FinishAsync(
341
0
    promiseHandle, promiseOut, NS_LITERAL_CSTRING("LockKSThread"), runnable);
342
0
}
343
344
void
345
BackgroundGenerateSecret(const nsACString& aLabel,
346
                         RefPtr<Promise>& aPromise,
347
                         RefPtr<OSKeyStore> self)
348
0
{
349
0
  nsAutoCString recovery;
350
0
  nsresult rv = self->GenerateSecret(aLabel, recovery);
351
0
  nsAutoString recoveryString;
352
0
  if (NS_SUCCEEDED(rv)){
353
0
    CopyUTF8toUTF16(recovery, recoveryString);
354
0
  }
355
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
356
0
    "BackgroundGenerateSecreteOSKSResolve",
357
0
    [rv, aPromise = std::move(aPromise), recoveryString]() {
358
0
      if (NS_FAILED(rv)) {
359
0
        aPromise->MaybeReject(rv);
360
0
      } else {
361
0
        aPromise->MaybeResolve(recoveryString);
362
0
      }
363
0
    }));
364
0
  NS_DispatchToMainThread(runnable.forget());
365
0
}
366
367
NS_IMETHODIMP
368
OSKeyStore::AsyncGenerateSecret(const nsACString& aLabel,
369
                                JSContext* aCx,
370
                                Promise** promiseOut)
371
0
{
372
0
  NS_ENSURE_ARG_POINTER(aCx);
373
0
374
0
  RefPtr<Promise> promiseHandle;
375
0
  nsresult rv = GetPromise(aCx, promiseHandle);
376
0
  if (NS_FAILED(rv)) {
377
0
    return rv;
378
0
  }
379
0
380
0
  RefPtr<OSKeyStore> self = this;
381
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
382
0
    "BackgroundGenerateSecret",
383
0
    [self, promiseHandle, aLabel = nsAutoCString(aLabel)]() mutable {
384
0
      BackgroundGenerateSecret(aLabel, promiseHandle, self);
385
0
    }));
386
0
387
0
  return FinishAsync(promiseHandle,
388
0
                     promiseOut,
389
0
                     NS_LITERAL_CSTRING("GenerateKSThread"),
390
0
                     runnable);
391
0
}
392
393
void
394
BackgroundSecretAvailable(const nsACString& aLabel,
395
                          RefPtr<Promise>& aPromise,
396
                          RefPtr<OSKeyStore> self)
397
0
{
398
0
  bool available = false;
399
0
  nsresult rv = self->SecretAvailable(aLabel, &available);
400
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
401
0
    "BackgroundSecreteAvailableOSKSResolve",
402
0
    [rv, aPromise = std::move(aPromise), available = available]() {
403
0
      if (NS_FAILED(rv)) {
404
0
        aPromise->MaybeReject(rv);
405
0
      } else {
406
0
        aPromise->MaybeResolve(available);
407
0
      }
408
0
    }));
409
0
  NS_DispatchToMainThread(runnable.forget());
410
0
}
411
412
NS_IMETHODIMP
413
OSKeyStore::AsyncSecretAvailable(const nsACString& aLabel,
414
                                 JSContext* aCx,
415
                                 Promise** promiseOut)
416
0
{
417
0
  NS_ENSURE_ARG_POINTER(aCx);
418
0
419
0
  RefPtr<Promise> promiseHandle;
420
0
  nsresult rv = GetPromise(aCx, promiseHandle);
421
0
  if (NS_FAILED(rv)) {
422
0
    return rv;
423
0
  }
424
0
425
0
  RefPtr<OSKeyStore> self = this;
426
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
427
0
    "BackgroundSecretAvailable",
428
0
    [self, promiseHandle, aLabel = nsAutoCString(aLabel)]() mutable {
429
0
      BackgroundSecretAvailable(aLabel, promiseHandle, self);
430
0
    }));
431
0
432
0
  return FinishAsync(promiseHandle,
433
0
                     promiseOut,
434
0
                     NS_LITERAL_CSTRING("AvaiableKSThread"),
435
0
                     runnable);
436
0
}
437
438
void
439
BackgroundRecoverSecret(const nsACString& aLabel,
440
                        const nsACString& aRecoveryPhrase,
441
                        RefPtr<Promise>& aPromise,
442
                        RefPtr<OSKeyStore> self)
443
0
{
444
0
  nsresult rv = self->RecoverSecret(aLabel, aRecoveryPhrase);
445
0
  nsCOMPtr<nsIRunnable> runnable(
446
0
    NS_NewRunnableFunction("BackgroundRecoverSecreteOSKSResolve",
447
0
                           [rv, aPromise = std::move(aPromise)]() {
448
0
                             if (NS_FAILED(rv)) {
449
0
                               aPromise->MaybeReject(rv);
450
0
                             } else {
451
0
                               aPromise->MaybeResolveWithUndefined();
452
0
                             }
453
0
                           }));
454
0
  NS_DispatchToMainThread(runnable.forget());
455
0
}
456
457
NS_IMETHODIMP
458
OSKeyStore::AsyncRecoverSecret(const nsACString& aLabel,
459
                               const nsACString& aRecoveryPhrase,
460
                               JSContext* aCx,
461
                               Promise** promiseOut)
462
0
{
463
0
  NS_ENSURE_ARG_POINTER(aCx);
464
0
465
0
  RefPtr<Promise> promiseHandle;
466
0
  nsresult rv = GetPromise(aCx, promiseHandle);
467
0
  if (NS_FAILED(rv)) {
468
0
    return rv;
469
0
  }
470
0
471
0
  RefPtr<OSKeyStore> self = this;
472
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
473
0
    "BackgroundRecoverSecret",
474
0
    [self,
475
0
     promiseHandle,
476
0
     aLabel = nsAutoCString(aLabel),
477
0
     aRecoveryPhrase = nsAutoCString(aRecoveryPhrase)]() mutable {
478
0
      BackgroundRecoverSecret(aLabel, aRecoveryPhrase, promiseHandle, self);
479
0
    }));
480
0
481
0
  return FinishAsync(
482
0
    promiseHandle, promiseOut, NS_LITERAL_CSTRING("RecoverKSThread"), runnable);
483
0
}
484
485
void
486
BackgroundDeleteSecret(const nsACString& aLabel,
487
                       RefPtr<Promise>& aPromise,
488
                       RefPtr<OSKeyStore> self)
489
0
{
490
0
  nsresult rv = self->DeleteSecret(aLabel);
491
0
  nsCOMPtr<nsIRunnable> runnable(
492
0
    NS_NewRunnableFunction("BackgroundDeleteSecreteOSKSResolve",
493
0
                           [rv, aPromise = std::move(aPromise)]() {
494
0
                             if (NS_FAILED(rv)) {
495
0
                               aPromise->MaybeReject(rv);
496
0
                             } else {
497
0
                               aPromise->MaybeResolveWithUndefined();
498
0
                             }
499
0
                           }));
500
0
  NS_DispatchToMainThread(runnable.forget());
501
0
}
502
503
NS_IMETHODIMP
504
OSKeyStore::AsyncDeleteSecret(const nsACString& aLabel,
505
                              JSContext* aCx,
506
                              Promise** promiseOut)
507
0
{
508
0
  NS_ENSURE_ARG_POINTER(aCx);
509
0
510
0
  RefPtr<Promise> promiseHandle;
511
0
  nsresult rv = GetPromise(aCx, promiseHandle);
512
0
  if (NS_FAILED(rv)) {
513
0
    return rv;
514
0
  }
515
0
516
0
  RefPtr<OSKeyStore> self = this;
517
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
518
0
    "BackgroundDeleteSecret",
519
0
    [self, promiseHandle, aLabel = nsAutoCString(aLabel)]() mutable {
520
0
      BackgroundDeleteSecret(aLabel, promiseHandle, self);
521
0
    }));
522
0
523
0
  return FinishAsync(
524
0
    promiseHandle, promiseOut, NS_LITERAL_CSTRING("DeleteKSThread"), runnable);
525
0
}
526
527
void
528
BackgroundEncryptBytes(const nsACString& aLabel,
529
                       std::vector<uint8_t> inBytes,
530
                       RefPtr<Promise>& aPromise,
531
                       RefPtr<OSKeyStore> self)
532
0
{
533
0
  nsAutoCString ciphertext;
534
0
  nsresult rv =
535
0
    self->EncryptBytes(aLabel, inBytes.size(), inBytes.data(), ciphertext);
536
0
  nsAutoString ctext;
537
0
  CopyUTF8toUTF16(ciphertext, ctext);
538
0
539
0
  nsCOMPtr<nsIRunnable> runnable(
540
0
    NS_NewRunnableFunction("BackgroundEncryptOSKSResolve",
541
0
                           [rv, aPromise = std::move(aPromise), ctext]() {
542
0
                             if (NS_FAILED(rv)) {
543
0
                               aPromise->MaybeReject(rv);
544
0
                             } else {
545
0
                               aPromise->MaybeResolve(ctext);
546
0
                             }
547
0
                           }));
548
0
  NS_DispatchToMainThread(runnable.forget());
549
0
}
550
551
NS_IMETHODIMP
552
OSKeyStore::AsyncEncryptBytes(const nsACString& aLabel,
553
                              uint32_t inLen,
554
                              uint8_t* inBytes,
555
                              JSContext* aCx,
556
                              Promise** promiseOut)
557
0
{
558
0
  NS_ENSURE_ARG_POINTER(aCx);
559
0
  NS_ENSURE_ARG_POINTER(inBytes);
560
0
561
0
  RefPtr<Promise> promiseHandle;
562
0
  nsresult rv = GetPromise(aCx, promiseHandle);
563
0
  if (NS_FAILED(rv)) {
564
0
    return rv;
565
0
  }
566
0
567
0
  RefPtr<OSKeyStore> self = this;
568
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
569
0
    "BackgroundEncryptBytes",
570
0
    [promiseHandle,
571
0
     inBytes = std::vector<uint8_t>(inBytes, inBytes + inLen),
572
0
     aLabel = nsAutoCString(aLabel),
573
0
     self]() mutable {
574
0
      BackgroundEncryptBytes(aLabel, inBytes, promiseHandle, self);
575
0
    }));
576
0
577
0
  return FinishAsync(
578
0
    promiseHandle, promiseOut, NS_LITERAL_CSTRING("EncryptKSThread"), runnable);
579
0
}
580
581
void
582
BackgroundDecryptBytes(const nsACString& aLabel,
583
                       const nsACString& aEncryptedBase64Text,
584
                       RefPtr<Promise>& aPromise,
585
                       RefPtr<OSKeyStore> self)
586
0
{
587
0
  uint8_t* plaintext = nullptr;
588
0
  uint32_t plaintextLen = 0;
589
0
  nsresult rv =
590
0
    self->DecryptBytes(aLabel, aEncryptedBase64Text, &plaintextLen, &plaintext);
591
0
  nsTArray<uint8_t> plain;
592
0
  if (plaintext) {
593
0
    MOZ_ASSERT(plaintextLen > 0);
594
0
    plain.AppendElements(plaintext, plaintextLen);
595
0
    free(plaintext);
596
0
  }
597
0
598
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
599
0
    "BackgroundDecryptOSKSResolve",
600
0
    [rv, aPromise = std::move(aPromise), plain = std::move(plain)]() {
601
0
      if (NS_FAILED(rv)) {
602
0
        aPromise->MaybeReject(rv);
603
0
      } else {
604
0
        aPromise->MaybeResolve(plain);
605
0
      }
606
0
    }));
607
0
  NS_DispatchToMainThread(runnable.forget());
608
0
}
609
610
NS_IMETHODIMP
611
OSKeyStore::AsyncDecryptBytes(const nsACString& aLabel,
612
                              const nsACString& aEncryptedBase64Text,
613
                              JSContext* aCx,
614
                              Promise** promiseOut)
615
0
{
616
0
  NS_ENSURE_ARG_POINTER(aCx);
617
0
618
0
  RefPtr<Promise> promiseHandle;
619
0
  nsresult rv = GetPromise(aCx, promiseHandle);
620
0
  if (NS_FAILED(rv)) {
621
0
    return rv;
622
0
  }
623
0
624
0
  RefPtr<OSKeyStore> self = this;
625
0
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
626
0
    "BackgroundDecryptBytes",
627
0
    [promiseHandle,
628
0
     self,
629
0
     aEncryptedBase64Text = nsAutoCString(aEncryptedBase64Text),
630
0
     aLabel = nsAutoCString(aLabel)]() mutable {
631
0
      BackgroundDecryptBytes(aLabel, aEncryptedBase64Text, promiseHandle, self);
632
0
    }));
633
0
634
0
  return FinishAsync(
635
0
    promiseHandle, promiseOut, NS_LITERAL_CSTRING("DecryptKSThread"), runnable);
636
0
}
637
638
// Generic AES-GCM cipher wrapper for NSS functions.
639
640
nsresult
641
AbstractOSKeyStore::BuildAesGcmKey(std::vector<uint8_t> aKeyBytes,
642
                                   /* out */ UniquePK11SymKey& aKey)
643
0
{
644
0
  if (aKeyBytes.size() != mKeyByteLength) {
645
0
    return NS_ERROR_INVALID_ARG;
646
0
  }
647
0
648
0
  UniquePK11SlotInfo slot(PK11_GetInternalSlot());
649
0
  if (!slot) {
650
0
    return NS_ERROR_FAILURE;
651
0
  }
652
0
653
0
  UniqueSECItem key =
654
0
    UniqueSECItem(SECITEM_AllocItem(nullptr, nullptr, mKeyByteLength));
655
0
  if (!key) {
656
0
    return NS_ERROR_FAILURE;
657
0
  }
658
0
  key->type = siBuffer;
659
0
  memcpy(key->data, aKeyBytes.data(), mKeyByteLength);
660
0
  key->len = mKeyByteLength;
661
0
662
0
  UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(),
663
0
                                            CKM_AES_GCM,
664
0
                                            PK11_OriginUnwrap,
665
0
                                            CKA_DECRYPT | CKA_ENCRYPT,
666
0
                                            key.get(),
667
0
                                            nullptr));
668
0
669
0
  if (!symKey) {
670
0
    return NS_ERROR_FAILURE;
671
0
  }
672
0
  aKey.swap(symKey);
673
0
674
0
  return NS_OK;
675
0
}
676
677
nsresult
678
AbstractOSKeyStore::DoCipher(const UniquePK11SymKey& aSymKey,
679
                             const std::vector<uint8_t>& inBytes,
680
                             std::vector<uint8_t>& outBytes,
681
                             bool encrypt)
682
0
{
683
0
  NS_ENSURE_ARG_POINTER(aSymKey);
684
0
  outBytes.clear();
685
0
686
0
  // Build params.
687
0
  // We need to get the IV from inBytes if we decrypt.
688
0
  if (!encrypt && (inBytes.size() < mIVLength || inBytes.size() == 0)) {
689
0
    return NS_ERROR_INVALID_ARG;
690
0
  }
691
0
692
0
  const uint8_t* ivp = nullptr;
693
0
  std::vector<uint8_t> ivBuf;
694
0
  if (encrypt) {
695
0
    // Generate a new IV.
696
0
    ivBuf.resize(mIVLength);
697
0
    nsresult rv = GenerateRandom(ivBuf);
698
0
    if (NS_FAILED(rv) || ivBuf.size() != mIVLength) {
699
0
      return NS_ERROR_FAILURE;
700
0
    }
701
0
    ivp = ivBuf.data();
702
0
  } else {
703
0
    // An IV was passed in. Use the first mIVLength bytes from inBytes as IV.
704
0
    ivp = inBytes.data();
705
0
  }
706
0
707
0
  CK_GCM_PARAMS gcm_params;
708
0
  gcm_params.pIv = const_cast<unsigned char*>(ivp);
709
0
  gcm_params.ulIvLen = mIVLength;
710
0
  gcm_params.ulTagBits = 128;
711
0
  gcm_params.pAAD = nullptr;
712
0
  gcm_params.ulAADLen = 0;
713
0
714
0
  SECItem paramsItem = { siBuffer,
715
0
                         reinterpret_cast<unsigned char*>(&gcm_params),
716
0
                         sizeof(CK_GCM_PARAMS) };
717
0
718
0
  size_t blockLength = 16;
719
0
  outBytes.resize(inBytes.size() + blockLength);
720
0
  unsigned int outLen = 0;
721
0
  SECStatus srv = SECFailure;
722
0
  if (encrypt) {
723
0
    srv = PK11_Encrypt(aSymKey.get(),
724
0
                       CKM_AES_GCM,
725
0
                       &paramsItem,
726
0
                       outBytes.data(),
727
0
                       &outLen,
728
0
                       inBytes.size() + blockLength,
729
0
                       inBytes.data(),
730
0
                       inBytes.size());
731
0
    // Prepend the used IV to the ciphertext.
732
0
    Unused << outBytes.insert(outBytes.begin(), ivp, ivp + mIVLength);
733
0
    outLen += mIVLength;
734
0
  } else {
735
0
    // Remove the IV from the input.
736
0
    std::vector<uint8_t> input(inBytes);
737
0
    input.erase(input.begin(), input.begin() + mIVLength);
738
0
    srv = PK11_Decrypt(aSymKey.get(),
739
0
                       CKM_AES_GCM,
740
0
                       &paramsItem,
741
0
                       outBytes.data(),
742
0
                       &outLen,
743
0
                       input.size() + blockLength,
744
0
                       input.data(),
745
0
                       input.size());
746
0
  }
747
0
  if (srv != SECSuccess || outLen > outBytes.size()) {
748
0
    outBytes.clear();
749
0
    return NS_ERROR_FAILURE;
750
0
  }
751
0
  if (outLen < outBytes.size()) {
752
0
    outBytes.resize(outLen);
753
0
  }
754
0
755
0
  return NS_OK;
756
0
}
757
758
bool
759
AbstractOSKeyStore::IsNSSKeyStore()
760
0
{
761
0
  return false;
762
0
}
763
764
bool
765
AbstractOSKeyStore::SecretAvailable(const nsACString& aLabel)
766
0
{
767
0
  nsAutoCString secret;
768
0
  nsresult rv = RetrieveSecret(aLabel, secret);
769
0
  if (NS_FAILED(rv) || secret.Length() == 0) {
770
0
    return false;
771
0
  }
772
0
  return true;
773
0
}
774
775
nsresult
776
AbstractOSKeyStore::EncryptDecrypt(const nsACString& aLabel,
777
                                   const std::vector<uint8_t>& inBytes,
778
                                   std::vector<uint8_t>& outBytes,
779
                                   bool encrypt)
780
0
{
781
0
  nsAutoCString secret;
782
0
  nsresult rv = RetrieveSecret(aLabel, secret);
783
0
  if (NS_FAILED(rv) || secret.Length() == 0) {
784
0
    return NS_ERROR_FAILURE;
785
0
  }
786
0
787
0
  uint8_t* p = BitwiseCast<uint8_t*, const char*>(secret.BeginReading());
788
0
  std::vector<uint8_t> buf(p, p + secret.Length());
789
0
  UniquePK11SymKey symKey;
790
0
  rv = BuildAesGcmKey(buf, symKey);
791
0
  if (NS_FAILED(rv)) {
792
0
    return NS_ERROR_FAILURE;
793
0
  }
794
0
  return DoCipher(symKey, inBytes, outBytes, encrypt);
795
0
}