Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/NSSKeyStore.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 "NSSKeyStore.h"
8
9
#include "mozilla/Base64.h"
10
#include "mozilla/SyncRunnable.h"
11
#include "nsPK11TokenDB.h"
12
13
/* Implementing OSKeyStore when there is no platform specific one.
14
 * This key store instead puts the keys into the NSS DB.
15
 */
16
17
using namespace mozilla;
18
using mozilla::SyncRunnable;
19
20
LazyLogModule gNSSKeyStoreLog("nsskeystore");
21
22
NSSKeyStore::NSSKeyStore()
23
0
{
24
0
  MOZ_ASSERT(XRE_IsParentProcess());
25
0
  if (!XRE_IsParentProcess()) {
26
0
    // This shouldn't happen as this is only initialised when creating the
27
0
    // OSKeyStore, which is ParentProcessOnly.
28
0
    return;
29
0
  }
30
0
  Unused << EnsureNSSInitializedChromeOrContent();
31
0
  Unused << InitToken();
32
0
}
33
0
NSSKeyStore::~NSSKeyStore() {}
34
35
bool
36
NSSKeyStore::IsNSSKeyStore()
37
0
{
38
0
  return true;
39
0
}
40
41
nsresult
42
NSSKeyStore::InitToken()
43
0
{
44
0
  if (!mSlot) {
45
0
    mSlot = UniquePK11SlotInfo(PK11_GetInternalKeySlot());
46
0
    if (!mSlot) {
47
0
      MOZ_LOG(
48
0
        gNSSKeyStoreLog, LogLevel::Debug, ("Error getting internal key slot"));
49
0
      return NS_ERROR_NOT_AVAILABLE;
50
0
    }
51
0
  }
52
0
  return NS_OK;
53
0
}
54
55
nsresult
56
NSSKeyStoreMainThreadLock(PK11SlotInfo* aSlot)
57
0
{
58
0
  nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
59
0
  return token->LogoutSimple();
60
0
}
61
62
nsresult
63
NSSKeyStore::Lock()
64
0
{
65
0
  NS_ENSURE_STATE(mSlot);
66
0
67
0
  if (!NS_IsMainThread()) {
68
0
    nsCOMPtr<nsIThread> mainThread;
69
0
    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
70
0
    if (NS_FAILED(rv)) {
71
0
      return NS_ERROR_FAILURE;
72
0
    }
73
0
74
0
    // Forward to the main thread synchronously.
75
0
    SyncRunnable::DispatchToThread(
76
0
      mainThread,
77
0
      new SyncRunnable(NS_NewRunnableFunction(
78
0
        "NSSKeyStoreMainThreadLock",
79
0
        [slot = mSlot.get()]() { NSSKeyStoreMainThreadLock(slot); })));
80
0
81
0
    return NS_OK;
82
0
  }
83
0
84
0
  return NSSKeyStoreMainThreadLock(mSlot.get());
85
0
}
86
87
nsresult
88
NSSKeyStoreMainThreadUnlock(PK11SlotInfo* aSlot)
89
0
{
90
0
  nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
91
0
  return token->Login(false /* force */);
92
0
}
93
94
nsresult
95
NSSKeyStore::Unlock()
96
0
{
97
0
  NS_ENSURE_STATE(mSlot);
98
0
99
0
  if (!NS_IsMainThread()) {
100
0
    nsCOMPtr<nsIThread> mainThread;
101
0
    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
102
0
    if (NS_FAILED(rv)) {
103
0
      return NS_ERROR_FAILURE;
104
0
    }
105
0
106
0
    // Forward to the main thread synchronously.
107
0
    SyncRunnable::DispatchToThread(
108
0
      mainThread,
109
0
      new SyncRunnable(NS_NewRunnableFunction(
110
0
        "NSSKeyStoreMainThreadUnlock",
111
0
        [slot = mSlot.get()]() { NSSKeyStoreMainThreadUnlock(slot); })));
112
0
113
0
    return NS_OK;
114
0
  }
115
0
116
0
  return NSSKeyStoreMainThreadUnlock(mSlot.get());
117
0
}
118
119
nsresult
120
NSSKeyStore::StoreSecret(const nsACString& aSecret, const nsACString& aLabel)
121
0
{
122
0
  NS_ENSURE_STATE(mSlot);
123
0
  if (NS_FAILED(Unlock())) {
124
0
    MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
125
0
    return NS_ERROR_FAILURE;
126
0
  }
127
0
128
0
  uint8_t* p = BitwiseCast<uint8_t*, const char*>(aSecret.BeginReading());
129
0
  UniqueSECItem key(SECITEM_AllocItem(nullptr, nullptr, aSecret.Length()));
130
0
  if (!key) {
131
0
    return NS_ERROR_OUT_OF_MEMORY;
132
0
  }
133
0
  key->type = siBuffer;
134
0
  memcpy(key->data, p, aSecret.Length());
135
0
  key->len = aSecret.Length();
136
0
  UniquePK11SymKey symKey(PK11_ImportSymKey(mSlot.get(),
137
0
                                            CKM_AES_GCM,
138
0
                                            PK11_OriginUnwrap,
139
0
                                            CKA_DECRYPT | CKA_ENCRYPT,
140
0
                                            key.get(),
141
0
                                            nullptr));
142
0
  if (!symKey) {
143
0
    MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error creating NSS SymKey"));
144
0
    return NS_ERROR_FAILURE;
145
0
  }
146
0
  UniquePK11SymKey storedKey(
147
0
    PK11_ConvertSessionSymKeyToTokenSymKey(symKey.get(), nullptr));
148
0
  if (!storedKey) {
149
0
    MOZ_LOG(
150
0
      gNSSKeyStoreLog, LogLevel::Debug, ("Error storing NSS SymKey in DB"));
151
0
    return NS_ERROR_FAILURE;
152
0
  }
153
0
  SECStatus srv =
154
0
    PK11_SetSymKeyNickname(storedKey.get(), PromiseFlatCString(aLabel).get());
155
0
  if (srv != SECSuccess) {
156
0
    MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error naming NSS SymKey"));
157
0
    (void)PK11_DeleteTokenSymKey(storedKey.get());
158
0
    return NS_ERROR_FAILURE;
159
0
  }
160
0
161
0
  return NS_OK;
162
0
}
163
164
nsresult
165
NSSKeyStore::DeleteSecret(const nsACString& aLabel)
166
0
{
167
0
  NS_ENSURE_STATE(mSlot);
168
0
  if (NS_FAILED(Unlock())) {
169
0
    MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
170
0
    return NS_ERROR_FAILURE;
171
0
  }
172
0
173
0
  UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
174
0
    mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()), nullptr));
175
0
  if (!symKey) {
176
0
    // Couldn't find the key or something is wrong. Be nice.
177
0
    return NS_OK;
178
0
  }
179
0
  for (PK11SymKey* tmp = symKey.get(); tmp; tmp = PK11_GetNextSymKey(tmp)) {
180
0
    SECStatus srv = PK11_DeleteTokenSymKey(tmp);
181
0
    if (srv != SECSuccess) {
182
0
      MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error deleting NSS SymKey"));
183
0
      return NS_ERROR_FAILURE;
184
0
    }
185
0
  }
186
0
  return NS_OK;
187
0
}
188
189
bool
190
NSSKeyStore::SecretAvailable(const nsACString& aLabel)
191
0
{
192
0
  if (!mSlot) {
193
0
    return false;
194
0
  }
195
0
  if (NS_FAILED(Unlock())) {
196
0
    MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
197
0
    return false;
198
0
  }
199
0
200
0
  UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
201
0
    mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()), nullptr));
202
0
  if (!symKey) {
203
0
    return false;
204
0
  }
205
0
  return true;
206
0
}
207
208
nsresult
209
NSSKeyStore::EncryptDecrypt(const nsACString& aLabel,
210
                            const std::vector<uint8_t>& inBytes,
211
                            std::vector<uint8_t>& outBytes,
212
                            bool encrypt)
213
0
{
214
0
  NS_ENSURE_STATE(mSlot);
215
0
  if (NS_FAILED(Unlock())) {
216
0
    MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
217
0
    return NS_ERROR_FAILURE;
218
0
  }
219
0
220
0
  UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
221
0
    mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()), nullptr));
222
0
  if (!symKey) {
223
0
    MOZ_LOG(
224
0
      gNSSKeyStoreLog, LogLevel::Debug, ("Error finding key for given label"));
225
0
    return NS_ERROR_FAILURE;
226
0
  }
227
0
  return DoCipher(symKey, inBytes, outBytes, encrypt);
228
0
}
229
230
// Because NSSKeyStore overrides AbstractOSKeyStore's EncryptDecrypt and
231
// SecretAvailable functions, this isn't necessary.
232
nsresult
233
NSSKeyStore::RetrieveSecret(const nsACString& aLabel,
234
                  /* out */ nsACString& aSecret)
235
0
{
236
0
  return NS_ERROR_NOT_IMPLEMENTED;
237
0
}